diff --git a/src/pkg/Makefile b/src/pkg/Makefile
index 2b96dc0f9423fe565343e4a2a19b0bcdf739c678..5bec3ce90166012eb549abdf4ce83413619b3b7b 100644
--- a/src/pkg/Makefile
+++ b/src/pkg/Makefile
@@ -193,7 +193,6 @@ endif
 # Disable tests that windows cannot run yet.
 ifeq ($(GOOS),windows)
 NOTEST+=exec         # no pipe
-NOTEST+=os           # many things unimplemented
 NOTEST+=os/signal    # no signals
 NOTEST+=path         # tree walking does not work
 NOTEST+=syslog       # no network
diff --git a/src/pkg/os/file_windows.go b/src/pkg/os/file_windows.go
index cee3aad7e1f3dfc9ba2cf333c4a0be4e8d9803aa..d5978a83c32f77c0e7d6f3be8dc9a6019bc44f78 100644
--- a/src/pkg/os/file_windows.go
+++ b/src/pkg/os/file_windows.go
@@ -53,12 +53,25 @@ func Open(name string, flag int, perm uint32) (file *File, err Error) {
 	// TODO(brainman): not sure about my logic of assuming it is dir first, then fall back to file
 	r, e := openDir(name)
 	if e == nil {
+		if flag&O_WRONLY != 0 || flag&O_RDWR != 0 {
+			r.Close()
+			return nil, &PathError{"open", name, EISDIR}
+		}
 		return r, nil
 	}
 	r, e = openFile(name, flag, perm)
 	if e == nil {
 		return r, nil
 	}
+	// Imitating Unix behavior by replacing syscall.ERROR_PATH_NOT_FOUND with
+	// os.ENOTDIR. Not sure if we should go into that.
+	if e2, ok := e.(*PathError); ok {
+		if e3, ok := e2.Error.(Errno); ok {
+			if e3 == Errno(syscall.ERROR_PATH_NOT_FOUND) {
+				return nil, &PathError{"open", name, ENOTDIR}
+			}
+		}
+	}
 	return nil, e
 }
 
diff --git a/src/pkg/os/os_test.go b/src/pkg/os/os_test.go
index f8b2d010dbb05be58ddad7cba4520fb3a954ed63..5a4e1a865f546b2d78282761ab7a4c96626d932a 100644
--- a/src/pkg/os/os_test.go
+++ b/src/pkg/os/os_test.go
@@ -28,11 +28,35 @@ var dot = []string{
 	"stat_linux.go",
 }
 
-var etc = []string{
-	"group",
-	"hosts",
-	"passwd",
-}
+type sysDir struct {
+	name  string
+	files []string
+}
+
+var sysdir = func() (sd *sysDir) {
+	switch syscall.OS {
+	case "windows":
+		sd = &sysDir{
+			Getenv("SystemRoot") + "\\system32\\drivers\\etc",
+			[]string{
+				"hosts",
+				"networks",
+				"protocol",
+				"services",
+			},
+		}
+	default:
+		sd = &sysDir{
+			"/etc",
+			[]string{
+				"group",
+				"hosts",
+				"passwd",
+			},
+		}
+	}
+	return
+}()
 
 func size(name string, t *testing.T) int64 {
 	file, err := Open(name, O_RDONLY, 0)
@@ -55,6 +79,16 @@ func size(name string, t *testing.T) int64 {
 	return int64(len)
 }
 
+func equal(name1, name2 string) (r bool) {
+	switch syscall.OS {
+	case "windows":
+		r = strings.ToLower(name1) == strings.ToLower(name2)
+	default:
+		r = name1 == name2
+	}
+	return
+}
+
 func newFile(testName string, t *testing.T) (f *File) {
 	// Use a local file system, not NFS.
 	// On Unix, override $TMPDIR in case the user
@@ -70,22 +104,27 @@ func newFile(testName string, t *testing.T) (f *File) {
 	return
 }
 
+var sfdir = sysdir.name
+var sfname = sysdir.files[0]
+
 func TestStat(t *testing.T) {
-	dir, err := Stat("/etc/passwd")
+	path := sfdir + "/" + sfname
+	dir, err := Stat(path)
 	if err != nil {
 		t.Fatal("stat failed:", err)
 	}
-	if dir.Name != "passwd" {
-		t.Error("name should be passwd; is", dir.Name)
+	if !equal(sfname, dir.Name) {
+		t.Error("name should be ", sfname, "; is", dir.Name)
 	}
-	filesize := size("/etc/passwd", t)
+	filesize := size(path, t)
 	if dir.Size != filesize {
 		t.Error("size should be", filesize, "; is", dir.Size)
 	}
 }
 
 func TestFstat(t *testing.T) {
-	file, err1 := Open("/etc/passwd", O_RDONLY, 0)
+	path := sfdir + "/" + sfname
+	file, err1 := Open(path, O_RDONLY, 0)
 	defer file.Close()
 	if err1 != nil {
 		t.Fatal("open failed:", err1)
@@ -94,24 +133,25 @@ func TestFstat(t *testing.T) {
 	if err2 != nil {
 		t.Fatal("fstat failed:", err2)
 	}
-	if dir.Name != "passwd" {
-		t.Error("name should be passwd; is", dir.Name)
+	if !equal(sfname, dir.Name) {
+		t.Error("name should be ", sfname, "; is", dir.Name)
 	}
-	filesize := size("/etc/passwd", t)
+	filesize := size(path, t)
 	if dir.Size != filesize {
 		t.Error("size should be", filesize, "; is", dir.Size)
 	}
 }
 
 func TestLstat(t *testing.T) {
-	dir, err := Lstat("/etc/passwd")
+	path := sfdir + "/" + sfname
+	dir, err := Lstat(path)
 	if err != nil {
 		t.Fatal("lstat failed:", err)
 	}
-	if dir.Name != "passwd" {
-		t.Error("name should be passwd; is", dir.Name)
+	if !equal(sfname, dir.Name) {
+		t.Error("name should be ", sfname, "; is", dir.Name)
 	}
-	filesize := size("/etc/passwd", t)
+	filesize := size(path, t)
 	if dir.Size != filesize {
 		t.Error("size should be", filesize, "; is", dir.Size)
 	}
@@ -133,7 +173,7 @@ func testReaddirnames(dir string, contents []string, t *testing.T) {
 			if n == "." || n == ".." {
 				t.Errorf("got %s in directory", n)
 			}
-			if m == n {
+			if equal(m, n) {
 				if found {
 					t.Error("present twice:", m)
 				}
@@ -159,7 +199,7 @@ func testReaddir(dir string, contents []string, t *testing.T) {
 	for _, m := range contents {
 		found := false
 		for _, n := range s {
-			if m == n.Name {
+			if equal(m, n.Name) {
 				if found {
 					t.Error("present twice:", m)
 				}
@@ -174,12 +214,12 @@ func testReaddir(dir string, contents []string, t *testing.T) {
 
 func TestReaddirnames(t *testing.T) {
 	testReaddirnames(".", dot, t)
-	testReaddirnames("/etc", etc, t)
+	testReaddirnames(sysdir.name, sysdir.files, t)
 }
 
 func TestReaddir(t *testing.T) {
 	testReaddir(".", dot, t)
-	testReaddir("/etc", etc, t)
+	testReaddir(sysdir.name, sysdir.files, t)
 }
 
 // Read the directory one entry at a time.
@@ -203,7 +243,11 @@ func smallReaddirnames(file *File, length int, t *testing.T) []string {
 // Check that reading a directory one entry at a time gives the same result
 // as reading it all at once.
 func TestReaddirnamesOneAtATime(t *testing.T) {
-	dir := "/usr/bin" // big directory that doesn't change often.
+	// big directory that doesn't change often.
+	dir := "/usr/bin"
+	if syscall.OS == "windows" {
+		dir = Getenv("SystemRoot") + "\\system32"
+	}
 	file, err := Open(dir, O_RDONLY, 0)
 	defer file.Close()
 	if err != nil {
@@ -226,6 +270,10 @@ func TestReaddirnamesOneAtATime(t *testing.T) {
 }
 
 func TestHardLink(t *testing.T) {
+	// Hardlinks are not supported under windows.
+	if syscall.OS == "windows" {
+		return
+	}
 	from, to := "hardlinktestfrom", "hardlinktestto"
 	Remove(from) // Just in case.
 	file, err := Open(to, O_CREAT|O_WRONLY, 0666)
@@ -255,6 +303,10 @@ func TestHardLink(t *testing.T) {
 }
 
 func TestSymLink(t *testing.T) {
+	// Symlinks are not supported under windows.
+	if syscall.OS == "windows" {
+		return
+	}
 	from, to := "symlinktestfrom", "symlinktestto"
 	Remove(from) // Just in case.
 	file, err := Open(to, O_CREAT|O_WRONLY, 0666)
@@ -313,6 +365,10 @@ func TestSymLink(t *testing.T) {
 }
 
 func TestLongSymlink(t *testing.T) {
+	// Symlinks are not supported under windows.
+	if syscall.OS == "windows" {
+		return
+	}
 	s := "0123456789abcdef"
 	// Long, but not too long: a common limit is 255.
 	s = s + s + s + s + s + s + s + s + s + s + s + s + s + s + s
@@ -354,6 +410,10 @@ func TestRename(t *testing.T) {
 }
 
 func TestForkExec(t *testing.T) {
+	// TODO(brainman): Try to enable this test once ForkExec is working.
+	if syscall.OS == "windows" {
+		return
+	}
 	r, w, err := Pipe()
 	if err != nil {
 		t.Fatalf("Pipe: %v", err)
@@ -385,6 +445,10 @@ func checkMode(t *testing.T, path string, mode uint32) {
 }
 
 func TestChmod(t *testing.T) {
+	// Chmod is not supported under windows.
+	if syscall.OS == "windows" {
+		return
+	}
 	f := newFile("TestChmod", t)
 	defer Remove(f.Name())
 	defer f.Close()
@@ -414,6 +478,10 @@ func checkUidGid(t *testing.T, path string, uid, gid int) {
 }
 
 func TestChown(t *testing.T) {
+	// Chown is not supported under windows.
+	if syscall.OS == "windows" {
+		return
+	}
 	// Use TempDir() to make sure we're on a local file system,
 	// so that the group ids returned by Getgroups will be allowed
 	// on the file.  On NFS, the Getgroups groups are
@@ -455,13 +523,13 @@ func TestChown(t *testing.T) {
 	}
 }
 
-func checkSize(t *testing.T, path string, size int64) {
-	dir, err := Stat(path)
+func checkSize(t *testing.T, f *File, size int64) {
+	dir, err := f.Stat()
 	if err != nil {
-		t.Fatalf("Stat %q (looking for size %d): %s", path, size, err)
+		t.Fatalf("Stat %q (looking for size %d): %s", f.Name(), size, err)
 	}
 	if dir.Size != size {
-		t.Errorf("Stat %q: size %d want %d", path, dir.Size, size)
+		t.Errorf("Stat %q: size %d want %d", f.Name(), dir.Size, size)
 	}
 }
 
@@ -470,17 +538,17 @@ func TestTruncate(t *testing.T) {
 	defer Remove(f.Name())
 	defer f.Close()
 
-	checkSize(t, f.Name(), 0)
+	checkSize(t, f, 0)
 	f.Write([]byte("hello, world\n"))
-	checkSize(t, f.Name(), 13)
+	checkSize(t, f, 13)
 	f.Truncate(10)
-	checkSize(t, f.Name(), 10)
+	checkSize(t, f, 10)
 	f.Truncate(1024)
-	checkSize(t, f.Name(), 1024)
+	checkSize(t, f, 1024)
 	f.Truncate(0)
-	checkSize(t, f.Name(), 0)
+	checkSize(t, f, 0)
 	f.Write([]byte("surprise!"))
-	checkSize(t, f.Name(), 13+9) // wrote at offset past where hello, world was.
+	checkSize(t, f, 13+9) // wrote at offset past where hello, world was.
 }
 
 // Use TempDir() to make sure we're on a local file system,
@@ -526,6 +594,10 @@ func TestChtimes(t *testing.T) {
 }
 
 func TestChdirAndGetwd(t *testing.T) {
+	// TODO(brainman): file.Chdir() is not implemented on windows.
+	if syscall.OS == "windows" {
+		return
+	}
 	fd, err := Open(".", O_RDONLY, 0)
 	if err != nil {
 		t.Fatalf("Open .: %s", err)
@@ -624,24 +696,24 @@ func TestSeek(t *testing.T) {
 type openErrorTest struct {
 	path  string
 	mode  int
-	error string
+	error Error
 }
 
 var openErrorTests = []openErrorTest{
 	openErrorTest{
-		"/etc/no-such-file",
+		sfdir + "/no-such-file",
 		O_RDONLY,
-		"open /etc/no-such-file: no such file or directory",
+		ENOENT,
 	},
 	openErrorTest{
-		"/etc",
+		sfdir,
 		O_WRONLY,
-		"open /etc: is a directory",
+		EISDIR,
 	},
 	openErrorTest{
-		"/etc/passwd/group",
+		sfdir + "/" + sfname + "/no-such-file",
 		O_WRONLY,
-		"open /etc/passwd/group: not a directory",
+		ENOTDIR,
 	},
 }
 
@@ -653,8 +725,12 @@ func TestOpenError(t *testing.T) {
 			f.Close()
 			continue
 		}
-		if s := err.String(); s != tt.error {
-			t.Errorf("Open(%q, %d) = _, %q; want %q", tt.path, tt.mode, s, tt.error)
+		perr, ok := err.(*PathError)
+		if !ok {
+			t.Errorf("Open(%q, %d) returns error of %T type; want *os.PathError", tt.path, tt.mode, err)
+		}
+		if perr.Error != tt.error {
+			t.Errorf("Open(%q, %d) = _, %q; want %q", tt.path, tt.mode, perr.Error.String(), tt.error.String())
 		}
 	}
 }
@@ -687,6 +763,10 @@ func run(t *testing.T, cmd []string) string {
 
 
 func TestHostname(t *testing.T) {
+	// There is no other way to fetch hostname on windows, but via winapi.
+	if syscall.OS == "windows" {
+		return
+	}
 	// Check internal Hostname() against the output of /bin/hostname.
 	// Allow that the internal Hostname returns a Fully Qualified Domain Name
 	// and the /bin/hostname only returns the first component
diff --git a/src/pkg/os/path_test.go b/src/pkg/os/path_test.go
index fcd4bac54f6677164fdcdf30b15f2ae037089f5d..9bc92ae0278cc8226764fd8f7da847a8609133ce 100644
--- a/src/pkg/os/path_test.go
+++ b/src/pkg/os/path_test.go
@@ -7,6 +7,7 @@ package os_test
 import (
 	. "os"
 	"testing"
+	"syscall"
 )
 
 func TestMkdirAll(t *testing.T) {
@@ -104,7 +105,16 @@ func TestRemoveAll(t *testing.T) {
 		t.Fatalf("Lstat %q succeeded after RemoveAll (second)", path)
 	}
 
-	if Getuid() != 0 { // Test fails as root
+	// Determine if we should run the following test.
+	testit := true
+	if syscall.OS == "windows" {
+		// Chmod is not supported under windows.
+		testit = false
+	} else {
+		// Test fails as root.
+		testit = Getuid() != 0
+	}
+	if testit {
 		// Make directory with file and subdirectory and trigger error.
 		if err = MkdirAll(dpath, 0777); err != nil {
 			t.Fatalf("MkdirAll %q: %s", dpath, err)
diff --git a/src/pkg/syscall/mkerrors_windows.sh b/src/pkg/syscall/mkerrors_windows.sh
index a06c13445ad3b7793b7077719f44e3253b579dc5..f5d4914cff0c44ed7268e3c3684919b6206d6214 100755
--- a/src/pkg/syscall/mkerrors_windows.sh
+++ b/src/pkg/syscall/mkerrors_windows.sh
@@ -73,12 +73,28 @@ do
 	fi
 done
 
+# These are go errors that will be mapped directly to windows errors
+goerrors='
+ENOENT:ERROR_FILE_NOT_FOUND
+ENOTDIR:ERROR_DIRECTORY
+'
+
 # Pull out just the error names for later.
+i=$(
+	for j in "$goerrors"
+	do
+		echo "$j"
+	done |
+	awk -F: '
+		{ if (NR > 1) printf("|") }
+		{ printf("%s", $1) }
+	'
+)
 errors=$(
 	echo '#include <errno.h>' | $GCC -x c - -E -dM $ccflags |
 	awk '
 		$1 != "#define" || $2 ~ /\(/ {next}
-		$2 ~ /^ENOTDIR$/ {next}
+		$2 ~ /^('$i')$/ {next}
 		$2 ~ /^E[A-Z0-9_]+$/ { print $2 }
 		{next}
 	' | sort
@@ -101,14 +117,31 @@ echo 'package syscall'
 
 enum { A = 'A', Z = 'Z', a = 'a', z = 'z' }; // avoid need for single quotes below
 
+struct {
+	char *goname;
+	char *winname;
+} goerrors[] = {
+"
+	for i in $goerrors
+	do
+		j=`echo $i | cut -d: -f1`
+		k=`echo $i | cut -d: -f2`
+		echo '	{"'$j'", "'$k'"},'
+	done
+
+	# Use /bin/echo to avoid builtin echo,
+	# which interprets \n itself
+	/bin/echo '
+};
+
 struct {
 	char *name;
 	int value;
 } errors[] = {
-"
+'
 	for i in $errors
 	do
-		/bin/echo '	{"'$i'",' $i'},'
+		echo '	{"'$i'",' $i'},'
 	done
 
 	# Use /bin/echo to avoid builtin echo,
@@ -122,7 +155,19 @@ main(void)
 	int i, j, e, iota = 1;
 	char buf[1024];
 
-	printf("\nconst (\n");
+	printf("\n// Go names for Windows errors.\n");
+	printf("const (\n");
+	for(i=0; i<nelem(goerrors); i++) {
+		printf("\t%s = %s\n", goerrors[i].goname, goerrors[i].winname);
+			
+	}
+	printf(")\n");
+
+	printf("\n// Windows reserves errors >= 1<<29 for application use.\n");
+	printf("const APPLICATION_ERROR = 1 << 29\n");
+
+	printf("\n// Invented values to support what package os and others expects.\n");
+	printf("const (\n");
 	for(i=0; i<nelem(errors); i++) {
 		e = errors[i].value;
 		strcpy(buf, strerror(e));
@@ -140,7 +185,7 @@ main(void)
 	printf("\tEWINDOWS\n");
 	printf(")\n");
 
-	printf("\n// Error table\n");
+	printf("\n// Error strings for invented errors\n");
 	printf("var errors = [...]string {\n");
 	for(i=0; i<nelem(errors); i++) {
 		e = errors[i].value;
diff --git a/src/pkg/syscall/zerrors_windows_386.go b/src/pkg/syscall/zerrors_windows_386.go
index a633f6a362ac88ec69202db71367a2b53d341a7d..a6bed6ea6b0c29ffe17c8de26be71ad3e766c875 100644
--- a/src/pkg/syscall/zerrors_windows_386.go
+++ b/src/pkg/syscall/zerrors_windows_386.go
@@ -3,6 +3,16 @@
 
 package syscall
 
+// Go names for Windows errors.
+const (
+	ENOENT  = ERROR_FILE_NOT_FOUND
+	ENOTDIR = ERROR_DIRECTORY
+)
+
+// Windows reserves errors >= 1<<29 for application use.
+const APPLICATION_ERROR = 1 << 29
+
+// Invented values to support what package os and others expects.
 const (
 	E2BIG = APPLICATION_ERROR + iota
 	EACCES
@@ -78,7 +88,6 @@ const (
 	ENOCSI
 	ENODATA
 	ENODEV
-	ENOENT
 	ENOEXEC
 	ENOKEY
 	ENOLCK
@@ -138,7 +147,7 @@ const (
 	EWINDOWS
 )
 
-// Error table
+// Error strings for invented errors
 var errors = [...]string{
 	E2BIG - APPLICATION_ERROR:           "argument list too long",
 	EACCES - APPLICATION_ERROR:          "permission denied",
@@ -213,7 +222,6 @@ var errors = [...]string{
 	ENOCSI - APPLICATION_ERROR:          "no CSI structure available",
 	ENODATA - APPLICATION_ERROR:         "no data available",
 	ENODEV - APPLICATION_ERROR:          "no such device",
-	ENOENT - APPLICATION_ERROR:          "no such file or directory",
 	ENOEXEC - APPLICATION_ERROR:         "exec format error",
 	ENOKEY - APPLICATION_ERROR:          "required key not available",
 	ENOLCK - APPLICATION_ERROR:          "no locks available",
diff --git a/src/pkg/syscall/ztypes_windows_386.go b/src/pkg/syscall/ztypes_windows_386.go
index c157a6525c3b3d8b084ed9cc1f8d59ea2afad163..1187f9033ae47ba3bdee936156a97ee5764e9fc2 100644
--- a/src/pkg/syscall/ztypes_windows_386.go
+++ b/src/pkg/syscall/ztypes_windows_386.go
@@ -20,6 +20,7 @@ const (
 const (
 	// Windows errors.
 	ERROR_FILE_NOT_FOUND      = 2
+	ERROR_PATH_NOT_FOUND      = 3
 	ERROR_NO_MORE_FILES       = 18
 	ERROR_BROKEN_PIPE         = 109
 	ERROR_INSUFFICIENT_BUFFER = 122
@@ -28,10 +29,6 @@ const (
 	ERROR_ENVVAR_NOT_FOUND    = 203
 	ERROR_DIRECTORY           = 267
 	ERROR_IO_PENDING          = 997
-	// Go names for Windows errors.
-	ENOTDIR = ERROR_DIRECTORY
-	// Windows reserves errors >= 1<<29 for application use.
-	APPLICATION_ERROR = 1 << 29
 )
 
 const (