diff --git a/src/os/os_test.go b/src/os/os_test.go index 65a2d7e23a..38cbfca272 100644 --- a/src/os/os_test.go +++ b/src/os/os_test.go @@ -1791,23 +1791,60 @@ func TestSameFile(t *testing.T) { } } -func TestDevNullFile(t *testing.T) { - f, err := Open(DevNull) - if err != nil { - t.Fatalf("Open(%s): %v", DevNull, err) - } - defer f.Close() - fi, err := f.Stat() - if err != nil { - t.Fatalf("Stat(%s): %v", DevNull, err) - } - name := filepath.Base(DevNull) - if fi.Name() != name { - t.Fatalf("wrong file name have %v want %v", fi.Name(), name) +func testDevNullFileInfo(t *testing.T, statname, devNullName string, fi FileInfo, ignoreCase bool) { + pre := fmt.Sprintf("%s(%q): ", statname, devNullName) + name := filepath.Base(devNullName) + if ignoreCase { + if strings.ToUpper(fi.Name()) != strings.ToUpper(name) { + t.Errorf(pre+"wrong file name have %v want %v", fi.Name(), name) + } + } else { + if fi.Name() != name { + t.Errorf(pre+"wrong file name have %v want %v", fi.Name(), name) + } } if fi.Size() != 0 { - t.Fatalf("wrong file size have %d want 0", fi.Size()) + t.Errorf(pre+"wrong file size have %d want 0", fi.Size()) } + if fi.Mode()&ModeDevice == 0 { + t.Errorf(pre+"wrong file mode %q: ModeDevice is not set", fi.Mode()) + } + if fi.Mode()&ModeCharDevice == 0 { + t.Errorf(pre+"wrong file mode %q: ModeCharDevice is not set", fi.Mode()) + } + if fi.Mode().IsRegular() { + t.Errorf(pre+"wrong file mode %q: IsRegular returns true", fi.Mode()) + } +} + +func testDevNullFile(t *testing.T, devNullName string, ignoreCase bool) { + f, err := Open(devNullName) + if err != nil { + t.Fatalf("Open(%s): %v", devNullName, err) + } + defer f.Close() + + fi, err := f.Stat() + if err != nil { + t.Fatalf("Stat(%s): %v", devNullName, err) + } + testDevNullFileInfo(t, "f.Stat", devNullName, fi, ignoreCase) + + fi, err = Stat(devNullName) + if err != nil { + t.Fatalf("Stat(%s): %v", devNullName, err) + } + testDevNullFileInfo(t, "Stat", devNullName, fi, ignoreCase) + + fi, err = Lstat(devNullName) + if err != nil { + t.Fatalf("Lstat(%s): %v", devNullName, err) + } + testDevNullFileInfo(t, "Lstat", devNullName, fi, ignoreCase) +} + +func TestDevNullFile(t *testing.T) { + testDevNullFile(t, DevNull, false) } var testLargeWrite = flag.Bool("large_write", false, "run TestLargeWriteToConsole test that floods console with output") diff --git a/src/os/os_windows_test.go b/src/os/os_windows_test.go index 12cd9c1f2e..25f93cf131 100644 --- a/src/os/os_windows_test.go +++ b/src/os/os_windows_test.go @@ -979,3 +979,35 @@ func TestOneDrive(t *testing.T) { } testIsDir(t, dir, fi) } + +func TestWindowsDevNullFile(t *testing.T) { + testDevNullFile(t, "NUL", true) + testDevNullFile(t, "nul", true) + testDevNullFile(t, "Nul", true) + + f1, err := os.Open("NUL") + if err != nil { + t.Fatal(err) + } + defer f1.Close() + + fi1, err := f1.Stat() + if err != nil { + t.Fatal(err) + } + + f2, err := os.Open("nul") + if err != nil { + t.Fatal(err) + } + defer f2.Close() + + fi2, err := f2.Stat() + if err != nil { + t.Fatal(err) + } + + if !os.SameFile(fi1, fi2) { + t.Errorf(`"NUL" and "nul" are not the same file`) + } +} diff --git a/src/os/stat_windows.go b/src/os/stat_windows.go index 0b54a15447..19cc0cf6b7 100644 --- a/src/os/stat_windows.go +++ b/src/os/stat_windows.go @@ -8,6 +8,24 @@ import ( "syscall" ) +// isNulName returns true if name is NUL file name. +// For example, it returns true for both "NUL" and "nul". +func isNulName(name string) bool { + if len(name) != 3 { + return false + } + if name[0] != 'n' && name[0] != 'N' { + return false + } + if name[1] != 'u' && name[1] != 'U' { + return false + } + if name[2] != 'l' && name[2] != 'L' { + return false + } + return true +} + // Stat returns the FileInfo structure describing file. // If there is an error, it will be of type *PathError. func (file *File) Stat() (FileInfo, error) { @@ -19,7 +37,7 @@ func (file *File) Stat() (FileInfo, error) { // I don't know any better way to do that for directory return Stat(file.dirinfo.path) } - if file.name == DevNull { + if isNulName(file.name) { return &devNullStat, nil } @@ -45,7 +63,7 @@ func statNolog(name string) (FileInfo, error) { if len(name) == 0 { return nil, &PathError{"Stat", name, syscall.Errno(syscall.ERROR_PATH_NOT_FOUND)} } - if name == DevNull { + if isNulName(name) { return &devNullStat, nil } namep, err := syscall.UTF16PtrFromString(fixLongPath(name)) @@ -80,7 +98,7 @@ func lstatNolog(name string) (FileInfo, error) { if len(name) == 0 { return nil, &PathError{"Lstat", name, syscall.Errno(syscall.ERROR_PATH_NOT_FOUND)} } - if name == DevNull { + if isNulName(name) { return &devNullStat, nil } namep, err := syscall.UTF16PtrFromString(fixLongPath(name))