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