From b2cfdc835c8146228f117ccbbc292c60dcfa46d4 Mon Sep 17 00:00:00 2001 From: Jalileh Date: Fri, 10 Jan 2025 21:19:28 +0100 Subject: [PATCH 1/3] fileMode-fix for issue #1694 Windows bug windows symlinks are strange and they are not treated as directories in go, so using just fileInfo.Dir isn't enough. --- pkg/util/utilfn/utilfn.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/pkg/util/utilfn/utilfn.go b/pkg/util/utilfn/utilfn.go index f70b5b46aa..29c77ea569 100644 --- a/pkg/util/utilfn/utilfn.go +++ b/pkg/util/utilfn/utilfn.go @@ -621,6 +621,12 @@ func CopyToChannel(outputCh chan<- []byte, reader io.Reader) error { // does not return "application/octet-stream" as this is considered a detection failure // can pass an existing fileInfo to avoid re-statting the file // falls back to text/plain for 0 byte files + +func isWinSymlink(bits os.FileMode) bool { + WIN_SYMLINK := os.ModeSymlink + return (bits&WIN_SYMLINK > 0) +} + func DetectMimeType(path string, fileInfo fs.FileInfo, extended bool) string { if fileInfo == nil { statRtn, err := os.Stat(path) @@ -629,7 +635,7 @@ func DetectMimeType(path string, fileInfo fs.FileInfo, extended bool) string { } fileInfo = statRtn } - if fileInfo.IsDir() { + if fileInfo.IsDir() || isWinSymlink(fileInfo.Mode()) { return "directory" } if fileInfo.Mode()&os.ModeNamedPipe == os.ModeNamedPipe { From 8f06fff3f9feace0494b94a39dad6cf93c9ebc7d Mon Sep 17 00:00:00 2001 From: Jalileh Date: Fri, 17 Jan 2025 17:26:34 +0100 Subject: [PATCH 2/3] both junction and softlink now work on windows when using fileviewer Added a cheesy workaround to distinguish between files and dir when softlinks are used. --- pkg/util/utilfn/utilfn.go | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/pkg/util/utilfn/utilfn.go b/pkg/util/utilfn/utilfn.go index 29c77ea569..a3f046c5cd 100644 --- a/pkg/util/utilfn/utilfn.go +++ b/pkg/util/utilfn/utilfn.go @@ -617,16 +617,37 @@ func CopyToChannel(outputCh chan<- []byte, reader io.Reader) error { } } +func WinSymlinkDir(path string, bits os.FileMode) bool { + /* for the cursed softlink on windows + the compability fileInfo interface gives us no way to determine its pointing type */ + isFileSymlink := func(filepath string) bool { + Length := len(filepath) - 1 + maxFileDotExt := 4 // should cover most file extensions + for i := Length; i >= (Length - maxFileDotExt); i-- { + if filepath[i] == '.' { + return true + } + } + return false + } + + winSymlink_flags := uint32(bits >> 12) + FLAG_SOFTLINK, FLAG_JUNCTION := uint32(0x8000), uint32(0x80) + + if winSymlink_flags == FLAG_SOFTLINK { + return !isFileSymlink(path) + } else if winSymlink_flags == FLAG_JUNCTION { + return true + } else { + return false + } +} + // on error just returns "" // does not return "application/octet-stream" as this is considered a detection failure // can pass an existing fileInfo to avoid re-statting the file // falls back to text/plain for 0 byte files -func isWinSymlink(bits os.FileMode) bool { - WIN_SYMLINK := os.ModeSymlink - return (bits&WIN_SYMLINK > 0) -} - func DetectMimeType(path string, fileInfo fs.FileInfo, extended bool) string { if fileInfo == nil { statRtn, err := os.Stat(path) @@ -635,7 +656,8 @@ func DetectMimeType(path string, fileInfo fs.FileInfo, extended bool) string { } fileInfo = statRtn } - if fileInfo.IsDir() || isWinSymlink(fileInfo.Mode()) { + + if fileInfo.IsDir() || WinSymlinkDir(path, fileInfo.Mode()) { return "directory" } if fileInfo.Mode()&os.ModeNamedPipe == os.ModeNamedPipe { From 69e17c0747b6171e03c5726afd746bec28b3b3cf Mon Sep 17 00:00:00 2001 From: Jalileh Date: Fri, 17 Jan 2025 17:46:58 +0100 Subject: [PATCH 3/3] PR refractor --- pkg/util/utilfn/utilfn.go | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/pkg/util/utilfn/utilfn.go b/pkg/util/utilfn/utilfn.go index a3f046c5cd..11d4795ab5 100644 --- a/pkg/util/utilfn/utilfn.go +++ b/pkg/util/utilfn/utilfn.go @@ -617,26 +617,26 @@ func CopyToChannel(outputCh chan<- []byte, reader io.Reader) error { } } +const ( + winFlagSoftlink = uint32(0x8000) // FILE_ATTRIBUTE_REPARSE_POINT + winFlagJunction = uint32(0x80) // FILE_ATTRIBUTE_JUNCTION +) + func WinSymlinkDir(path string, bits os.FileMode) bool { - /* for the cursed softlink on windows - the compability fileInfo interface gives us no way to determine its pointing type */ + // Windows compatibility layer doesn't expose symlink target type through fileInfo + // so we need to check file attributes and extension patterns isFileSymlink := func(filepath string) bool { - Length := len(filepath) - 1 - maxFileDotExt := 4 // should cover most file extensions - for i := Length; i >= (Length - maxFileDotExt); i-- { - if filepath[i] == '.' { - return true - } + if len(filepath) == 0 { + return false } - return false + return strings.LastIndex(filepath, ".") > strings.LastIndex(filepath, "/") } - winSymlink_flags := uint32(bits >> 12) - FLAG_SOFTLINK, FLAG_JUNCTION := uint32(0x8000), uint32(0x80) + flags := uint32(bits >> 12) - if winSymlink_flags == FLAG_SOFTLINK { + if flags == winFlagSoftlink { return !isFileSymlink(path) - } else if winSymlink_flags == FLAG_JUNCTION { + } else if flags == winFlagJunction { return true } else { return false