# Changelog All notable changes to this project are documented in this file, in the style of [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). This project follows [Semantic Versioning](https://semver.org/); see `PACKFS_VERSION_STRING` in `include/packfs.h` for the authoritative current version (`packfs.pc`, generated by `make install`, is derived from it, not maintained separately). This project is pre-release (`0.x`, an initial, partial implementation of `concept.md`, not a completed one; see `README.md`'s "Status"). `v0.1.0` is tagged locally in this repository's own git history but has not been pushed to any remote — there is no public release yet, only a local one. ## [0.1.0] - 2026-09-14 ### Added - Initial implementation of `concept.md`: `vfs_*` core, `mem`/`dir`/`pack` backends, the copy-on-write overlay (copy-up, whiteouts, compaction, an append journal), path containment (`openat2`/Landlock on Linux 5.6+/5.13+, a documented weaker fallback elsewhere), and pack integrity validation. - `tests/test_*.c` covering each backend, concurrency, and randomized structural-index stress testing against an independent reference model. - `bench/bench.c` (`make bench`) and `BENCH.md`, comparing PackFS against the host filesystem across metadata operations, large sequential I/O, random-access pack reads, mount-table scaling, and concurrent workloads. - `PACKFS_VERSION_MAJOR`/`MINOR`/`PATCH`/`STRING` and `pfs_version()` for compile-time and runtime version/ABI checks. - `packfs.pc` (pkg-config), generated by `make install` from `packfs.pc.in`, version always derived from `include/packfs.h`. - `SPDX-License-Identifier: MIT` on every file under `src/` and `include/`. ### Fixed - **Bulk sequential `create`/`unlink`/`mkdir` on `mem`/`dir` was O(n²) in file count.** The index (`UpperSnapshot`) was a flat sorted array copied in full on every structural write; rewritten as a persistent treap (`src/upper.c`), reducing a structural write to the O(log n) nodes on the path to the change. See `BENCH.md`'s "Resolution" for the full before/after measurement and complexity-class confirmation. - **`pack_write`'s compaction-time exact-duplicate elimination (Section 9.2) was O(n²) in entry count, and trusted a hash match without comparing actual bytes** (a latent correctness bug: FNV-1a64 is explicitly not collision-resistant). Rewritten as an open-addressing hash table with a `memcmp` verification before ever reusing a `data_off`, fixing both at once. See `BENCH.md`'s "Resolution #2". - **`backend_pack_new` was declared in `include/packfs.h` but never implemented** — any program calling it failed at link time. Implemented as a standalone, read-only `pack` `Backend`. - The CI config's (`.gitea/workflows/ci.yml`) sanitizer-build steps never passed `-D_GNU_SOURCE` when compiling test files (only the library object files got it), which was harmless until a test included `internal.h` (needed for `pthread_rwlock_t`) and became a link failure. ### Changed - CI moved from a GitHub-Actions-convention config (`.github/workflows/`) to Gitea Actions (`.gitea/workflows/`) — this project is hosted on Gitea, not GitHub, and was never actually hosted on GitHub; only the scaffolding's starting convention changed. `SECURITY.md`, `CLAUDE.md`, `CONTRIBUTING.md`, and `README.md` updated to match. ### Documented - **`vfs.c`'s mount table (`MountSnapshot`) is O(n²) in mount count, the same pattern the file index used to have — confirmed, and deliberately left unfixed.** Mount counts are bounded by a program's own source code, not workload-driven, so they do not reach the scale that made the file index's O(n²) a real problem. See `BENCH.md`'s "Finding: mount table scaling" for the numbers and reasoning. - A ThreadSanitizer environment limitation (some sandboxes block the `personality(ADDR_NO_RANDOMIZE)` syscall TSan needs) and a related ASan/UBSan sandbox startup flake (`AddressSanitizer:DEADLYSIGNAL`), both in `CONTRIBUTING.md` and `CLAUDE.md`, with the confirming tests and the required mitigation (`timeout`-wrapped sanitizer runs).