docs: design recycle-backed salvage metadata store
This commit is contained in:
222
tests/salvage/SALVAGE_BACKEND_DESIGN.md
Normal file
222
tests/salvage/SALVAGE_BACKEND_DESIGN.md
Normal file
@@ -0,0 +1,222 @@
|
||||
# mars_nwe salvage backend design
|
||||
|
||||
This document describes the planned mars_nwe salvage backend for NetWare 3.x
|
||||
compatibility. The backend should live in `src/nwsalvage.c` with public
|
||||
interfaces in `include/nwsalvage.h`.
|
||||
|
||||
The goal is to implement NetWare-style salvage without relying on filesystem
|
||||
undelete features. mars_nwe sees the delete while the file still exists, so it
|
||||
can move the file to a recycle repository and write the metadata required for
|
||||
NetWare scan/recover/purge calls.
|
||||
|
||||
## Directory layout
|
||||
|
||||
The file payload and the mars_nwe metadata are deliberately separated.
|
||||
|
||||
```text
|
||||
<SYS>/
|
||||
.recycle/
|
||||
<user>/
|
||||
<original tree>/
|
||||
<deleted file>
|
||||
|
||||
.salvage/
|
||||
<user>/
|
||||
<original tree>/
|
||||
<deleted file>.json
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```text
|
||||
SYS/.recycle/SUPERVISOR/PUBLIC/PMDFLTS.INI
|
||||
SYS/.salvage/SUPERVISOR/PUBLIC/PMDFLTS.INI.json
|
||||
```
|
||||
|
||||
When a name collides, mars_nwe should version the recycle name in a
|
||||
Samba-like way and use the same versioned name for the sidecar JSON:
|
||||
|
||||
```text
|
||||
SYS/.recycle/SUPERVISOR/PUBLIC/PMDFLTS.~1~.INI
|
||||
SYS/.salvage/SUPERVISOR/PUBLIC/PMDFLTS.~1~.INI.json
|
||||
```
|
||||
|
||||
The `.recycle` tree contains the actual deleted file. The `.salvage` tree
|
||||
contains only mars_nwe metadata and indexes. This keeps the recycle area usable
|
||||
for administrators and compatible with Samba-style recycle setups, while
|
||||
allowing mars_nwe to keep NetWare-specific salvage state.
|
||||
|
||||
## Why not filesystem undelete
|
||||
|
||||
Linux and FreeBSD do not provide a portable, online, filesystem-independent
|
||||
undelete API that matches NetWare salvage semantics. ext-style recovery tools,
|
||||
snapshot filesystems, and forensic recovery tools do not provide the stable
|
||||
per-directory scan/recover/purge model required by the NetWare NCPs.
|
||||
|
||||
mars_nwe should therefore implement salvage as controlled server-side
|
||||
"trash-on-delete" behavior:
|
||||
|
||||
1. Delete request reaches mars_nwe.
|
||||
2. mars_nwe captures the required metadata.
|
||||
3. mars_nwe moves the file to `.recycle`.
|
||||
4. mars_nwe writes a JSON metadata record to `.salvage`.
|
||||
5. NetWare salvage NCPs operate on those metadata records.
|
||||
|
||||
## JSON metadata
|
||||
|
||||
Use one JSON file per deleted object. Do not use a single large JSON file per
|
||||
directory; per-object JSON is easier to inspect, easier to clean up, and safer
|
||||
when one record is damaged.
|
||||
|
||||
Minimal example:
|
||||
|
||||
```json
|
||||
{
|
||||
"version": 1,
|
||||
"source": "mars_nwe",
|
||||
"volume": "SYS",
|
||||
"deleted_by": "SUPERVISOR",
|
||||
"deleted_at": 1780215322,
|
||||
|
||||
"original_path": "SYS:PUBLIC/PMDFLTS.INI",
|
||||
"original_parent_entry_id": 4,
|
||||
"original_name": "PMDFLTS.INI",
|
||||
"dos_name": "PMDFLTS.INI",
|
||||
"long_name": "pmdflts.ini",
|
||||
|
||||
"recycle_relative_path": ".recycle/SUPERVISOR/PUBLIC/PMDFLTS.INI",
|
||||
"salvage_relative_path": ".salvage/SUPERVISOR/PUBLIC/PMDFLTS.INI.json",
|
||||
|
||||
"attributes": 8192,
|
||||
"size": 8161,
|
||||
"atime": 1700000000,
|
||||
"mtime": 1700000000,
|
||||
"ctime": 1700000000,
|
||||
"backup_time": 1700000000,
|
||||
|
||||
"finder_info_hex": "0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"afp_entry_id": "0x2cc1243d",
|
||||
"resource_fork_size": 0
|
||||
}
|
||||
```
|
||||
|
||||
The JSON should store paths relative to the volume root wherever possible. That
|
||||
makes the records easier to move with the volume and easier to read manually.
|
||||
|
||||
## Cleanup of stale metadata
|
||||
|
||||
Samba or an administrator may delete files from `.recycle`. mars_nwe must not
|
||||
leave stale salvage entries forever.
|
||||
|
||||
The salvage backend should include an opportunistic cleanup pass:
|
||||
|
||||
```text
|
||||
scan .salvage/**/*.json
|
||||
read recycle_relative_path
|
||||
if the .recycle file no longer exists:
|
||||
remove the JSON record
|
||||
remove empty .salvage directories where safe
|
||||
```
|
||||
|
||||
Cleanup should run at least:
|
||||
|
||||
- on server startup,
|
||||
- before `Scan Salvageable Files`,
|
||||
- before AFP `0x13` deleted-file metadata lookup,
|
||||
- optionally on a low-frequency timer later.
|
||||
|
||||
The first implementation can keep this simple and synchronous.
|
||||
|
||||
## Backend module
|
||||
|
||||
Implement the backend in:
|
||||
|
||||
```text
|
||||
src/nwsalvage.c
|
||||
include/nwsalvage.h
|
||||
```
|
||||
|
||||
Planned responsibilities:
|
||||
|
||||
- build `.recycle` and `.salvage` paths for a volume,
|
||||
- generate versioned recycle names on collision,
|
||||
- move a deleted file into `.recycle`,
|
||||
- write/read JSON records,
|
||||
- remove stale JSON when the recycle file is gone,
|
||||
- scan records by original parent directory entry,
|
||||
- recover a record by moving the recycle file back,
|
||||
- purge a record by deleting both recycle file and JSON metadata.
|
||||
|
||||
The AFP code must not implement salvage directly. AFP `0x13` should be only an
|
||||
adapter on top of `nwsalvage`.
|
||||
|
||||
## NetWare 3.x NCP scope
|
||||
|
||||
mars_nwe targets NetWare 3.x-style compatibility for this slice. The salvage
|
||||
backend should initially support the 3.x-era NCPs:
|
||||
|
||||
```text
|
||||
NCP 0x2222 / 22 / 27 Scan Salvageable Files (old)
|
||||
NCP 0x2222 / 87 / 16 Scan Salvageable Files
|
||||
NCP 0x2222 / 87 / 17 Recover Salvageable File
|
||||
NCP 0x2222 / 87 / 18 Purge Salvageable File
|
||||
```
|
||||
|
||||
Later NetWare 4.11+ list variants and UTF-8 extensions are out of scope for the
|
||||
initial mars_nwe 3.x salvage slice:
|
||||
|
||||
```text
|
||||
NCP 0x2222 / 87 / 41 Scan Salvageable File List
|
||||
NCP 0x2222 / 87 / 42 Purge Salvageable File List
|
||||
NCP 0x2222 / 89 / 16 UTF-8 / extended Scan Salvageable Files
|
||||
```
|
||||
|
||||
## AFP integration
|
||||
|
||||
AFP `0x13 Get Macintosh Info On Deleted Files` remains unsupported until the
|
||||
mars_nwe salvage backend exists.
|
||||
|
||||
After the backend is available, AFP `0x13` should:
|
||||
|
||||
1. validate the request volume and deleted DOS directory entry,
|
||||
2. resolve the deleted entry through `nwsalvage`,
|
||||
3. return FinderInfo from the JSON record when available,
|
||||
4. return ProDOS information as zeroes unless mars_nwe later gains a ProDOS
|
||||
metadata store,
|
||||
5. return resource fork size as zero while resource forks remain unsupported,
|
||||
6. return the deleted filename from the salvage record.
|
||||
|
||||
AFP must not scan `.recycle` or `.salvage` itself.
|
||||
|
||||
## Test plan
|
||||
|
||||
Create a separate test group first:
|
||||
|
||||
```text
|
||||
tests/salvage/
|
||||
```
|
||||
|
||||
Initial tests should cover the backend without AFP:
|
||||
|
||||
- create sample file,
|
||||
- delete through the salvage helper path,
|
||||
- verify the file is moved to `.recycle`,
|
||||
- verify the JSON exists in `.salvage`,
|
||||
- verify cleanup removes stale JSON when the recycle file is deleted,
|
||||
- verify recover restores the file,
|
||||
- verify purge removes both file and JSON.
|
||||
|
||||
Only after those tests are stable should `tests/afp` gain an AFP `0x13` smoke.
|
||||
|
||||
## Configuration direction
|
||||
|
||||
The first implementation may use fixed per-volume defaults:
|
||||
|
||||
```text
|
||||
recycle repository: .recycle
|
||||
salvage metadata: .salvage
|
||||
```
|
||||
|
||||
Later configuration can expose those names if needed. The default should remain
|
||||
compatible with a Samba-style recycle layout and should keep `.salvage` as
|
||||
metadata-only state.
|
||||
Reference in New Issue
Block a user