Drop mimeType and ctime from the manifest format (closes #235)
check / check (push) Waiting to run

Nothing goes in the 1.0 manifest that 1.0 does not read or write, and
mfer never wrote either field. mf.proto now reserves the numbers 301 and
303 and both names in MFFilePath, and mf.pb.go is regenerated. The
decoded-size check counts only file entries, hashes and timestamps, and
counts a file entry, 16 bytes smaller without the two fields, at 160
bytes. export prints no ctime, and FileEntry loses the Ctime nothing
set. FORMAT.md and the README no longer describe either field.

The test of entries that decode too large gives each entry a second,
empty hash: an entry with one hash and a modification time can no
longer reach 8 times its size.

Model: opus-5-5
This commit is contained in:
2026-10-19 18:40:56 +00:00
committed by sneak
parent 033d8be5be
commit b9583fea27
13 changed files with 159 additions and 113 deletions
+17 -16
View File
@@ -9,8 +9,11 @@ including their paths, sizes, and cryptographic checksums. It supports optional
OpenPGP signatures for integrity verification and optional timestamps and file
permissions for metadata preservation.
Nothing goes in the 1.0 manifest that 1.0 does not read or write: no field is
reserved or kept for later use.
Nothing goes in the 1.0 manifest that 1.0 does not read or write, and no field
is kept for later use. [`mfer/mf.proto`](../mfer/mf.proto) reserves the field
numbers 301 and 303 and the names `mimeType` and `ctime` in `MFFilePath`, so
that a later version cannot reuse them by accident. No field uses them, and
readers ignore them like any field they do not know.
## File Structure
@@ -58,11 +61,11 @@ enforce a decompression size limit to prevent decompression bombs. The reference
implementation limits decompressed size to 256 MiB. It writes zstd frames with a
window of at most 8 MiB, the largest window the zstd format recommends decoders
support, and refuses frames that ask for a larger one. It also refuses an inner
message whose file entries, hashes, timestamps and MIME types, counted at 176,
112, 64 and 16 bytes each, add up to more than 8 times its size. It refuses a
manifest file larger than 258 MiB without reading the rest of it: zstd's worst
case grows a 256 MiB inner message by 1/256 to 257 MiB, and the last MiB is room
for the signature, the signing key and the other outer fields.
message whose file entries, hashes and timestamps, counted at 160, 112 and 64
bytes each, add up to more than 8 times its size. It refuses a manifest file
larger than 258 MiB without reading the rest of it: zstd's worst case grows a
256 MiB inner message by 1/256 to 257 MiB, and the last MiB is room for the
signature, the signing key and the other outer fields.
## Inner Message (`MFFile`)
@@ -80,15 +83,13 @@ After decompressing `innerMessage`, the result is a serialized `MFFile`
Each file entry contains:
| Field | Number | Type | Description |
| ---------- | ------ | ------------------------- | ------------------------------------------------------------ |
| `path` | 1 | string | Relative file path (see Path Rules) |
| `size` | 2 | int64 | File size in bytes |
| `hashes` | 3 | repeated `MFFileChecksum` | Must include exactly one SHA-256 multihash (see Hash Format) |
| `mimeType` | 301 | string (optional) | MIME type |
| `mtime` | 302 | Timestamp (optional) | Modification time |
| `ctime` | 303 | Timestamp (optional) | Change time (inode metadata change) |
| `mode` | 304 | uint32 | Permission bits (see File Mode) |
| Field | Number | Type | Description |
| -------- | ------ | ------------------------- | ------------------------------------------------------------ |
| `path` | 1 | string | Relative file path (see Path Rules) |
| `size` | 2 | int64 | File size in bytes |
| `hashes` | 3 | repeated `MFFileChecksum` | Must include exactly one SHA-256 multihash (see Hash Format) |
| `mtime` | 302 | Timestamp (optional) | Modification time |
| `mode` | 304 | uint32 | Permission bits (see File Mode) |
## File Mode