From 7ff5da8517154d5528a2d9be8d77f33b24dcdec0 Mon Sep 17 00:00:00 2001 From: Nick Craig-Wood Date: Wed, 23 Sep 2026 12:29:45 +0100 Subject: [PATCH] internxt: fix "directory not empty" and stale directories after moves and deletes The Internxt API serves listings from read replicas which lag behind writes, so for a short while after files or directories are moved or deleted they can still be listed in their old location. This caused removing a directory which had just been emptied to fail with "directory not empty" (eg when moving a directory without server side directory moves or purging a directory) and a directory which had just been moved to be found in its old location. Remember the directories this process has moved or deleted and ignore directory and file entries which contradict that when listing, finding directories and checking a directory is empty before removing it. --- backend/internxt/internxt.go | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/backend/internxt/internxt.go b/backend/internxt/internxt.go index fc4f1b46f..a2b985b6b 100644 --- a/backend/internxt/internxt.go +++ b/backend/internxt/internxt.go @@ -474,8 +474,10 @@ func (f *Fs) Rmdir(ctx context.Context, dir string) error { if err != nil { return err } - if len(childFolders) > 0 { - return fs.ErrorDirectoryNotEmpty + for _, e := range childFolders { + if !recent.stale(e.UUID, id, e.PlainName) { + return fs.ErrorDirectoryNotEmpty + } } var childFiles []folders.File @@ -487,8 +489,10 @@ func (f *Fs) Rmdir(ctx context.Context, dir string) error { if err != nil { return err } - if len(childFiles) > 0 { - return fs.ErrorDirectoryNotEmpty + for _, e := range childFiles { + if !recent.stale(e.UUID, id, joinNameExt(e.PlainName, e.Type)) { + return fs.ErrorDirectoryNotEmpty + } } // Delete the directory @@ -502,6 +506,7 @@ func (f *Fs) Rmdir(ctx context.Context, dir string) error { if err != nil { return err } + recent.deleted(id) f.dirCache.FlushDir(dir) return nil @@ -520,6 +525,9 @@ func (f *Fs) FindLeaf(ctx context.Context, pathID, leaf string) (string, bool, e return "", false, err } for _, e := range entries { + if recent.stale(e.UUID, pathID, e.PlainName) { + continue + } if f.opt.Encoding.ToStandardName(e.PlainName) == leaf { return e.UUID, true, nil } @@ -753,6 +761,9 @@ func (f *Fs) List(ctx context.Context, dir string) (fs.DirEntries, error) { return nil, err } for _, e := range foldersList { + if recent.stale(e.UUID, dirID, e.PlainName) { + continue + } remote := path.Join(dir, f.opt.Encoding.ToStandardName(e.PlainName)) out = append(out, fs.NewDir(remote, e.ModificationTime)) } @@ -845,6 +856,7 @@ func (f *Fs) Remove(ctx context.Context, remote string) error { if err != nil { return err } + recent.deleted(dirID) f.dirCache.FlushDir(remote) return nil } @@ -1026,6 +1038,7 @@ func (f *Fs) DirMove(ctx context.Context, src fs.Fs, srcRemote, dstRemote string if err != nil { return err } + recent.moved(srcID, dstDirectoryID, encodedLeaf) srcFs.dirCache.FlushDir(srcRemote) return nil