github.com/zxy12/go_duplicate_112_new@v0.0.0-20200807091221-747231827200/src/os/stat_windows.go (about) 1 // Copyright 2009 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package os 6 7 import ( 8 "internal/syscall/windows" 9 "syscall" 10 "unsafe" 11 ) 12 13 // isNulName reports whether name is NUL file name. 14 // For example, it returns true for both "NUL" and "nul". 15 func isNulName(name string) bool { 16 if len(name) != 3 { 17 return false 18 } 19 if name[0] != 'n' && name[0] != 'N' { 20 return false 21 } 22 if name[1] != 'u' && name[1] != 'U' { 23 return false 24 } 25 if name[2] != 'l' && name[2] != 'L' { 26 return false 27 } 28 return true 29 } 30 31 // Stat returns the FileInfo structure describing file. 32 // If there is an error, it will be of type *PathError. 33 func (file *File) Stat() (FileInfo, error) { 34 if file == nil { 35 return nil, ErrInvalid 36 } 37 38 if file.isdir() { 39 // I don't know any better way to do that for directory 40 return Stat(file.dirinfo.path) 41 } 42 if isNulName(file.name) { 43 return &devNullStat, nil 44 } 45 46 ft, err := file.pfd.GetFileType() 47 if err != nil { 48 return nil, &PathError{"GetFileType", file.name, err} 49 } 50 switch ft { 51 case syscall.FILE_TYPE_PIPE, syscall.FILE_TYPE_CHAR: 52 return &fileStat{name: basename(file.name), filetype: ft}, nil 53 } 54 55 fs, err := newFileStatFromGetFileInformationByHandle(file.name, file.pfd.Sysfd) 56 if err != nil { 57 return nil, err 58 } 59 fs.filetype = ft 60 return fs, err 61 } 62 63 // stat implements both Stat and Lstat of a file. 64 func stat(funcname, name string, createFileAttrs uint32) (FileInfo, error) { 65 if len(name) == 0 { 66 return nil, &PathError{funcname, name, syscall.Errno(syscall.ERROR_PATH_NOT_FOUND)} 67 } 68 if isNulName(name) { 69 return &devNullStat, nil 70 } 71 namep, err := syscall.UTF16PtrFromString(fixLongPath(name)) 72 if err != nil { 73 return nil, &PathError{funcname, name, err} 74 } 75 76 // Try GetFileAttributesEx first, because it is faster than CreateFile. 77 // See https://golang.org/issues/19922#issuecomment-300031421 for details. 78 var fa syscall.Win32FileAttributeData 79 err = syscall.GetFileAttributesEx(namep, syscall.GetFileExInfoStandard, (*byte)(unsafe.Pointer(&fa))) 80 if err == nil && fa.FileAttributes&syscall.FILE_ATTRIBUTE_REPARSE_POINT == 0 { 81 // Not a symlink. 82 fs := &fileStat{ 83 path: name, 84 FileAttributes: fa.FileAttributes, 85 CreationTime: fa.CreationTime, 86 LastAccessTime: fa.LastAccessTime, 87 LastWriteTime: fa.LastWriteTime, 88 FileSizeHigh: fa.FileSizeHigh, 89 FileSizeLow: fa.FileSizeLow, 90 } 91 // Gather full path to be used by os.SameFile later. 92 if !isAbs(fs.path) { 93 fs.path, err = syscall.FullPath(fs.path) 94 if err != nil { 95 return nil, &PathError{"FullPath", name, err} 96 } 97 } 98 fs.name = basename(name) 99 return fs, nil 100 } 101 // GetFileAttributesEx fails with ERROR_SHARING_VIOLATION error for 102 // files, like c:\pagefile.sys. Use FindFirstFile for such files. 103 if err == windows.ERROR_SHARING_VIOLATION { 104 var fd syscall.Win32finddata 105 sh, err := syscall.FindFirstFile(namep, &fd) 106 if err != nil { 107 return nil, &PathError{"FindFirstFile", name, err} 108 } 109 syscall.FindClose(sh) 110 return newFileStatFromWin32finddata(&fd), nil 111 } 112 113 // Finally use CreateFile. 114 h, err := syscall.CreateFile(namep, 0, 0, nil, 115 syscall.OPEN_EXISTING, createFileAttrs, 0) 116 if err != nil { 117 return nil, &PathError{"CreateFile", name, err} 118 } 119 defer syscall.CloseHandle(h) 120 121 return newFileStatFromGetFileInformationByHandle(name, h) 122 } 123 124 // statNolog implements Stat for Windows. 125 func statNolog(name string) (FileInfo, error) { 126 return stat("Stat", name, syscall.FILE_FLAG_BACKUP_SEMANTICS) 127 } 128 129 // lstatNolog implements Lstat for Windows. 130 func lstatNolog(name string) (FileInfo, error) { 131 attrs := uint32(syscall.FILE_FLAG_BACKUP_SEMANTICS) 132 // Use FILE_FLAG_OPEN_REPARSE_POINT, otherwise CreateFile will follow symlink. 133 // See https://docs.microsoft.com/en-us/windows/desktop/FileIO/symbolic-link-effects-on-file-systems-functions#createfile-and-createfiletransacted 134 attrs |= syscall.FILE_FLAG_OPEN_REPARSE_POINT 135 return stat("Lstat", name, attrs) 136 }