Merge commit from fork [v2] RemoveAll: do not follow a symlink at the given path
diff --git a/client.go b/client.go index 688e811..9855d5c 100644 --- a/client.go +++ b/client.go
@@ -933,7 +933,7 @@ // f the path does not exist, RemoveAll returns nil (no error). // If there is an error, it will be of type *PathError. func (cl *Client) RemoveAll(pathname string) error { - fi, err := cl.Stat(pathname) + fi, err := cl.LStat(pathname) if err != nil { if errors.Is(err, fs.ErrNotExist) { return nil
diff --git a/localfs/localfs_integration_test.go b/localfs/localfs_integration_test.go index 4b3da75..ec2358f 100644 --- a/localfs/localfs_integration_test.go +++ b/localfs/localfs_integration_test.go
@@ -893,6 +893,50 @@ } } +func TestRemoveAllSymlink(t *testing.T) { + dir := t.TempDir() + + target := filepath.Join(dir, "removeall-target") + if err := os.Mkdir(target, 0755); err != nil { + t.Fatal(err) + } + + file := filepath.Join(target, "file") + if err := os.WriteFile(file, []byte("foo"), 0644); err != nil { + t.Fatal(err) + } + + link := filepath.Join(dir, "removeall-link") + if err := os.Symlink(target, link); err != nil { + t.Skip("cannot create symlink:", err) + } + + sub := filepath.Join(dir, "removeall-dir") + if err := os.Mkdir(sub, 0755); err != nil { + t.Fatal(err) + } + + if err := os.Symlink(target, filepath.Join(sub, "link")); err != nil { + t.Fatal(err) + } + + if err := cl.RemoveAll(toRemotePath(link)); err != nil { + t.Fatal(err) + } + + if err := cl.RemoveAll(toRemotePath(sub)); err != nil { + t.Fatal(err) + } + + if _, err := os.Lstat(link); !errors.Is(err, fs.ErrNotExist) { + t.Errorf("symlink still exists: %v", err) + } + + if _, err := os.Stat(file); err != nil { + t.Errorf("file behind the symlink was removed: %v", err) + } +} + var benchBuf []byte func benchHelperWriteTo(b *testing.B, length int) {