package wincmd import ( "b612.me/win32api" "golang.org/x/sys/windows" "os" "sync" "syscall" "time" ) const DevNull = "NUL" // A fileStat is the implementation of FileInfo returned by Stat and Lstat. type FileStat struct { name string // from ByHandleFileInformation, Win32FileAttributeData and Win32finddata FileAttributes uint32 CreationTime syscall.Filetime LastAccessTime syscall.Filetime LastWriteTime syscall.Filetime FileSizeHigh uint32 FileSizeLow uint32 // from Win32finddata Reserved0 uint32 // what syscall.GetFileType returns filetype uint32 // used to implement SameFile sync.Mutex path string vol uint32 idxhi uint32 idxlo uint32 appendNameToPath bool } // newFileStatFromWin32finddata copies all required information // from syscall.Win32finddata d into the newly created fileStat. func newFileStatFromInformation(d *syscall.ByHandleFileInformation, name string, path string) *FileStat { return &FileStat{ name: name, path: path, FileAttributes: d.FileAttributes, CreationTime: d.CreationTime, LastAccessTime: d.LastAccessTime, LastWriteTime: d.LastWriteTime, FileSizeHigh: d.FileSizeHigh, FileSizeLow: d.FileSizeLow, } } func (fs *FileStat) Name() string { return fs.name } func (fs *FileStat) IsDir() bool { return fs.FileAttributes&win32api.FILE_ATTRIBUTE_DIRECTORY != 0 } func (fs *FileStat) isSymlink() bool { // Use instructions described at // https://blogs.msdn.microsoft.com/oldnewthing/20100212-00/?p=14963/ // to recognize whether it's a symlink. if fs.FileAttributes&syscall.FILE_ATTRIBUTE_REPARSE_POINT == 0 { return false } return fs.Reserved0 == syscall.IO_REPARSE_TAG_SYMLINK || fs.Reserved0 == windows.IO_REPARSE_TAG_MOUNT_POINT } func (fs *FileStat) Size() int64 { return int64(fs.FileSizeHigh)<<32 + int64(fs.FileSizeLow) } func (fs *FileStat) Mode() (m os.FileMode) { if fs == &devNullStat { return os.ModeDevice | os.ModeCharDevice | 0666 } if fs.FileAttributes&syscall.FILE_ATTRIBUTE_READONLY != 0 { m |= 0444 } else { m |= 0666 } if fs.isSymlink() { return m | os.ModeSymlink } if fs.FileAttributes&syscall.FILE_ATTRIBUTE_DIRECTORY != 0 { m |= os.ModeDir | 0111 } switch fs.filetype { case syscall.FILE_TYPE_PIPE: m |= os.ModeNamedPipe case syscall.FILE_TYPE_CHAR: m |= os.ModeDevice | os.ModeCharDevice } return m } func (fs *FileStat) ModTime() time.Time { return time.Unix(0, fs.LastWriteTime.Nanoseconds()) } // Sys returns syscall.Win32FileAttributeData for file fs. func (fs *FileStat) Sys() interface{} { return &syscall.Win32FileAttributeData{ FileAttributes: fs.FileAttributes, CreationTime: fs.CreationTime, LastAccessTime: fs.LastAccessTime, LastWriteTime: fs.LastWriteTime, FileSizeHigh: fs.FileSizeHigh, FileSizeLow: fs.FileSizeLow, } } // saveInfoFromPath saves full path of the file to be used by os.SameFile later, // and set name from path. // 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, }