diff options
Diffstat (limited to 'src/os/types_windows.go')
-rw-r--r-- | src/os/types_windows.go | 68 |
1 files changed, 64 insertions, 4 deletions
diff --git a/src/os/types_windows.go b/src/os/types_windows.go index 9a3d508783..6b9fef6c12 100644 --- a/src/os/types_windows.go +++ b/src/os/types_windows.go @@ -16,7 +16,7 @@ import ( type fileStat struct { name string - // from ByHandleFileInformation, Win32FileAttributeData and Win32finddata + // from ByHandleFileInformation, Win32FileAttributeData, Win32finddata, and GetFileInformationByHandleEx FileAttributes uint32 CreationTime syscall.Filetime LastAccessTime syscall.Filetime @@ -24,7 +24,7 @@ type fileStat struct { FileSizeHigh uint32 FileSizeLow uint32 - // from Win32finddata + // from Win32finddata and GetFileInformationByHandleEx ReparseTag uint32 // what syscall.GetFileType returns @@ -80,6 +80,40 @@ func newFileStatFromGetFileInformationByHandle(path string, h syscall.Handle) (f }, nil } +// newFileStatFromFileIDBothDirInfo copies all required information +// from windows.FILE_ID_BOTH_DIR_INFO d into the newly created fileStat. +func newFileStatFromFileIDBothDirInfo(d *windows.FILE_ID_BOTH_DIR_INFO) *fileStat { + // The FILE_ID_BOTH_DIR_INFO MSDN documentations isn't completely correct. + // FileAttributes can contain any file attributes that is currently set on the file, + // not just the ones documented. + // EaSize contains the reparse tag if the file is a reparse point. + return &fileStat{ + FileAttributes: d.FileAttributes, + CreationTime: d.CreationTime, + LastAccessTime: d.LastAccessTime, + LastWriteTime: d.LastWriteTime, + FileSizeHigh: uint32(d.EndOfFile >> 32), + FileSizeLow: uint32(d.EndOfFile), + ReparseTag: d.EaSize, + idxhi: uint32(d.FileID >> 32), + idxlo: uint32(d.FileID), + } +} + +// newFileStatFromFileFullDirInfo copies all required information +// from windows.FILE_FULL_DIR_INFO d into the newly created fileStat. +func newFileStatFromFileFullDirInfo(d *windows.FILE_FULL_DIR_INFO) *fileStat { + return &fileStat{ + FileAttributes: d.FileAttributes, + CreationTime: d.CreationTime, + LastAccessTime: d.LastAccessTime, + LastWriteTime: d.LastWriteTime, + FileSizeHigh: uint32(d.EndOfFile >> 32), + FileSizeLow: uint32(d.EndOfFile), + ReparseTag: d.EaSize, + } +} + // newFileStatFromWin32finddata copies all required information // from syscall.Win32finddata d into the newly created fileStat. func newFileStatFromWin32finddata(d *syscall.Win32finddata) *fileStat { @@ -101,6 +135,16 @@ func newFileStatFromWin32finddata(d *syscall.Win32finddata) *fileStat { return fs } +// isReparseTagNameSurrogate determines whether a tag's associated +// reparse point is a surrogate for another named entity (for example, a mounted folder). +// +// See https://learn.microsoft.com/en-us/windows/win32/api/winnt/nf-winnt-isreparsetagnamesurrogate +// and https://learn.microsoft.com/en-us/windows/win32/fileio/reparse-point-tags. +func (fs *fileStat) isReparseTagNameSurrogate() bool { + // True for IO_REPARSE_TAG_SYMLINK and IO_REPARSE_TAG_MOUNT_POINT. + return fs.ReparseTag&0x20000000 != 0 +} + func (fs *fileStat) isSymlink() bool { // As of https://go.dev/cl/86556, we treat MOUNT_POINT reparse points as // symlinks because otherwise certain directory junction tests in the @@ -141,7 +185,23 @@ func (fs *fileStat) Mode() (m FileMode) { m |= ModeDevice | ModeCharDevice } if fs.FileAttributes&syscall.FILE_ATTRIBUTE_REPARSE_POINT != 0 && m&ModeType == 0 { - m |= ModeIrregular + if fs.ReparseTag == windows.IO_REPARSE_TAG_DEDUP { + // If the Data Deduplication service is enabled on Windows Server, its + // Optimization job may convert regular files to IO_REPARSE_TAG_DEDUP + // whenever that job runs. + // + // However, DEDUP reparse points remain similar in most respects to + // regular files: they continue to support random-access reads and writes + // of persistent data, and they shouldn't add unexpected latency or + // unavailability in the way that a network filesystem might. + // + // Go programs may use ModeIrregular to filter out unusual files (such as + // raw device files on Linux, POSIX FIFO special files, and so on), so + // to avoid files changing unpredictably from regular to irregular we will + // consider DEDUP files to be close enough to regular to treat as such. + } else { + m |= ModeIrregular + } } return m } @@ -171,7 +231,7 @@ func (fs *fileStat) loadFileId() error { } var path string if fs.appendNameToPath { - path = fs.path + `\` + fs.name + path = fixLongPath(fs.path + `\` + fs.name) } else { path = fs.path } |