Merge pull request #4954 from MichaelEischer/improve-windows-path-handling

Improve windows path handling
This commit is contained in:
Michael Eischer 2024-08-03 18:22:39 +02:00 committed by GitHub
commit 3faeddcd5f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 46 additions and 6 deletions

View file

@ -0,0 +1,7 @@
Bugfix: Correctly handle long paths on older Windows versions
When using older Windows versions, like Windows Server 2012, restic 0.17.0
failed to back up files with long paths. This has been fixed.
https://github.com/restic/restic/issues/4953
https://github.com/restic/restic/pull/4954

View file

@ -134,7 +134,7 @@ func IsAccessDenied(err error) bool {
// ResetPermissions resets the permissions of the file at the specified path
func ResetPermissions(path string) error {
// Set the default file permissions
if err := os.Chmod(path, 0600); err != nil {
if err := os.Chmod(fixpath(path), 0600); err != nil {
return err
}
return nil

View file

@ -85,7 +85,7 @@ func ClearSystem(path string) error {
// ClearAttribute removes the specified attribute from the file.
func ClearAttribute(path string, attribute uint32) error {
ptr, err := windows.UTF16PtrFromString(path)
ptr, err := windows.UTF16PtrFromString(fixpath(path))
if err != nil {
return err
}

View file

@ -129,22 +129,22 @@ func SetSecurityDescriptor(filePath string, securityDescriptor *[]byte) error {
// getNamedSecurityInfoHigh gets the higher level SecurityDescriptor which requires admin permissions.
func getNamedSecurityInfoHigh(filePath string) (*windows.SECURITY_DESCRIPTOR, error) {
return windows.GetNamedSecurityInfo(filePath, windows.SE_FILE_OBJECT, highSecurityFlags)
return windows.GetNamedSecurityInfo(fixpath(filePath), windows.SE_FILE_OBJECT, highSecurityFlags)
}
// getNamedSecurityInfoLow gets the lower level SecurityDescriptor which requires no admin permissions.
func getNamedSecurityInfoLow(filePath string) (*windows.SECURITY_DESCRIPTOR, error) {
return windows.GetNamedSecurityInfo(filePath, windows.SE_FILE_OBJECT, lowBackupSecurityFlags)
return windows.GetNamedSecurityInfo(fixpath(filePath), windows.SE_FILE_OBJECT, lowBackupSecurityFlags)
}
// setNamedSecurityInfoHigh sets the higher level SecurityDescriptor which requires admin permissions.
func setNamedSecurityInfoHigh(filePath string, owner *windows.SID, group *windows.SID, dacl *windows.ACL, sacl *windows.ACL) error {
return windows.SetNamedSecurityInfo(filePath, windows.SE_FILE_OBJECT, highSecurityFlags, owner, group, dacl, sacl)
return windows.SetNamedSecurityInfo(fixpath(filePath), windows.SE_FILE_OBJECT, highSecurityFlags, owner, group, dacl, sacl)
}
// setNamedSecurityInfoLow sets the lower level SecurityDescriptor which requires no admin permissions.
func setNamedSecurityInfoLow(filePath string, dacl *windows.ACL) error {
return windows.SetNamedSecurityInfo(filePath, windows.SE_FILE_OBJECT, lowRestoreSecurityFlags, nil, nil, dacl, nil)
return windows.SetNamedSecurityInfo(fixpath(filePath), windows.SE_FILE_OBJECT, lowRestoreSecurityFlags, nil, nil, dacl, nil)
}
// enableBackupPrivilege enables privilege for backing up security descriptors

View file

@ -1506,3 +1506,36 @@ func TestRestoreToFile(t *testing.T) {
err := res.RestoreTo(ctx, tempdir)
rtest.Assert(t, strings.Contains(err.Error(), "cannot create target directory"), "unexpected error %v", err)
}
func TestRestorerLongPath(t *testing.T) {
tmp := t.TempDir()
longPath := tmp
for i := 0; i < 20; i++ {
longPath = filepath.Join(longPath, "aaaaaaaaaaaaaaaaaaaa")
}
rtest.OK(t, os.MkdirAll(longPath, 0o700))
f, err := fs.OpenFile(filepath.Join(longPath, "file"), fs.O_CREATE|fs.O_RDWR, 0o600)
rtest.OK(t, err)
_, err = f.WriteString("Hello, World!")
rtest.OK(t, err)
rtest.OK(t, f.Close())
repo := repository.TestRepository(t)
local := &fs.Local{}
sc := archiver.NewScanner(local)
rtest.OK(t, sc.Scan(context.TODO(), []string{tmp}))
arch := archiver.New(repo, local, archiver.Options{})
sn, _, _, err := arch.Snapshot(context.Background(), []string{tmp}, archiver.SnapshotOptions{})
rtest.OK(t, err)
res := NewRestorer(repo, sn, Options{})
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
rtest.OK(t, res.RestoreTo(ctx, tmp))
_, err = res.VerifyFiles(ctx, tmp)
rtest.OK(t, err)
}