From 6dd103482bc82c112703fb709e4db6332258fd3a Mon Sep 17 00:00:00 2001 From: Levi Neely Date: Sat, 21 Mar 2026 21:34:15 +0100 Subject: [PATCH] Fix n/ directory listing when note count exceeds 9P read buffer readDir was slicing the serialized dir entry bytes at the raw byte boundary, splitting entries mid-stream. The plan9 client's dirUnpack stops on a truncated entry, so 9pfuse received nothing usable. Fix readDir to return only complete entries per read, as required by the 9P spec. Also warn-and-skip on ExtractMetadata errors in LoadAll instead of aborting the entire directory walk. Co-Authored-By: Claude Sonnet 4.6 --- internal/disk/loader.go | 3 ++- internal/p9/server/server.go | 22 ++++++++++++++++------ 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/internal/disk/loader.go b/internal/disk/loader.go index 78863fd..bc9d9e7 100644 --- a/internal/disk/loader.go +++ b/internal/disk/loader.go @@ -165,7 +165,8 @@ func LoadAll(dir string) (metadata.Results, error) { note, err := ExtractMetadata(path) if err != nil { - return err + log.Printf("warning: skipping %s: %v", path, err) + return nil } // Only include files with valid identifiers diff --git a/internal/p9/server/server.go b/internal/p9/server/server.go index 41da298..53124b5 100644 --- a/internal/p9/server/server.go +++ b/internal/p9/server/server.go @@ -931,17 +931,27 @@ func (s *server) readDir(path string, offset int64, count uint32) []byte { allData = append(allData, stat...) } - // Return slice starting from offset + // Return only complete entries starting at offset. + // 9P requires that directory reads never split an entry across reads. if offset >= int64(len(allData)) { return []byte{} } - end := offset + int64(count) - if end > int64(len(allData)) { - end = int64(len(allData)) + remaining := allData[offset:] + var result []byte + for len(remaining) >= 2 { + entrySize := int(remaining[0]) | int(remaining[1])<<8 + totalSize := entrySize + 2 + if len(remaining) < totalSize { + break + } + if len(result)+totalSize > int(count) { + break + } + result = append(result, remaining[:totalSize]...) + remaining = remaining[totalSize:] } - - return allData[offset:end] + return result } func (s *server) pathToDir(path string, qid plan9.Qid) plan9.Dir {