github.com/dannin/go@v0.0.0-20161031215817-d35dfd405eaa/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 // Stat returns the FileInfo structure describing file. 14 // If there is an error, it will be of type *PathError. 15 func (file *File) Stat() (FileInfo, error) { 16 if file == nil { 17 return nil, ErrInvalid 18 } 19 if file == nil || file.fd < 0 { 20 return nil, syscall.EINVAL 21 } 22 if file.isdir() { 23 // I don't know any better way to do that for directory 24 return Stat(file.dirinfo.path) 25 } 26 if file.name == DevNull { 27 return &devNullStat, nil 28 } 29 30 ft, err := syscall.GetFileType(file.fd) 31 if err != nil { 32 return nil, &PathError{"GetFileType", file.name, err} 33 } 34 if ft == syscall.FILE_TYPE_PIPE { 35 return &fileStat{name: basename(file.name), pipe: true}, nil 36 } 37 38 var d syscall.ByHandleFileInformation 39 err = syscall.GetFileInformationByHandle(file.fd, &d) 40 if err != nil { 41 return nil, &PathError{"GetFileInformationByHandle", file.name, err} 42 } 43 return &fileStat{ 44 name: basename(file.name), 45 sys: syscall.Win32FileAttributeData{ 46 FileAttributes: d.FileAttributes, 47 CreationTime: d.CreationTime, 48 LastAccessTime: d.LastAccessTime, 49 LastWriteTime: d.LastWriteTime, 50 FileSizeHigh: d.FileSizeHigh, 51 FileSizeLow: d.FileSizeLow, 52 }, 53 vol: d.VolumeSerialNumber, 54 idxhi: d.FileIndexHigh, 55 idxlo: d.FileIndexLow, 56 pipe: false, 57 }, nil 58 } 59 60 // Stat returns a FileInfo structure describing the named file. 61 // If there is an error, it will be of type *PathError. 62 func Stat(name string) (FileInfo, error) { 63 var fi FileInfo 64 var err error 65 for i := 0; i < 255; i++ { 66 fi, err = Lstat(name) 67 if err != nil { 68 return fi, err 69 } 70 if fi.Mode()&ModeSymlink == 0 { 71 return fi, nil 72 } 73 name, err = Readlink(name) 74 if err != nil { 75 return fi, err 76 } 77 } 78 return nil, &PathError{"Stat", name, syscall.ELOOP} 79 } 80 81 // Lstat returns the FileInfo structure describing the named file. 82 // If the file is a symbolic link, the returned FileInfo 83 // describes the symbolic link. Lstat makes no attempt to follow the link. 84 // If there is an error, it will be of type *PathError. 85 func Lstat(name string) (FileInfo, error) { 86 if len(name) == 0 { 87 return nil, &PathError{"Lstat", name, syscall.Errno(syscall.ERROR_PATH_NOT_FOUND)} 88 } 89 if name == DevNull { 90 return &devNullStat, nil 91 } 92 fs := &fileStat{name: basename(name)} 93 namep, e := syscall.UTF16PtrFromString(name) 94 if e != nil { 95 return nil, &PathError{"Lstat", name, e} 96 } 97 e = syscall.GetFileAttributesEx(namep, syscall.GetFileExInfoStandard, (*byte)(unsafe.Pointer(&fs.sys))) 98 if e != nil { 99 if e != windows.ERROR_SHARING_VIOLATION { 100 return nil, &PathError{"GetFileAttributesEx", name, e} 101 } 102 // try FindFirstFile now that GetFileAttributesEx failed 103 var fd syscall.Win32finddata 104 h, e2 := syscall.FindFirstFile(namep, &fd) 105 if e2 != nil { 106 return nil, &PathError{"FindFirstFile", name, e} 107 } 108 syscall.FindClose(h) 109 110 fs.sys.FileAttributes = fd.FileAttributes 111 fs.sys.CreationTime = fd.CreationTime 112 fs.sys.LastAccessTime = fd.LastAccessTime 113 fs.sys.LastWriteTime = fd.LastWriteTime 114 fs.sys.FileSizeHigh = fd.FileSizeHigh 115 fs.sys.FileSizeLow = fd.FileSizeLow 116 } 117 fs.path = name 118 if !isAbs(fs.path) { 119 fs.path, e = syscall.FullPath(fs.path) 120 if e != nil { 121 return nil, e 122 } 123 } 124 return fs, nil 125 }