github.com/bgentry/go@v0.0.0-20150121062915-6cf5a733d54d/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 "syscall" 9 "unsafe" 10 ) 11 12 // Stat returns the FileInfo structure describing file. 13 // If there is an error, it will be of type *PathError. 14 func (file *File) Stat() (fi FileInfo, err error) { 15 if file == nil { 16 return nil, ErrInvalid 17 } 18 if file == nil || file.fd < 0 { 19 return nil, syscall.EINVAL 20 } 21 if file.isdir() { 22 // I don't know any better way to do that for directory 23 return Stat(file.name) 24 } 25 if file.name == DevNull { 26 return &devNullStat, nil 27 } 28 var d syscall.ByHandleFileInformation 29 e := syscall.GetFileInformationByHandle(syscall.Handle(file.fd), &d) 30 if e != nil { 31 return nil, &PathError{"GetFileInformationByHandle", file.name, e} 32 } 33 return &fileStat{ 34 name: basename(file.name), 35 sys: syscall.Win32FileAttributeData{ 36 FileAttributes: d.FileAttributes, 37 CreationTime: d.CreationTime, 38 LastAccessTime: d.LastAccessTime, 39 LastWriteTime: d.LastWriteTime, 40 FileSizeHigh: d.FileSizeHigh, 41 FileSizeLow: d.FileSizeLow, 42 }, 43 vol: d.VolumeSerialNumber, 44 idxhi: d.FileIndexHigh, 45 idxlo: d.FileIndexLow, 46 }, nil 47 } 48 49 // Stat returns a FileInfo structure describing the named file. 50 // If there is an error, it will be of type *PathError. 51 func Stat(name string) (fi FileInfo, err error) { 52 for { 53 fi, err = Lstat(name) 54 if err != nil { 55 return 56 } 57 if fi.Mode()&ModeSymlink == 0 { 58 return 59 } 60 name, err = Readlink(name) 61 if err != nil { 62 return 63 } 64 } 65 return fi, err 66 } 67 68 // Lstat returns the FileInfo structure describing the named file. 69 // If the file is a symbolic link, the returned FileInfo 70 // describes the symbolic link. Lstat makes no attempt to follow the link. 71 // If there is an error, it will be of type *PathError. 72 func Lstat(name string) (fi FileInfo, err error) { 73 if len(name) == 0 { 74 return nil, &PathError{"Lstat", name, syscall.Errno(syscall.ERROR_PATH_NOT_FOUND)} 75 } 76 if name == DevNull { 77 return &devNullStat, nil 78 } 79 fs := &fileStat{name: basename(name)} 80 namep, e := syscall.UTF16PtrFromString(name) 81 if e != nil { 82 return nil, &PathError{"Lstat", name, e} 83 } 84 e = syscall.GetFileAttributesEx(namep, syscall.GetFileExInfoStandard, (*byte)(unsafe.Pointer(&fs.sys))) 85 if e != nil { 86 return nil, &PathError{"GetFileAttributesEx", name, e} 87 } 88 fs.path = name 89 if !isAbs(fs.path) { 90 fs.path, e = syscall.FullPath(fs.path) 91 if e != nil { 92 return nil, e 93 } 94 } 95 return fs, nil 96 } 97 98 // basename removes trailing slashes and the leading 99 // directory name and drive letter from path name. 100 func basename(name string) string { 101 // Remove drive letter 102 if len(name) == 2 && name[1] == ':' { 103 name = "." 104 } else if len(name) > 2 && name[1] == ':' { 105 name = name[2:] 106 } 107 i := len(name) - 1 108 // Remove trailing slashes 109 for ; i > 0 && (name[i] == '/' || name[i] == '\\'); i-- { 110 name = name[:i] 111 } 112 // Remove leading directory name 113 for i--; i >= 0; i-- { 114 if name[i] == '/' || name[i] == '\\' { 115 name = name[i+1:] 116 break 117 } 118 } 119 return name 120 } 121 122 func isAbs(path string) (b bool) { 123 v := volumeName(path) 124 if v == "" { 125 return false 126 } 127 path = path[len(v):] 128 if path == "" { 129 return false 130 } 131 return IsPathSeparator(path[0]) 132 } 133 134 func volumeName(path string) (v string) { 135 if len(path) < 2 { 136 return "" 137 } 138 // with drive letter 139 c := path[0] 140 if path[1] == ':' && 141 ('0' <= c && c <= '9' || 'a' <= c && c <= 'z' || 142 'A' <= c && c <= 'Z') { 143 return path[:2] 144 } 145 // is it UNC 146 if l := len(path); l >= 5 && IsPathSeparator(path[0]) && IsPathSeparator(path[1]) && 147 !IsPathSeparator(path[2]) && path[2] != '.' { 148 // first, leading `\\` and next shouldn't be `\`. its server name. 149 for n := 3; n < l-1; n++ { 150 // second, next '\' shouldn't be repeated. 151 if IsPathSeparator(path[n]) { 152 n++ 153 // third, following something characters. its share name. 154 if !IsPathSeparator(path[n]) { 155 if path[n] == '.' { 156 break 157 } 158 for ; n < l; n++ { 159 if IsPathSeparator(path[n]) { 160 break 161 } 162 } 163 return path[:n] 164 } 165 break 166 } 167 } 168 } 169 return "" 170 }