From bcfdd78e7e44f58cf16d08675cb1b43449689004 Mon Sep 17 00:00:00 2001 From: Boofdev Date: Sun, 29 Mar 2026 17:19:58 +0200 Subject: [PATCH] mount: add option to show system entries --- weed/command/mount.go | 2 ++ weed/command/mount_std.go | 1 + weed/mount/meta_cache/meta_cache.go | 5 +++++ weed/mount/meta_cache/meta_cache_init.go | 2 +- weed/mount/weedfs.go | 2 ++ weed/mount/weedfs_dir_read.go | 8 ++++---- weed/mount/weedfs_dir_read_test.go | 24 +++++++++++++++++++++++- 7 files changed, 38 insertions(+), 6 deletions(-) diff --git a/weed/command/mount.go b/weed/command/mount.go index f1bacae8b..dc279a529 100644 --- a/weed/command/mount.go +++ b/weed/command/mount.go @@ -31,6 +31,7 @@ type MountOptions struct { uidMap *string gidMap *string readOnly *bool + showSystemEntries *bool debug *bool debugPort *int localSocket *string @@ -99,6 +100,7 @@ func init() { mountOptions.uidMap = cmdMount.Flag.String("map.uid", "", "map local uid to uid on filer, comma-separated :") mountOptions.gidMap = cmdMount.Flag.String("map.gid", "", "map local gid to gid on filer, comma-separated :") mountOptions.readOnly = cmdMount.Flag.Bool("readOnly", false, "read only") + mountOptions.showSystemEntries = cmdMount.Flag.Bool("showSystemEntries", false, "show filer system entries (e.g. /topics, /etc) in directory listings") mountOptions.debug = cmdMount.Flag.Bool("debug", false, "serves runtime profiling data, e.g., http://localhost:/debug/pprof/goroutine?debug=2") mountOptions.debugPort = cmdMount.Flag.Int("debug.port", 6061, "http port for debugging") mountOptions.localSocket = cmdMount.Flag.String("localSocket", "", "default to /tmp/seaweedfs-mount-.sock") diff --git a/weed/command/mount_std.go b/weed/command/mount_std.go index 331820ef4..6e1a97215 100644 --- a/weed/command/mount_std.go +++ b/weed/command/mount_std.go @@ -340,6 +340,7 @@ func RunMount(option *MountOptions, umask os.FileMode) bool { VolumeServerAccess: *mountOptions.volumeServerAccess, Cipher: cipher, UidGidMapper: uidGidMapper, + ShowSystemEntries: *option.showSystemEntries, DisableXAttr: *option.disableXAttr, IsMacOs: runtime.GOOS == "darwin", MetadataFlushSeconds: *option.metadataFlushSeconds, diff --git a/weed/mount/meta_cache/meta_cache.go b/weed/mount/meta_cache/meta_cache.go index 4925a23b6..0776984f7 100644 --- a/weed/mount/meta_cache/meta_cache.go +++ b/weed/mount/meta_cache/meta_cache.go @@ -39,6 +39,7 @@ type MetaCache struct { applyClosed bool buildingDirs map[util.FullPath]*directoryBuildState dedupRing dedupRingBuffer + includeSystemEntries bool } var errMetaCacheClosed = errors.New("metadata cache is shut down") @@ -107,6 +108,10 @@ func NewMetaCache(dbFolder string, uidGidMapper *UidGidMapper, root util.FullPat return mc } +func (mc *MetaCache) SetIncludeSystemEntries(include bool) { + mc.includeSystemEntries = include +} + func openMetaStore(dbFolder string) (*leveldb.LevelDBStore, filer.VirtualFilerStore) { os.RemoveAll(dbFolder) diff --git a/weed/mount/meta_cache/meta_cache_init.go b/weed/mount/meta_cache/meta_cache_init.go index 81aad780f..60af3481c 100644 --- a/weed/mount/meta_cache/meta_cache_init.go +++ b/weed/mount/meta_cache/meta_cache_init.go @@ -107,7 +107,7 @@ func doEnsureVisited(ctx context.Context, mc *MetaCache, client filer_pb.FilerCl var err error snapshotTsNs, err = filer_pb.ReadDirAllEntriesWithSnapshot(ctx, client, path, "", func(pbEntry *filer_pb.Entry, isLast bool) error { entry := filer.FromPbEntry(string(path), pbEntry) - if IsHiddenSystemEntry(string(path), entry.Name()) { + if !mc.includeSystemEntries && IsHiddenSystemEntry(string(path), entry.Name()) { return nil } diff --git a/weed/mount/weedfs.go b/weed/mount/weedfs.go index c5a1acef1..cb12522ec 100644 --- a/weed/mount/weedfs.go +++ b/weed/mount/weedfs.go @@ -65,6 +65,7 @@ type Option struct { VolumeServerAccess string // how to access volume servers Cipher bool // whether encrypt data on volume server UidGidMapper *meta_cache.UidGidMapper + ShowSystemEntries bool // Periodic metadata flush interval in seconds (0 to disable) // This protects chunks from being purged by volume.fsck for long-running writes @@ -233,6 +234,7 @@ func NewSeaweedFileSystem(option *Option) *WFS { wfs.markDirectoryReadThrough(dirPath) } }) + wfs.metaCache.SetIncludeSystemEntries(option.ShowSystemEntries) grace.OnInterrupt(func() { // grace calls os.Exit(0) after all hooks, so WaitForAsyncFlush // after server.Serve() would never execute. Drain here first. diff --git a/weed/mount/weedfs_dir_read.go b/weed/mount/weedfs_dir_read.go index 9488f9aff..9fc342b64 100644 --- a/weed/mount/weedfs_dir_read.go +++ b/weed/mount/weedfs_dir_read.go @@ -302,7 +302,7 @@ func (wfs *WFS) readDirectoryDirect(input *fuse.ReadIn, out *fuse.DirEntryList, if input.Offset >= dh.entryStreamOffset { if len(dh.entryStream) == 0 && input.Offset > dh.entryStreamOffset { skipCount := uint32(input.Offset-dh.entryStreamOffset) + batchSize - entries, snapshotTs, err := loadDirectoryEntriesDirect(context.Background(), wfs, wfs.option.UidGidMapper, dirPath, "", false, skipCount, dh.snapshotTsNs) + entries, snapshotTs, err := loadDirectoryEntriesDirect(context.Background(), wfs, wfs.option.UidGidMapper, dirPath, "", false, skipCount, dh.snapshotTsNs, wfs.option.ShowSystemEntries) if err != nil { glog.Errorf("list filer directory: %v", err) return fuse.EIO @@ -331,7 +331,7 @@ func (wfs *WFS) readDirectoryDirect(input *fuse.ReadIn, out *fuse.DirEntryList, } } - entries, snapshotTs, err := loadDirectoryEntriesDirect(context.Background(), wfs, wfs.option.UidGidMapper, dirPath, lastEntryName, false, batchSize, dh.snapshotTsNs) + entries, snapshotTs, err := loadDirectoryEntriesDirect(context.Background(), wfs, wfs.option.UidGidMapper, dirPath, lastEntryName, false, batchSize, dh.snapshotTsNs, wfs.option.ShowSystemEntries) if err != nil { glog.Errorf("list filer directory: %v", err) return fuse.EIO @@ -360,13 +360,13 @@ func (wfs *WFS) readDirectoryDirect(input *fuse.ReadIn, out *fuse.DirEntryList, return fuse.OK } -func loadDirectoryEntriesDirect(ctx context.Context, client filer_pb.FilerClient, uidGidMapper *meta_cache.UidGidMapper, dirPath util.FullPath, startFileName string, includeStart bool, limit uint32, snapshotTsNs int64) ([]*filer.Entry, int64, error) { +func loadDirectoryEntriesDirect(ctx context.Context, client filer_pb.FilerClient, uidGidMapper *meta_cache.UidGidMapper, dirPath util.FullPath, startFileName string, includeStart bool, limit uint32, snapshotTsNs int64, showSystemEntries bool) ([]*filer.Entry, int64, error) { entries := make([]*filer.Entry, 0, limit) var actualSnapshotTsNs int64 err := client.WithFilerClient(false, func(sc filer_pb.SeaweedFilerClient) error { var innerErr error actualSnapshotTsNs, innerErr = filer_pb.DoSeaweedListWithSnapshot(ctx, sc, dirPath, "", func(entry *filer_pb.Entry, isLast bool) error { - if meta_cache.IsHiddenSystemEntry(string(dirPath), entry.Name) { + if !showSystemEntries && meta_cache.IsHiddenSystemEntry(string(dirPath), entry.Name) { return nil } if uidGidMapper != nil && entry.Attributes != nil { diff --git a/weed/mount/weedfs_dir_read_test.go b/weed/mount/weedfs_dir_read_test.go index e8e8e7d79..b2c792da0 100644 --- a/weed/mount/weedfs_dir_read_test.go +++ b/weed/mount/weedfs_dir_read_test.go @@ -84,7 +84,7 @@ func TestLoadDirectoryEntriesDirectFiltersHiddenEntriesAndMapsIds(t *testing.T) }, } - entries, _, err := loadDirectoryEntriesDirect(context.Background(), client, mapper, util.FullPath("/"), "", false, 10, 0) + entries, _, err := loadDirectoryEntriesDirect(context.Background(), client, mapper, util.FullPath("/"), "", false, 10, 0, false) if err != nil { t.Fatalf("loadDirectoryEntriesDirect: %v", err) } @@ -98,3 +98,25 @@ func TestLoadDirectoryEntriesDirectFiltersHiddenEntriesAndMapsIds(t *testing.T) t.Fatalf("mapped uid/gid = %d/%d, want 10/20", entries[0].Attr.Uid, entries[0].Attr.Gid) } } + +func TestLoadDirectoryEntriesDirectShowsSystemEntriesWhenEnabled(t *testing.T) { + client := &directoryFilerAccessor{ + client: &directoryListClient{ + responses: []*filer_pb.ListEntriesResponse{ + {Entry: &filer_pb.Entry{Name: "topics"}}, + {Entry: &filer_pb.Entry{Name: "visible"}}, + }, + }, + } + + entries, _, err := loadDirectoryEntriesDirect(context.Background(), client, nil, util.FullPath("/"), "", false, 10, 0, true) + if err != nil { + t.Fatalf("loadDirectoryEntriesDirect: %v", err) + } + if got := len(entries); got != 2 { + t.Fatalf("entry count = %d, want 2", got) + } + if entries[0].Name() != "topics" || entries[1].Name() != "visible" { + t.Fatalf("entry names = %q, %q, want topics, visible", entries[0].Name(), entries[1].Name()) + } +}