From 62c4a5e9a0f463203120aba3bb7fc76896b19f8a Mon Sep 17 00:00:00 2001 From: Michael Eischer Date: Mon, 29 Jul 2024 20:10:58 +0200 Subject: [PATCH 1/3] fs: fix long path handling for ResetPermissions, ClearAttributes and security descriptors --- internal/fs/file.go | 2 +- internal/fs/file_windows.go | 2 +- internal/fs/sd_windows.go | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/internal/fs/file.go b/internal/fs/file.go index 929195f1c..85b202dc8 100644 --- a/internal/fs/file.go +++ b/internal/fs/file.go @@ -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 diff --git a/internal/fs/file_windows.go b/internal/fs/file_windows.go index b05068c42..50c7e9938 100644 --- a/internal/fs/file_windows.go +++ b/internal/fs/file_windows.go @@ -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 } diff --git a/internal/fs/sd_windows.go b/internal/fs/sd_windows.go index 5d98b4ef4..2da1c5df4 100644 --- a/internal/fs/sd_windows.go +++ b/internal/fs/sd_windows.go @@ -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 From a9be9867828b65d1b8ac6c21c9d695b0ee294ec2 Mon Sep 17 00:00:00 2001 From: Michael Eischer Date: Mon, 29 Jul 2024 21:11:47 +0200 Subject: [PATCH 2/3] restorer: add minimal long path handling test --- internal/restorer/restorer_test.go | 33 ++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/internal/restorer/restorer_test.go b/internal/restorer/restorer_test.go index 9c02afe68..191f3b8ef 100644 --- a/internal/restorer/restorer_test.go +++ b/internal/restorer/restorer_test.go @@ -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) +} From b3bfb5ed44c255820989d621b429e62730ae5c66 Mon Sep 17 00:00:00 2001 From: Michael Eischer Date: Sat, 3 Aug 2024 18:09:28 +0200 Subject: [PATCH 3/3] add changelog for long paths on windows --- changelog/unreleased/issue-4953 | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 changelog/unreleased/issue-4953 diff --git a/changelog/unreleased/issue-4953 b/changelog/unreleased/issue-4953 new file mode 100644 index 000000000..78a266aff --- /dev/null +++ b/changelog/unreleased/issue-4953 @@ -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