From 2f3895fa3cd331f4a7b3f7180a89f1a3a286b39a Mon Sep 17 00:00:00 2001 From: maximilize <3752128+maximilize@users.noreply.github.com> Date: Tue, 21 Jul 2026 08:31:57 +0000 Subject: [PATCH] archive/squashfs: fix reading images with no fragment or xattr table Bump go-diskfs to v1.9.4, which contains diskfs/go-diskfs#413 handling squashfs images that have no fragment table or no xattr table. On v1.9.3 these images fail to list at all (ReadDir errors, or a nil xattr-table dereference inside the library). Adapt the backend to the v1.9.4 io/fs API: ReadDir now returns io/fs.DirEntry (metadata via DirEntry.Info), and files are opened via FileSystem.OpenFile instead of the removed FileStat.Open. The path conversion added in c10eb47 (toIOFS) is reused. Add a regression test with two committed fixtures built from trivial placeholder content: an empty directory (no fragment table) and a small tree whose superblock has the NO_XATTRS flag set while inodes still carry an xattr index. Fixes #9004 --- backend/archive/archive_internal_test.go | 58 +++++++++++++++++++++++ backend/archive/squashfs/squashfs.go | 47 +++++++++--------- backend/archive/squashfs/testdata/1.sqfs | Bin 0 -> 4096 bytes backend/archive/squashfs/testdata/2.sqfs | Bin 0 -> 4096 bytes go.mod | 2 +- go.sum | 4 +- 6 files changed, 83 insertions(+), 28 deletions(-) create mode 100644 backend/archive/squashfs/testdata/1.sqfs create mode 100644 backend/archive/squashfs/testdata/2.sqfs diff --git a/backend/archive/archive_internal_test.go b/backend/archive/archive_internal_test.go index ccbd04ff2..0866b7dec 100644 --- a/backend/archive/archive_internal_test.go +++ b/backend/archive/archive_internal_test.go @@ -6,6 +6,7 @@ import ( "bytes" "context" "fmt" + "io" "os" "os/exec" "path" @@ -219,3 +220,60 @@ func TestArchiveSquashfs(t *testing.T) { run(t, "mksquashfs", input, output) }) } + +// TestArchiveSquashfsIssue9004 lists and reads squashfs images that exercise +// two layouts go-diskfs used to choke on (fixed in go-diskfs v1.9.4): +// +// - 1.sqfs: a single empty directory, so the image has no fragment table +// (its fragment-table start holds the "not present" sentinel). +// - 2.sqfs: a small tree whose superblock has the NO_XATTRS flag set while +// inodes still carry a (non-sentinel) xattr index - the shape squashfs- +// tools-ng can emit. Built by packing a two-file tree with xattrs via +// `gensquashfs -x`, then setting the NO_XATTRS superblock flag; the tree +// content is trivial placeholder data. +// +// Both images used to fail to list. Regression test for #9004. +func TestArchiveSquashfsIssue9004(t *testing.T) { + fstest.Initialise() + ctx := context.Background() + + testdata, err := filepath.Abs(filepath.Join("squashfs", "testdata")) + require.NoError(t, err) + + archiveFor := func(t *testing.T, name string) fs.Fs { + f, err := cache.Get(ctx, ":archive:"+filepath.Join(testdata, name)) + require.NoError(t, err) + return f + } + + t.Run("EmptyDir", func(t *testing.T) { + // 1.sqfs is a single empty directory - it must list without error. + entries, err := archiveFor(t, "1.sqfs").List(ctx, "") + require.NoError(t, err) + assert.Equal(t, 0, len(entries)) + }) + + t.Run("NoXattrTree", func(t *testing.T) { + f := archiveFor(t, "2.sqfs") + entries, err := f.List(ctx, "") + require.NoError(t, err) + names := make([]string, 0, len(entries)) + for _, e := range entries { + names = append(names, path.Base(e.Remote())) + } + assert.Contains(t, names, "alpha") + assert.Contains(t, names, "beta") + + // A file in the tree must be readable with its real content. + obj, err := f.NewObject(ctx, "beta/sample.xml") + require.NoError(t, err) + assert.Greater(t, obj.Size(), int64(0)) + rc, err := obj.Open(ctx) + require.NoError(t, err) + data, err := io.ReadAll(rc) + require.NoError(t, err) + require.NoError(t, rc.Close()) + assert.Equal(t, int(obj.Size()), len(data)) + assert.True(t, bytes.HasPrefix(data, []byte("o|6eK|TO=#jUd4&c>hPQAFU<{Bw z%upRH4IlNIJpf4n!E7jf0!l9ci!v~XLHWH<`acw8 zq~_%0E2I_W=PD%T6l5fF+1OX)<|ve<78Pga=h-S5>KQ26+i}?x<>!~!6({BvFS?Vybl=8GZ@D*urvtUh|QI6 zSG`~*wZNG1fsp&3kHK}jYWdQlgf90PWiF_CTzzPp=ZAwzE&uE5HE%*hEfdMU<|0bQED^