You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@iceberg.apache.org by ze...@apache.org on 2026/06/24 20:16:30 UTC

(iceberg-go) branch main updated: fix(io): keep MemFS WalkDir within root (#1302)

This is an automated email from the ASF dual-hosted git repository.

zeroshade pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/iceberg-go.git


The following commit(s) were added to refs/heads/main by this push:
     new 59265455 fix(io): keep MemFS WalkDir within root (#1302)
59265455 is described below

commit 59265455ab65917d653821524091fee763d712e9
Author: Minh Vu <vu...@gmail.com>
AuthorDate: Wed Jun 24 22:16:24 2026 +0200

    fix(io): keep MemFS WalkDir within root (#1302)
    
    MemFS.WalkDir matched roots by raw string prefix, so walking a path like .../table also included sibling keys such as table2 and table_backup. Match on path boundaries instead and normalize trailing slashes on the walk root, with regression coverage for sibling prefixes.
---
 io/mem.go      |  7 ++++++-
 io/mem_test.go | 33 +++++++++++++++++++++++++++++++++
 2 files changed, 39 insertions(+), 1 deletion(-)

diff --git a/io/mem.go b/io/mem.go
index 217da242..f0965eb4 100644
--- a/io/mem.go
+++ b/io/mem.go
@@ -104,8 +104,9 @@ func (m *MemFS) WalkDir(root string, fn fs.WalkDirFunc) error {
 	m.mu.RLock()
 	defer m.mu.RUnlock()
 
+	root = strings.TrimRight(root, "/")
 	for key, data := range m.files {
-		if !strings.HasPrefix(key, root) {
+		if !memPathInRoot(key, root) {
 			continue
 		}
 		info := &memFileInfo{name: filepath.Base(key), size: int64(len(data))}
@@ -117,6 +118,10 @@ func (m *MemFS) WalkDir(root string, fn fs.WalkDirFunc) error {
 	return nil
 }
 
+func memPathInRoot(path, root string) bool {
+	return root == "" || path == root || strings.HasPrefix(path, root+"/")
+}
+
 type memFile struct {
 	data []byte
 	name string
diff --git a/io/mem_test.go b/io/mem_test.go
index c064c49c..97d3b536 100644
--- a/io/mem_test.go
+++ b/io/mem_test.go
@@ -159,3 +159,36 @@ func TestMemIO_WalkDir(t *testing.T) {
 		"mem://walkdir-bucket/a/2.txt",
 	}, walked)
 }
+
+func TestMemIO_WalkDirDoesNotIncludeSiblingPrefixes(t *testing.T) {
+	ctx := context.Background()
+
+	memIO, err := icebergio.LoadFS(ctx, map[string]string{}, "mem://walkdir-boundary-bucket/")
+	require.NoError(t, err)
+
+	listable := memIO.(icebergio.ListableIO)
+	writeIO := memIO.(icebergio.WriteFileIO)
+
+	require.NoError(t, writeIO.WriteFile("mem://walkdir-boundary-bucket/table/data.parquet", []byte("table")))
+	require.NoError(t, writeIO.WriteFile("mem://walkdir-boundary-bucket/table2/data.parquet", []byte("table2")))
+	require.NoError(t, writeIO.WriteFile("mem://walkdir-boundary-bucket/table_backup/data.parquet", []byte("backup")))
+
+	for _, root := range []string{
+		"mem://walkdir-boundary-bucket/table",
+		"mem://walkdir-boundary-bucket/table/",
+	} {
+		t.Run(root, func(t *testing.T) {
+			var walked []string
+			err := listable.WalkDir(root, func(path string, _ fs.DirEntry, err error) error {
+				require.NoError(t, err)
+				walked = append(walked, path)
+
+				return nil
+			})
+			require.NoError(t, err)
+			assert.ElementsMatch(t, []string{
+				"mem://walkdir-boundary-bucket/table/data.parquet",
+			}, walked)
+		})
+	}
+}