Merge 1dc85e5fcaec5c7c8a5dbb5a914935bb84b2fd6a into e0d477804b583163b4b5696d24a2ccf8c0bb11e3

This commit is contained in:
Herlon Aguiar 2025-02-20 23:57:17 +00:00 committed by GitHub
commit c74a5ad9cf
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 73 additions and 0 deletions

View File

@ -7,7 +7,10 @@ import (
"os"
"path/filepath"
"regexp"
"strings"
"syscall"
"golang.org/x/sys/windows/registry"
)
// OpenFile is the generalized open call; most users will use Open or Create
@ -27,6 +30,14 @@ func OpenFile(path string, mode int, perm os.FileMode) (*os.File, error) {
if len(path) == 0 {
return nil, syscall.ERROR_FILE_NOT_FOUND
}
// For windows the max path length is 260 characters
// if the LongPathsEnabled is not set
// https://docs.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation
if !strings.HasPrefix(path, `\\?\`) && !IsLongPathsEnabled() && len(path) >= 260 {
return nil, &os.PathError{Path: path, Op: "open", Err: errors.New("path length 260 or higher")}
}
pathp, err := syscall.UTF16PtrFromString(path)
if err != nil {
return nil, err
@ -100,3 +111,24 @@ func IsReserved(path string) error {
}
return nil
}
// IsLongPathsEnabled checks if the current have the LongPathsEnabled enabled
func IsLongPathsEnabled() bool {
// Read registry
k, err := registry.OpenKey(registry.LOCAL_MACHINE, `SYSTEM\CurrentControlSet\Control\FileSystem`, registry.QUERY_VALUE)
if err != nil {
return false
}
defer k.Close()
s, _, err := k.GetIntegerValue("LongPathsEnabled")
if err != nil {
return false
}
if s == 0x00000001 {
return true
} else {
return false
}
}

View File

@ -0,0 +1,21 @@
//go:build windows
// +build windows
package file
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestFileOpenMaxPathLength(t *testing.T) {
// Skip if the long path is enabled
if IsLongPathsEnabled() {
t.Skip()
}
path := `C:\my\path\my\path\my\path\my\path\my\path\my\path\my\path\my\path\my\path\my\path\my\path\my\path\my\path\my\path\my\path\my\path\my\path\my\path\my\path\my\path\my\path\my\path\my\path\my\path\my\path\my\path\my\path\my\path\my\path\my\path\my\path\my\path\my\path`
_, err := OpenFile(path, 0644, 0644)
assert.Error(t, err, "mkdir: Max path length can't exceed 260")
}

View File

@ -3,8 +3,10 @@
package file
import (
"errors"
"os"
"path/filepath"
"strings"
"syscall"
)
@ -17,6 +19,13 @@ import (
// Based on source code from golang's os.MkdirAll
// (https://github.com/golang/go/blob/master/src/os/path.go)
func MkdirAll(path string, perm os.FileMode) error {
// For windows the max path length is 260 characters
// if the LongPathsEnabled is not set
// https://docs.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation
if !strings.HasPrefix(path, `\\?\`) && !IsLongPathsEnabled() && len(path) >= 260 {
return &os.PathError{Path: path, Op: "open", Err: errors.New("path length 260 or higher")}
}
// Fast path: if we can tell whether path is a directory or file, stop with success or error.
dir, err := os.Stat(path)
if err == nil {

View File

@ -159,3 +159,14 @@ func TestMkdirAllOnUnusedNetworkHost(t *testing.T) {
)
}
func TestMkdirMaxPathLength(t *testing.T) {
// Skip if the long path is enabled
if IsLongPathsEnabled() {
t.Skip()
}
path := `C:\my\path\my\path\my\path\my\path\my\path\my\path\my\path\my\path\my\path\my\path\my\path\my\path\my\path\my\path\my\path\my\path\my\path\my\path\my\path\my\path\my\path\my\path\my\path\my\path\my\path\my\path\my\path\my\path\my\path\my\path\my\path\my\path\my\path`
err := MkdirAll(path, 0777)
assert.Error(t, err, "mkdir: Max path length can't exceed 260")
}