archive: fix corrupt listings when listing a zip directory more than once

The zip archiver handed out its cached directory tree directly. Any
caller which filters a listing in place (as the core listing code
does) altered the cache, so later listings of the same directory could
be corrupted.

Return a copy of the cached listing instead.
This commit is contained in:
Nick Craig-Wood
2026-09-05 12:14:46 +01:00
parent 6cdd0ea761
commit 68eab60564
2 changed files with 30 additions and 1 deletions
+3 -1
View File
@@ -9,6 +9,7 @@ import (
"io" "io"
"os" "os"
"path" "path"
"slices"
"strings" "strings"
"time" "time"
@@ -217,7 +218,8 @@ func (f *Fs) List(ctx context.Context, dir string) (entries fs.DirEntries, err e
return nil, fs.ErrorDirNotFound return nil, fs.ErrorDirNotFound
} }
fs.Debugf(f, "dir=%q, entries=%v", dir, entries) fs.Debugf(f, "dir=%q, entries=%v", dir, entries)
return entries, nil // Return a copy as callers may filter the listing in place
return slices.Clone(entries), nil
} }
// NewObject finds the Object at remote. // NewObject finds the Object at remote.
+27
View File
@@ -128,3 +128,30 @@ func TestReadZipRootNamedEntry(t *testing.T) {
remotes := allRemotes(t, f) remotes := allRemotes(t, f)
assert.Equal(t, []string{"good.txt"}, remotes) assert.Equal(t, []string{"good.txt"}, remotes)
} }
// Listings are served from a cache which must survive callers
// filtering the returned slice in place, as fs/list does.
func TestListCacheNotAliased(t *testing.T) {
ctx := context.Background()
dir := t.TempDir()
name := writeZip(t, dir, "test.zip", "a.txt", "b.txt", "c.txt")
localFs, err := cache.Get(ctx, dir)
require.NoError(t, err)
f, err := New(ctx, localFs, name, "", "")
require.NoError(t, err)
entries, err := f.List(ctx, "")
require.NoError(t, err)
require.Len(t, entries, 3)
// Compact in place, dropping the first entry
copy(entries, entries[1:])
entries, err = f.List(ctx, "")
require.NoError(t, err)
var remotes []string
for _, entry := range entries {
remotes = append(remotes, entry.Remote())
}
assert.Equal(t, []string{"a.txt", "b.txt", "c.txt"}, remotes)
}