ZDDC/zddc/internal/listing/listing.go
ZDDC 89c5ec064d feat(zddc-server): hide _-prefixed entries from listings (e.g. _template)
Listings now filter both '.' and '_' prefixes:

- '.' entries: excluded from listings AND 404 on direct HTTP access
  (existing behavior). For invisible side-state like .devshell.
- '_' entries: excluded from listings only — direct URL access still
  works. For operator scaffolding like install.zip's _template/
  directory of bootstrap stubs that should be reachable but should
  not appear in the project picker.

Filter applied at both listing entry points: ServeProjectList (the
project picker JSON at GET / Accept: application/json) and the generic
listing/FromDirEntries (used by ServeDirectory for sub-directory
browse listings).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 16:56:47 -05:00

50 lines
1.3 KiB
Go

package listing
import (
"net/url"
"os"
)
// FromDirEntries converts os.DirEntry slice to []FileInfo.
// baseURL is the URL prefix for this directory (must end with "/").
// Entries starting with "." or "_" are excluded (see filter below).
func FromDirEntries(entries []os.DirEntry, baseURL string) ([]FileInfo, error) {
var result []FileInfo
for _, entry := range entries {
name := entry.Name()
// Skip hidden entries. '.' and '_' are both reserved prefixes:
// '.' marks system/internal state (.zddc files, .archive virtual
// path, .admin debug page, dev-shell home dirs); '_' marks operator
// scaffolding like install.zip's _template/ directory that's
// reachable by direct URL but should not appear in browse listings.
if len(name) == 0 || name[0] == '.' || name[0] == '_' {
continue
}
info, err := entry.Info()
if err != nil {
continue
}
isDir := entry.IsDir()
entryName := name
entryURL := baseURL + url.PathEscape(name)
if isDir {
entryName = name + "/"
entryURL = baseURL + url.PathEscape(name) + "/"
}
fi := FileInfo{
Name: entryName,
Size: info.Size(),
URL: entryURL,
ModTime: info.ModTime(),
Mode: uint32(info.Mode()),
IsDir: isDir,
IsSymlink: false,
}
result = append(result, fi)
}
return result, nil
}