// bits (before umask).
// If there is an error, it will be of type *PathError.
func Mkdir(name string, perm FileMode) error {
- if runtime.GOOS == "windows" && isWindowsNulName(name) {
- return &PathError{Op: "mkdir", Path: name, Err: syscall.ENOTDIR}
- }
longName := fixLongPath(name)
e := ignoringEINTR(func() error {
return syscall.Mkdir(longName, syscallMode(perm))
return newRawConn(f)
}
-// isWindowsNulName reports whether name is os.DevNull ('NUL') on Windows.
-// True is returned if name is 'NUL' whatever the case.
-func isWindowsNulName(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
-}
-
// DirFS returns a file system (an fs.FS) for the tree of files rooted at the directory dir.
//
// Note that DirFS("/prefix") only guarantees that the Open calls it makes to the
}
}
-func testDevNullFileInfo(t *testing.T, statname, devNullName string, fi FileInfo, ignoreCase bool) {
+func testDevNullFileInfo(t *testing.T, statname, devNullName string, fi FileInfo) {
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.Errorf(pre+"wrong file size have %d want 0", fi.Size())
}
}
}
-func testDevNullFile(t *testing.T, devNullName string, ignoreCase bool) {
+func testDevNullFile(t *testing.T, devNullName string) {
f, err := Open(devNullName)
if err != nil {
t.Fatalf("Open(%s): %v", devNullName, err)
if err != nil {
t.Fatalf("Stat(%s): %v", devNullName, err)
}
- testDevNullFileInfo(t, "f.Stat", devNullName, fi, ignoreCase)
+ testDevNullFileInfo(t, "f.Stat", devNullName, fi)
fi, err = Stat(devNullName)
if err != nil {
t.Fatalf("Stat(%s): %v", devNullName, err)
}
- testDevNullFileInfo(t, "Stat", devNullName, fi, ignoreCase)
+ testDevNullFileInfo(t, "Stat", devNullName, fi)
}
func TestDevNullFile(t *testing.T) {
- testDevNullFile(t, DevNull, false)
+ testDevNullFile(t, DevNull)
+ if runtime.GOOS == "windows" {
+ testDevNullFile(t, "./nul")
+ testDevNullFile(t, "//./nul")
+ }
}
var testLargeWrite = flag.Bool("large_write", false, "run TestLargeWriteToConsole test that floods console with output")
}
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)
}
}
+func TestFileStatNUL(t *testing.T) {
+ f, err := os.Open("NUL")
+ if err != nil {
+ t.Fatal(err)
+ }
+ fi, err := f.Stat()
+ if err != nil {
+ t.Fatal(err)
+ }
+ if got, want := fi.Mode(), os.ModeDevice|os.ModeCharDevice|0666; got != want {
+ t.Errorf("Open(%q).Stat().Mode() = %v, want %v", "NUL", got, want)
+ }
+}
+
+func TestStatNUL(t *testing.T) {
+ fi, err := os.Stat("NUL")
+ if err != nil {
+ t.Fatal(err)
+ }
+ if got, want := fi.Mode(), os.ModeDevice|os.ModeCharDevice|0666; got != want {
+ t.Errorf("Stat(%q).Mode() = %v, want %v", "NUL", got, want)
+ }
+}
+
// TestSymlinkCreation verifies that creating a symbolic link
// works on Windows when developer mode is active.
// This is supported starting Windows 10 (1703, v10.0.14972).
mklink(t, "relfilelink", "file")
testReadlink(t, "relfilelink", "file")
}
-
-// os.Mkdir(os.DevNull) fails.
-func TestMkdirDevNull(t *testing.T) {
- err := os.Mkdir(os.DevNull, 777)
- oserr, ok := err.(*fs.PathError)
- if !ok {
- t.Fatalf("error (%T) is not *fs.PathError", err)
- }
- errno, ok := oserr.Err.(syscall.Errno)
- if !ok {
- t.Fatalf("error (%T) is not syscall.Errno", oserr)
- }
- if errno != syscall.ENOTDIR {
- t.Fatalf("error %d is not syscall.ENOTDIR", errno)
- }
-}
if file == nil {
return nil, ErrInvalid
}
-
if file.isdir() {
// I don't know any better way to do that for directory
return Stat(file.dirinfo.path)
}
- if isWindowsNulName(file.name) {
- return &devNullStat, nil
- }
-
- ft, err := file.pfd.GetFileType()
- if err != nil {
- return nil, &PathError{Op: "GetFileType", Path: file.name, Err: err}
- }
- switch ft {
- case syscall.FILE_TYPE_PIPE, syscall.FILE_TYPE_CHAR:
- return &fileStat{name: basename(file.name), filetype: ft}, nil
- }
-
- fs, err := newFileStatFromGetFileInformationByHandle(file.name, file.pfd.Sysfd)
- if err != nil {
- return nil, err
- }
- fs.filetype = ft
- return fs, err
+ return statHandle(file.name, file.pfd.Sysfd)
}
// stat implements both Stat and Lstat of a file.
if len(name) == 0 {
return nil, &PathError{Op: funcname, Path: name, Err: syscall.Errno(syscall.ERROR_PATH_NOT_FOUND)}
}
- if isWindowsNulName(name) {
- return &devNullStat, nil
- }
namep, err := syscall.UTF16PtrFromString(fixLongPath(name))
if err != nil {
return nil, &PathError{Op: funcname, Path: name, Err: err}
}
// Finally use CreateFile.
- h, err := syscall.CreateFile(namep, 0, 0, nil,
- syscall.OPEN_EXISTING, createFileAttrs, 0)
+ h, err := syscall.CreateFile(namep,
+ syscall.GENERIC_READ,
+ syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE,
+ nil,
+ syscall.OPEN_EXISTING,
+ createFileAttrs, 0)
if err != nil {
return nil, &PathError{Op: "CreateFile", Path: name, Err: err}
}
defer syscall.CloseHandle(h)
+ return statHandle(name, h)
+}
- return newFileStatFromGetFileInformationByHandle(name, h)
+func statHandle(name string, h syscall.Handle) (FileInfo, error) {
+ ft, err := syscall.GetFileType(h)
+ if err != nil {
+ return nil, &PathError{Op: "GetFileType", Path: name, Err: err}
+ }
+ switch ft {
+ case syscall.FILE_TYPE_PIPE, syscall.FILE_TYPE_CHAR:
+ return &fileStat{name: basename(name), filetype: ft}, nil
+ }
+ fs, err := newFileStatFromGetFileInformationByHandle(name, h)
+ if err != nil {
+ return nil, err
+ }
+ fs.filetype = ft
+ return fs, err
}
// statNolog implements Stat for Windows.
}
func (fs *fileStat) Mode() (m FileMode) {
- if fs == &devNullStat {
- return ModeDevice | ModeCharDevice | 0666
- }
if fs.FileAttributes&syscall.FILE_ATTRIBUTE_READONLY != 0 {
m |= 0444
} else {
return nil
}
-// devNullStat is fileStat structure describing DevNull file ("NUL").
-var devNullStat = fileStat{
- name: DevNull,
- // hopefully this will work for SameFile
- vol: 0,
- idxhi: 0,
- idxlo: 0,
-}
-
func sameFile(fs1, fs2 *fileStat) bool {
e := fs1.loadFileId()
if e != nil {