s3: fix rmdir of the root directory with --s3-directory-markers

Rmdir only removed the directory marker of a directory below the root
of the remote, so `rclone rmdir remote:bucket/dir` left the marker of
dir behind, and with it the directory.
This commit is contained in:
Nick Craig-Wood committed 2026-10-29 11:01:45 +00:00
1 parent cb73c3ae0b
commit 98a8e793bd
2 files changed
+30 -2

No files matched your search

+3 -2
View File
@@ -2978,8 +2978,9 @@ func (f *Fs) makeBucket(ctx context.Context, bucket string) error {
// Returns an error if it isn't empty
func (f *Fs) Rmdir(ctx context.Context, dir string) error {
bucket, directory := f.split(dir)
// Remove directory marker file
if f.opt.DirectoryMarkers && bucket != "" && dir != "" {
// Remove directory marker file, including the one of the root
// when it is a directory in the bucket
if f.opt.DirectoryMarkers && bucket != "" && directory != "" {
o := &Object{
fs: f,
remote: dir + "/",
+27
View File
@@ -12,6 +12,7 @@ import (
"net/http"
"net/http/httptest"
"path"
"slices"
"strings"
"testing"
"time"
@@ -891,6 +892,31 @@ func (f *Fs) InternalTestObjectLock(t *testing.T) {
})
}
// InternalTestRmdirRoot checks the directory marker of the root of a
// remote is removed by Rmdir.
func (f *Fs) InternalTestRmdirRoot(t *testing.T) {
if !f.opt.DirectoryMarkers {
t.Skip("needs --s3-directory-markers")
}
ctx := context.Background()
dir := "rmdir-root-" + random.String(8)
hasDir := func() bool {
entries, err := f.List(ctx, "")
require.NoError(t, err)
return slices.ContainsFunc(entries, func(entry fs.DirEntry) bool {
_, isDir := entry.(fs.Directory)
return isDir && entry.Remote() == dir
})
}
require.NoError(t, f.Mkdir(ctx, dir))
require.True(t, hasDir(), "directory marker not made")
fDir, err := cache.Get(ctx, bucket.Join(fs.ConfigStringFull(f), dir))
require.NoError(t, err)
require.NoError(t, fDir.Rmdir(ctx, ""))
assert.False(t, hasDir(), "directory marker not removed")
}
func (f *Fs) InternalTest(t *testing.T) {
t.Run("Metadata", f.InternalTestMetadata)
t.Run("NoHead", f.InternalTestNoHead)
@@ -898,6 +924,7 @@ func (f *Fs) InternalTest(t *testing.T) {
t.Run("HasChildren", f.InternalTestHasChildren)
t.Run("Versions", f.InternalTestVersions)
t.Run("ObjectLock", f.InternalTestObjectLock)
t.Run("RmdirRoot", f.InternalTestRmdirRoot)
}
var _ fstests.InternalTester = (*Fs)(nil)