aboutsummaryrefslogtreecommitdiff
path: root/src/os/types_windows.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/os/types_windows.go')
-rw-r--r--src/os/types_windows.go68
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
}