Document every public function; fix a real gap the audit found
Cross-checked every function declared in include/packfs.h against nm -D libpackfs.so.0 as the starting point for a full documentation pass, per the request to document literally everything rather than just the parts already covered. That check found a genuine bug, not just a documentation gap: backend_pack_new was declared in the public header and named in CLAUDE.md's architecture map, but never implemented in src/pack.c — any caller would fail at link time. Implemented it as a standalone, read-only `pack` Backend (every mutating call returns VFS_ERR_PERM, consistent with concept.md Section 2.1 listing `pack` as its own backend kind distinct from the overlay), covered it with a new test case, and verified it under -fsanitize=undefined per CLAUDE.md's sanitizer rule. Added a doc comment to every previously-undocumented function and struct field in packfs.h and internal.h (vfs_open/read/write/close/ stat/readdir/mkdir/unlink/rename, every upper_* structural/content function, pfs_dir_*, pfs_fnv1a64, PackIndexEntry/Pack fields). Updated README and CLAUDE.md to mention backend_pack_new and to stop gesturing at zip/tar as though import/export exists. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UqJpkdJ6Njnt1pw3CbghzB
This commit is contained in:
+74
-3
@@ -47,27 +47,39 @@ typedef enum {
|
||||
VFS_KIND_DIR = 1
|
||||
} VfsEntryKind;
|
||||
|
||||
/* Result of vfs_stat. For a directory, `size` is always 0 (directories
|
||||
* carry no byte content) and `mtime` is 0 for one that exists only
|
||||
* implicitly via a child's path (Section 9.3) rather than an explicit
|
||||
* directory-marker entry. */
|
||||
typedef struct VfsStat {
|
||||
pfs_usize size;
|
||||
int64_t mtime; /* seconds since epoch */
|
||||
VfsEntryKind kind;
|
||||
} VfsStat;
|
||||
|
||||
/* One child of a directory, as populated by vfs_readdir. `name` is the
|
||||
* final path component only (not the full path), NUL-terminated. */
|
||||
typedef struct VfsDirEntry {
|
||||
char name[256];
|
||||
VfsEntryKind kind;
|
||||
} VfsDirEntry;
|
||||
|
||||
/* Result of vfs_readdir: `count` entries at `entries`, owned by the
|
||||
* caller until passed to vfs_dir_free. A freshly zeroed VfsDir
|
||||
* (`{0}`/`memset`) is always safe to pass to vfs_dir_free even if
|
||||
* vfs_readdir was never called on it or returned an error. */
|
||||
typedef struct VfsDir {
|
||||
VfsDirEntry *entries;
|
||||
pfs_usize count;
|
||||
} VfsDir;
|
||||
|
||||
/* Flags for vfs_open, bitwise-OR'd. VFS_O_RDONLY is 0, i.e. the absence
|
||||
* of VFS_O_WRONLY/VFS_O_RDWR, matching POSIX's convention. */
|
||||
#define VFS_O_RDONLY 0x00
|
||||
#define VFS_O_WRONLY 0x01
|
||||
#define VFS_O_RDWR 0x02
|
||||
#define VFS_O_CREAT 0x04
|
||||
#define VFS_O_TRUNC 0x08
|
||||
#define VFS_O_CREAT 0x04 /* create the file if it does not already exist */
|
||||
#define VFS_O_TRUNC 0x08 /* reset an existing file's content to empty */
|
||||
|
||||
/* --- VFS lifecycle -------------------------------------------------- */
|
||||
|
||||
@@ -87,7 +99,14 @@ Backend *backend_mem_new(void);
|
||||
/* dir: capability-scoped host directory, containment per Section 6. */
|
||||
Backend *backend_dir_new(const char *host_path, int *err);
|
||||
|
||||
/* pack: read-only image loaded and validated per Section 7. */
|
||||
/*
|
||||
* pack: a shipped tree in one file, read-only, loaded and validated per
|
||||
* Section 7 (Section 2.1, 3.1). Every mutating operation on a Backend
|
||||
* returned by this constructor (open with a write flag, mkdir, unlink,
|
||||
* rename, sync) returns VFS_ERR_PERM rather than being silently absorbed.
|
||||
* To make a pack writable, wrap it in an overlay via backend_overlay_new
|
||||
* instead of mounting it directly.
|
||||
*/
|
||||
Backend *backend_pack_new(const char *pack_path, int *err);
|
||||
|
||||
/*
|
||||
@@ -115,21 +134,73 @@ void backend_free(Backend *b);
|
||||
* observed mid-change by a concurrent path resolution.
|
||||
*/
|
||||
|
||||
/* Mounts `b` at `prefix` (longest-prefix match resolves overlapping
|
||||
* mounts, Section 2.2). Returns VFS_ERR_INVAL if `prefix` fails
|
||||
* virtual-namespace canonicalization (Section 6.1), VFS_ERR_EXIST if a
|
||||
* mount already exists at exactly this prefix, else VFS_OK. */
|
||||
int vfs_mount(Vfs *v, const char *prefix, Backend *b);
|
||||
|
||||
/* Detaches the backend mounted at exactly `prefix`. Returns
|
||||
* VFS_ERR_NOMOUNT if nothing is mounted there. The detached Backend is
|
||||
* not freed — call backend_free explicitly once no other thread can
|
||||
* still be resolving a path through it. */
|
||||
int vfs_unmount(Vfs *v, const char *prefix);
|
||||
|
||||
/* --- File operations -------------------------------------------------- */
|
||||
|
||||
/* Opens `path` per the resolved backend's semantics. VFS_O_CREAT creates
|
||||
* a new file if none exists; VFS_O_TRUNC resets an existing file's
|
||||
* content to empty. Returns NULL and sets *err on failure (e.g.
|
||||
* VFS_ERR_NOENT if the path doesn't exist and VFS_O_CREAT wasn't given,
|
||||
* VFS_ERR_ISDIR if the path names a directory, VFS_ERR_PERM if the
|
||||
* backend or the specific path is read-only). */
|
||||
VfsFile *vfs_open(Vfs *v, const char *path, int flags, int *err);
|
||||
|
||||
/* Reads up to `n` bytes from the file's current position into `buf`,
|
||||
* advancing that position by the number of bytes actually read. Returns
|
||||
* the byte count (0 at end of file), or a negative VfsStatus on error. */
|
||||
pfs_isize vfs_read(VfsFile *f, void *buf, pfs_usize n);
|
||||
|
||||
/* Writes `n` bytes from `buf` at the file's current position, advancing
|
||||
* that position by the number of bytes actually written; a write past
|
||||
* the current end of the file extends it. Returns the byte count
|
||||
* written, or a negative VfsStatus on error (e.g. VFS_ERR_PERM for a
|
||||
* file opened read-only or served from a read-only backend). */
|
||||
pfs_isize vfs_write(VfsFile *f, const void *buf, pfs_usize n);
|
||||
|
||||
/* Closes a file handle from vfs_open, releasing every resource it held.
|
||||
* `f` must not be used again afterward. Always returns VFS_OK. */
|
||||
int vfs_close(VfsFile *f);
|
||||
|
||||
/* Fills `out` with `path`'s size, kind, and mtime. Returns VFS_ERR_NOENT
|
||||
* if nothing exists at that path in the resolved backend. */
|
||||
int vfs_stat(Vfs *v, const char *path, VfsStat *out);
|
||||
|
||||
/* Lists the immediate children of the directory at `path` into `out`
|
||||
* (caller-owned until passed to vfs_dir_free). Returns VFS_ERR_NOENT if
|
||||
* `path` doesn't exist, VFS_ERR_NOTDIR if it names a file. */
|
||||
int vfs_readdir(Vfs *v, const char *path, VfsDir *out);
|
||||
|
||||
/* Frees the entries array a prior vfs_readdir populated into `*d` and
|
||||
* zeroes it; safe to call on an already-freed or zeroed VfsDir. */
|
||||
void vfs_dir_free(VfsDir *d);
|
||||
|
||||
/* Creates an empty directory at `path` (Section 9.3: this writes an
|
||||
* explicit, compaction-surviving marker, since an empty directory has no
|
||||
* file beneath it to imply its existence). Returns VFS_ERR_EXIST if
|
||||
* `path` already names something. */
|
||||
int vfs_mkdir(Vfs *v, const char *path);
|
||||
|
||||
/* Removes the file or empty directory at `path`. Returns VFS_ERR_NOENT
|
||||
* if nothing exists there, VFS_ERR_NOTEMPTY for a non-empty directory,
|
||||
* VFS_ERR_PERM if the resolved backend is read-only. Against an overlay,
|
||||
* removing a path that exists in the read-only lower pack writes a
|
||||
* whiteout rather than failing (Section 4.2). */
|
||||
int vfs_unlink(Vfs *v, const char *path);
|
||||
|
||||
/* Moves the entry at `from` to `to` within the same mount; both paths
|
||||
* must resolve to the same backend (VFS_ERR_INVAL otherwise — v0 does
|
||||
* not support a cross-mount rename). */
|
||||
int vfs_rename(Vfs *v, const char *from, const char *to);
|
||||
|
||||
/*
|
||||
|
||||
Reference in New Issue
Block a user