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 <noreply@anthropic.com>
This commit is contained in:
Levi Neely 2026-03-21 21:34:15 +01:00
parent 8a6c90f160
commit 6dd103482b
2 changed files with 18 additions and 7 deletions

View File

@ -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

View File

@ -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 {