tests: consolidate AFP and salvage markdown docs

This commit is contained in:
OpenAI
2026-06-01 14:38:37 +00:00
committed by Mario Fetka
parent 25f0bf9165
commit fa3a922700
9 changed files with 245 additions and 2143 deletions

View File

@@ -5,9 +5,9 @@ exercise outside the normal install flow.
## AFP
`tests/afp` contains the current AFP endpoint smoke suite and AFP-specific
notes. AFP deleted-file endpoint `0x13` is intentionally still unsupported
until the shared salvage backend exposes scan/recover/purge semantics.
`tests/afp` contains the current AFP endpoint smoke suite and its single AFP
README. AFP deleted-file endpoint `0x13` is implemented as a thin adapter over
the shared salvage backend and is covered by the AFP smoke suite.
## Salvage

View File

@@ -1,57 +0,0 @@
# AFP deleted-file Macintosh metadata
`AFP Get Macintosh Info On Deleted Files` is NetWare AFP subfunction `0x13`.
Keep it documented as an unsupported, salvage-backend-dependent endpoint for the
current AFP compatibility slice.
## Why this is not implemented directly
The request is not a normal path, name, or file-handle metadata query. It is
keyed by a volume number and a DOS directory entry for a deleted Macintosh
directory entry. The reply shape is also salvage-specific: Finder information,
ProDOS information, resource fork size, and the deleted file name.
That means the AFP call is an adapter on top of NetWare salvage/deleted-entry
state, not an independent AFP metadata lookup. Implementing it directly in the
AFP handler would create a parallel deleted-file path and would violate the
current rule that AFP endpoints reuse mars_nwe backend semantics.
## Required mars_nwe backend first
Before implementing AFP subfunction `0x13`, the normal NetWare salvage backend
must exist and be verified. The relevant non-AFP NCP family is:
- `NCP 0x2222 / 87 / 16` - Scan Salvageable Files
- `NCP 0x2222 / 87 / 17` - Recover Salvageable File
- `NCP 0x2222 / 87 / 18` - Purge Salvageable File
- optional legacy `NCP 0x2222 / 22 / 27` - Scan Salvageable File (old)
AFP `0x13` translates the WebSDK/NWAFP
wire request to the mars_nwe salvage entry and then append AFP-specific deleted
Macintosh metadata.
## Intended future mapping
AFP `0x13` behaves like this:
1. Validate the request volume and DOS directory entry.
2. Look up the deleted entry through the mars_nwe salvage/deleted-entry backend.
3. Return FinderInfo from the AFP metadata store when available, otherwise zeroes.
4. Return ProDOS information from the Salvage JSON snapshot (`prodos_info_hex`), which is captured from the nwatalk ProDOSInfo xattr backend.
5. Return resource fork size as zero while resource forks remain unsupported.
6. Return the deleted file name from the salvage entry, not from a live path scan.
## Current audit status
Current status for the AFP inventory and final audit:
```text
0x13 AFP Get Macintosh Info On Deleted Files
status: unsupported / final-audit item
reason: requires mars_nwe salvage/deleted-entry backend first
do not: implement a standalone AFP-local deleted-file scan
```
This keeps the AFP implementation aligned with the rest of the current design:
NetWare semantics come from mars_nwe core paths, while AFP-only metadata is kept
small and explicit.

View File

@@ -1,79 +0,0 @@
# AFP endpoint inventory before final audit
This file records the current mars_nwe AFP endpoint inventory before the final
WebSDK / Novell NWAFP header audit. The generated helper output should remain
the source of truth for fresh checks:
```sh
tests/afp/afp_endpoint_inventory.py
```
## Current endpoint coverage
| Subfn | Name | Status | Backend discipline |
| --- | --- | --- | --- |
| `0x01` | AFP Create Directory | implemented | mars_nwe path/namespace and object lifecycle |
| `0x02` | AFP Create File | implemented | mars_nwe path/namespace and object lifecycle; AFP xattr only for file entry-id metadata |
| `0x03` | AFP Delete | implemented | mars_nwe path/namespace and object lifecycle |
| `0x04` | AFP Get Entry ID From Name | implemented / validating | mars_nwe path/namespace; entry-id-relative bases are directory entry IDs only |
| `0x05` | AFP Get File Information | implemented | mars_nwe path/namespace plus mars_nwe attributes/rights; AFP xattrs only for FinderInfo / entry-id |
| `0x06` | AFP Get Entry ID From NetWare Handle | implemented | mars_nwe file-handle lookup, then AFP entry-id metadata |
| `0x07` | AFP Rename | implemented | mars_nwe path/namespace and object lifecycle; AFP entry-id metadata follows renamed files |
| `0x08` | AFP Open File Fork | implemented for data fork | mars_nwe file handles; resource fork remains unsupported |
| `0x09` | AFP Set File Information | implemented | mars_nwe attributes/archive/fileinfo/trustee; AFP xattrs only for FinderInfo / AFP-only bits |
| `0x0a` | AFP Scan File Information | implemented for path and directory entry-id starts | mars_nwe path/namespace; entry IDs must resolve to directories |
| `0x0b` | AFP Alloc Temporary Dir Handle | implemented | mars_nwe path/namespace and directory handles |
| `0x0c` | AFP Get Entry ID From Path Name | implemented / validating | mars_nwe path/namespace; AFP entry-id metadata for files |
| `0x0d` | AFP 2.0 Create Directory | implemented | mars_nwe path/namespace and object lifecycle |
| `0x0e` | AFP 2.0 Create File | implemented | mars_nwe path/namespace and object lifecycle; AFP xattr only for file entry-id metadata |
| `0x0f` | AFP 2.0 Get File Information | implemented | same backend discipline as `0x05` |
| `0x10` | AFP 2.0 Set File Information | implemented | same backend discipline as `0x09` |
| `0x11` | AFP 2.0 Scan File Information | implemented for path and directory entry-id starts | same backend discipline as `0x0a` |
| `0x12` | AFP Get DOS Name From Entry ID | implemented | mars_nwe path/namespace and AFP entry-id reverse lookup |
| `0x13` | AFP Get Macintosh Info On Deleted Files | implemented / salvage-backed | covered by afp_deleted_info_smoke |
## Backend rules for the final audit
AFP handlers must not grow independent filesystem semantics. The final audit
must verify that each endpoint continues to use the mars_nwe core backend:
- Create, delete, rename, and directory operations go through mars_nwe
path/namespace and object lifecycle helpers.
- Data-fork open/read/write/close uses mars_nwe file handles and the normal
NetWare file I/O path. AFP `0x08` opens the data fork; subsequent I/O and
close use normal NetWare handle semantics.
- Rights checks use mars_nwe trustee/effective-rights logic.
- Hidden, system, archive, timestamps, creator/modifier, and backup/archive
metadata use mars_nwe attribute/archive/fileinfo paths.
- AFP-only xattrs are limited to:
- `user.org.mars-nwe.afp.entry-id`
- `user.org.mars-nwe.afp.finder-info`
- `user.org.mars-nwe.afp.attributes` only for future AFP-only bits
- Resource forks remain unsupported and should return the documented completion
code instead of inventing a parallel storage backend.
- Deleted-file Macintosh metadata (`0x13`) is implemented on the mars_nwe
salvage backend and must not perform an AFP-local deleted-file scan.
## Resolved final-audit items
Resolved WebSDK compatibility items:
1. `0x13` is implemented as a salvage/deleted-entry backend adapter and covered
by `afp_deleted_info_smoke`.
- `0x0a` / `0x11` entry-id-only scan requests are supported when the base entry
ID resolves to a directory through mars_nwe namespace/basehandle logic.
## Final comparison checklist
When doing the final WebSDK / Novell NWAFP header pass, compare:
- AFP subfunction numbers and names.
- Request field order, sizes, and byte order.
- Reply field order, sizes, and byte order.
- Bitmap meanings for get/set/scan information calls.
- Legacy vs AFP 2.0 layout variants.
- Completion codes for unsupported resource forks, insufficient rights, bad
handles, missing entries, bad paths, and unsupported deleted-file metadata.
- Whether each implemented endpoint still routes NetWare semantics through
mars_nwe functions rather than AFP-local shortcuts.

View File

@@ -1,129 +0,0 @@
# AFP final WebSDK / Novell header audit plan
This document is the working checklist for the final AFP endpoint audit. It is
not a statement that the audit is complete. The goal is to make the final pass
repeatable and to keep the comparison focused on protocol compatibility and
mars_nwe backend discipline.
## Required reference sources
Before marking the audit complete, compare the current implementation against
all available authoritative local references:
- WebSDK AFP definitions, especially the header or documentation equivalent to
`nwafp.h`.
- Novell/NWAFP include files from the SDK tree used for the compatibility work.
- Any WebSDK request/reply examples bundled with the uploaded SDK archive.
- mars_nwe current `src/nwconn.c`.
- mars_nwe AFP helper inventory:
```sh
tests/afp/afp_endpoint_inventory.py
tests/afp/afp_endpoint_inventory.py --json
```
The final audit should record the exact source paths used, for example:
```text
WebSDK source: <path-to-websdk>/...
Novell headers: <path-to-novell-headers>/...
mars_nwe source: src/nwconn.c
audit date: YYYY-MM-DD
```
## Source greps to run
Run these in the mars_nwe tree and in the unpacked WebSDK / Novell header trees.
```sh
grep -RIn "AFP.*Get Entry ID\|Get Macintosh Info On Deleted\|Scan File Information\|Open File Fork\|Set File Information" .
grep -RIn "0x2222.*35\|function 35\|NWAFP\|nwafp" .
grep -RIn "AFP.*0x0[0-9a-fA-F]\|AFP.*0x1[0-3]" .
grep -RIn "Scan Salvageable\|Recover Salvageable\|Purge Salvageable\|Deleted" .
```
Run these in mars_nwe to verify cleanup and backend discipline:
```sh
grep -RIn "layout=websdk\|libatalk\|Netatalk\|HAVE_NETATALK\|ENABLE_NETATALK" src include tests/afp CMakeLists.txt cmake 2>/dev/null
grep -RIn "entry-id-only .*unsupported\|unsupported.*entry-id" src/nwconn.c tests/afp
grep -RIn "\bopen\s*(\|\bread\s*(\|\bwrite\s*(\|\brename\s*(\|\bunlink\s*(\|\brmdir\s*(\|\bmkdir\s*(" src/nwconn.c
```
The last grep is review material, not an automatic failure. Some direct POSIX
calls may be legitimate inside older mars_nwe core paths, but AFP endpoint code
should not bypass mars_nwe helpers for NetWare semantics.
## Endpoint comparison table
Fill this table during the final pass. `mars_nwe backend path` must name the
mars_nwe helper family used by the endpoint, not just the AFP handler.
| Subfn | WebSDK / Novell name | mars_nwe handler | Request layout OK | Reply layout OK | Completion codes OK | mars_nwe backend path OK | Notes |
| --- | --- | --- | --- | --- | --- | --- | --- |
| `0x01` | AFP Create Directory | inline AFP create directory case | TODO | TODO | TODO | TODO | |
| `0x02` | AFP Create File | inline AFP create file case | TODO | TODO | TODO | TODO | |
| `0x03` | AFP Delete | inline AFP delete case | TODO | TODO | TODO | TODO | |
| `0x04` | AFP Get Entry ID From Name | `afp_get_entry_id_from_name` | TODO | TODO | TODO | TODO | |
| `0x05` | AFP Get File Information | `afp_get_file_information` | TODO | TODO | TODO | TODO | |
| `0x06` | AFP Get Entry ID From NetWare Handle | `afp_get_entry_id_from_netware_handle` | TODO | TODO | TODO | TODO | |
| `0x07` | AFP Rename | inline AFP rename case | TODO | TODO | TODO | TODO | |
| `0x08` | AFP Open File Fork | inline AFP open file fork case | TODO | TODO | TODO | TODO | data fork only; resource fork unsupported |
| `0x09` | AFP Set File Information | inline AFP set file information case | TODO | TODO | TODO | TODO | legacy variant |
| `0x0a` | AFP Scan File Information | `afp_scan_file_information` | TODO | TODO | TODO | TODO | entry-id-only directory scan supported |
| `0x0b` | AFP Alloc Temporary Dir Handle | inline AFP alloc temporary dir handle case | TODO | TODO | TODO | TODO | |
| `0x0c` | AFP Get Entry ID From Path Name | `afp_get_entry_id_from_path_name` | TODO | TODO | TODO | TODO | |
| `0x0d` | AFP 2.0 Create Directory | inline AFP 2.0 create directory case | TODO | TODO | TODO | TODO | |
| `0x0e` | AFP 2.0 Create File | inline AFP 2.0 create file case | TODO | TODO | TODO | TODO | |
| `0x0f` | AFP 2.0 Get File Information | `afp_get_file_information` | TODO | TODO | TODO | TODO | AFP 2.0 variant |
| `0x10` | AFP 2.0 Set File Information | inline AFP 2.0 set file information case | TODO | TODO | TODO | TODO | AFP 2.0 variant |
| `0x11` | AFP 2.0 Scan File Information | `afp_scan_file_information` | TODO | TODO | TODO | TODO | entry-id-only directory scan supported |
| `0x12` | AFP Get DOS Name From Entry ID | `afp_get_dos_name_from_entry_id` | TODO | TODO | TODO | TODO | |
| `0x13` | AFP Get Macintosh Info On Deleted Files | implemented | server | helper | suite | docs | salvage-backed |
## Backend discipline checklist
For every implemented endpoint, check these rules explicitly:
- Path resolution uses mars_nwe path/namespace helpers.
- Directory identities use mars_nwe namespace/basehandle state.
- File entry-id reverse lookup uses the AFP entry-id xattr cache only for files.
- File open/read/write/close uses mars_nwe NetWare file handles.
- Rights use mars_nwe trustee/effective-rights checks.
- Hidden/system/archive attributes use mars_nwe attribute/archive paths.
- FinderInfo uses the AFP-only metadata store.
- Resource forks remain unsupported until a real backend exists.
- Deleted-file Macintosh metadata waits for mars_nwe salvage/deleted-entry state.
- AFP handlers do not introduce standalone POSIX filesystem semantics.
## Known open decisions
### Entry-id-only scan
AFP `0x0a` and AFP 2.0 `0x11` support directory entry-id starts. The entry ID
must resolve through mars_nwe namespace/basehandle logic; file AFP entry-id xattrs
are not valid scan bases.
### Deleted-file Macintosh metadata
AFP `0x13` is now implemented as a thin adapter over the normal NetWare
salvage family, which is present and verified:
- `NCP 0x2222 / 87 / 16` - Scan Salvageable Files
- `NCP 0x2222 / 87 / 17` - Recover Salvageable File
- `NCP 0x2222 / 87 / 18` - Purge Salvageable File
- optional legacy `NCP 0x2222 / 22 / 27` - Scan Salvageable File (old)
Do not extend AFP `0x13` as an AFP-local deleted-file scan; keep it on the shared salvage backend.
## Completion criteria
The final audit is complete only when:
1. The endpoint table above is filled with explicit OK/unsupported decisions.
2. The exact WebSDK and Novell header paths used for the comparison are listed.
3. `tests/afp/afp_endpoint_inventory.py` has no unexpected warnings.
4. The only accepted warnings are documented final-slice limitations.
5. The AFP smoke suite still reports `failures=0`.
6. Any unsupported endpoint has a documented backend dependency or deliberate
compatibility-slice reason.

View File

@@ -1,141 +0,0 @@
# AFP WebSDK audit findings
This records the concrete WebSDK pass done against the uploaded SDK tree before
turning the final audit checklist into implementation decisions.
## Sources inspected
The available uploaded WebSDK tree contained AFP reference HTML pages rather
than a standalone `nwafp.h` header. The checked source paths were:
```text
/mnt/data/websdk_full/websdk/htmldoc/nwhtm/TOCMap.txt
/mnt/data/websdk_full/websdk/htmldoc/nwhtm/projmap.txt
/mnt/data/websdk_full/websdk/htmldoc/nwhtm/redleg14/a_apiref/0002R001.htm
/mnt/data/websdk_full/websdk/htmldoc/nwhtm/redleg14/a_apiref/0002R002.htm
/mnt/data/websdk_full/websdk/htmldoc/nwhtm/redleg14/a_apiref/0002R003.htm
/mnt/data/websdk_full/websdk/htmldoc/nwhtm/redleg14/a_apiref/0002R004.htm
/mnt/data/websdk_full/websdk/htmldoc/nwhtm/redleg14/a_apiref/0002R005.htm
/mnt/data/websdk_full/websdk/htmldoc/nwhtm/redleg14/a_apiref/0002R006.htm
/mnt/data/websdk_full/websdk/htmldoc/nwhtm/redleg14/a_apiref/0002R007.htm
/mnt/data/websdk_full/websdk/htmldoc/nwhtm/redleg14/a_apiref/0002R008.htm
/mnt/data/websdk_full/websdk/htmldoc/nwhtm/redleg14/a_apiref/0002R009.htm
/mnt/data/websdk_full/websdk/htmldoc/nwhtm/redleg14/a_apiref/0002R010.htm
/mnt/data/websdk_full/websdk/htmldoc/nwhtm/redleg14/a_apiref/0002R011.htm
/mnt/data/websdk_full/websdk/htmldoc/nwhtm/redleg14/a_apiref/0002R012.htm
/mnt/data/websdk_full/websdk/htmldoc/nwhtm/redleg14/a_apiref/0002R013.htm
/mnt/data/websdk_full/websdk/htmldoc/nwhtm/redleg14/a_apiref/0002R014.htm
/mnt/data/websdk_full/websdk/htmldoc/nwhtm/redleg14/a_apiref/0002R015.htm
/mnt/data/websdk_full/websdk/htmldoc/nwhtm/redleg14/a_apiref/0002R016.htm
/mnt/data/websdk_full/websdk/htmldoc/nwhtm/redleg14/a_apiref/0002R017.htm
/mnt/data/websdk_full/websdk/htmldoc/nwhtm/redleg14/a_apiref/0002R018.htm
```
The deleted-file dependency check also inspected the normal salvage reference
pages:
```text
/mnt/data/websdk_full/websdk/htmldoc/nwhtm/redleg14/a_apiref/0010R024.htm
/mnt/data/websdk_full/websdk/htmldoc/nwhtm/redleg14/a_apiref/0010R027.htm
/mnt/data/websdk_full/websdk/htmldoc/nwhtm/redleg14/a_apiref/0010R038.htm
/mnt/data/websdk_full/websdk/htmldoc/nwhtm/redleg14/a_apiref/0010R039.htm
```
## AFP subfunction numbers
The WebSDK AFP reference pages confirm this NCP `0x2222 / function 35` subfunction
map:
| Subfn | WebSDK page | Name | mars_nwe inventory status |
| --- | --- | --- | --- |
| `0x01` | `0002R006.htm` | AFP Create Directory | implemented |
| `0x02` | `0002R007.htm` | AFP Create File | implemented |
| `0x03` | `0002R008.htm` | AFP Delete | implemented |
| `0x04` | `0002R010.htm` | AFP Get Entry ID From Name | implemented / validating |
| `0x05` | `0002R013.htm` | AFP Get File Information | implemented |
| `0x06` | `0002R011.htm` | AFP Get Entry ID From NetWare Handle | implemented |
| `0x07` | `0002R016.htm` | AFP Rename | implemented |
| `0x08` | `0002R015.htm` | AFP Open File Fork | implemented for data fork |
| `0x09` | `0002R018.htm` | AFP Set File Information | implemented |
| `0x0a` | `0002R017.htm` | AFP Scan File Information | implemented for path and directory entry-id starts |
| `0x0b` | `0002R005.htm` | AFP Alloc Temporary Directory Handle | implemented |
| `0x0c` | `0002R012.htm` | AFP Get Entry ID From Path Name | implemented |
| `0x0d` | `0002R001.htm` | AFP 2.0 Create Directory | implemented |
| `0x0e` | `0002R002.htm` | AFP 2.0 Create File | implemented |
| `0x0f` | `0002R013.htm` | AFP 2.0 Get File Information | implemented through shared handler |
| `0x10` | `0002R004.htm` | AFP 2.0 Set File Information | implemented through shared semantics |
| `0x11` | `0002R003.htm` | AFP 2.0 Scan File Information | implemented for path and directory entry-id starts |
| `0x12` | `0002R009.htm` | AFP Get DOS Name From Entry ID | implemented |
| `0x13` | `0002R014.htm` | AFP Get Macintosh Info On Deleted Files | implemented / salvage-backend adapter |
No extra AFP subfunction beyond `0x13` appeared in the WebSDK AFP reference TOC.
## Layout findings
The current mars_nwe request/reply layouts match the WebSDK direction for the
implemented compatibility slice:
- `0x04` Get Entry ID From Name uses volume, AFP entry ID, path length, and an
AFP-style path relative to the entry ID, then returns a 32-bit AFP entry ID.
- `0x05` and `0x0f` Get File Information use volume, AFP entry ID, request
bitmap, path length, and AFP-style path, then return the AFP information
record.
- `0x09` and `0x10` Set File Information use volume, AFP entry ID, request
bitmap, attributes, date/time fields, FinderInfo, ProDOS info, and relative
AFP path. The server intentionally implements only the safe subset that maps
to mars_nwe metadata and AFP-only xattrs.
- `0x0a` and `0x11` Scan File Information use volume, AFP entry ID, last-seen
ID, desired response count, search bitmap, request bitmap, path length, and an
AFP-style path relative to the entry ID.
- `0x0b` Alloc Temporary Directory Handle uses volume, AFP entry ID, path length,
and an AFP-style path relative to the entry ID, then returns a NetWare
directory handle and access-rights byte.
- `0x0c` Get Entry ID From Path Name is the older NetWare-directory-handle based
lookup and returns a 32-bit AFP entry ID.
- `0x08` Open File Fork returns AFP entry ID, fork length, and a NetWare access
handle. The WebSDK page confirms the data/resource fork indicator and access
mode bits. mars_nwe currently supports the data fork and rejects resource
fork requests until a real backend exists.
- `0x13` Get Macintosh Info On Deleted Files is not a live path lookup. Its
request is volume number plus DOS directory entry, and its reply is FinderInfo,
ProDOS info, resource fork size, and deleted file name.
## Important implementation decisions
### Entry-id-only Scan File Information
The WebSDK Scan File Information pages describe the path string as relative to
`AFP Entry ID`. mars_nwe supports the compatible directory case: a request with
a directory AFP entry ID and an empty path scans that directory.
The implementation remains intentionally narrow:
1. Entry-id scan bases must resolve to directories through mars_nwe
namespace/basehandle logic.
2. The existing mars_nwe directory scan path is reused after resolution.
3. File AFP xattr entry IDs are not valid scan bases.
### AFP 0x13 is salvage-backed in this slice
The WebSDK `0x13` page makes this call dependent on deleted-file state: the
request is keyed by volume and DOS directory entry, and the reply describes a
deleted Macintosh directory entry. The WebSDK file services chapter also
contains the normal salvage family:
- Scan Salvageable Files
- Recover Salvageable File
- Purge Salvageable File
- Scan Salvageable File (old)
Therefore `0x13` is implemented only after the verified mars_nwe
salvage/deleted-entry backend. It must remain a backend adapter, not an
AFP-local scan of live paths or filesystem trash.
## Result
The WebSDK pass does not require renaming the AFP endpoint map again. The
remaining concrete work before closing the current AFP slice is:
1. Keep `0x13` documented as salvage-backed; do not add a second AFP deleted-file store.
2. Re-run `tests/afp/afp_endpoint_inventory.py` and the AFP smoke suite.
3. Fill the final audit table with these WebSDK source paths and results.

File diff suppressed because it is too large Load Diff

View File

@@ -1,31 +0,0 @@
# AFP TODO
This file contains only AFP follow-up work that is still open. Smoke results,
endpoint inventory, WebSDK audit notes, and implementation history belong in the
neighboring AFP documentation files, not in the root `TODO.md`.
## Remaining AFP work
### `0x13 AFP Get Macintosh Info On Deleted File`
Current status:
- Implemented as a conservative adapter over the mars_nwe salvage/deleted-entry
backend.
- Covered by `afp_deleted_info_smoke` and the full `afp_smoke_suite.sh`.
- Does not scan or expose `.recycle` / `.salvage` as AFP-visible paths.
Current AFP mapping:
1. Resolve the deleted DOS directory entry through the mars_nwe salvage backend.
2. Return FinderInfo from the salvage JSON snapshot.
3. Return ProDOS information from the nwatalk xattr-backed Salvage JSON snapshot (`prodos_info_hex`).
4. Return resource fork size from the salvage JSON snapshot.
5. Return the deleted filename from the salvage/deleted-entry record.
References:
- `tests/afp/AFP_DELETED_FILE_INFO.md`
- `tests/afp/AFP_ENDPOINT_INVENTORY.md`
- `tests/afp/AFP_FINAL_AUDIT.md`
- `tests/afp/AFP_WEBSK_AUDIT_FINDINGS.md`

View File

@@ -1,9 +1,15 @@
# Salvage smoke tests
This directory contains the shared mars_nwe NetWare salvage/deleted-entry tests.
The backend is shared by NetWare NCP salvage calls and the later AFP `0x13`
`Get Macintosh Info On Deleted Files` adapter; AFP must not grow a parallel
local deleted-file scanner.
Status: finished for the current NetWare salvage compatibility slice.
This directory contains the shared mars_nwe NetWare salvage/deleted-entry tests
and the single remaining salvage documentation file for this test group. The
previous backend-design notes have been folded into this README so the salvage
test directory has one Markdown entry point.
The backend is shared by the NetWare NCP salvage calls and AFP `0x13` `Get
Macintosh Info On Deleted Files`. AFP must remain a thin adapter over this
backend and must not grow a parallel deleted-file scanner.
## Configuration covered by the tests
@@ -24,27 +30,26 @@ The active salvage configuration block is intentionally in a low `nwserv.conf` /
Section meanings:
- `51` enables/disables salvage.
- `52` names the recycle payload repository and the `.salvage` metadata
repository.
- `53` is a compact Samba-`vfs_recycle`-style behaviour flag string:
- `51` enables or disables salvage.
- `52` names the recycle payload repository and the salvage metadata repository.
- `53` is a compact Samba `vfs_recycle`-style behaviour flag string:
- `k` = keeptree,
- `v` = versions,
- `t` = touch,
- `m` = touch_mtime.
- `54` reserves directory/subdirectory modes for generated repositories.
- `55` is `minsize maxsize`. Values may be raw bytes or case-insensitive
`kb`, `mb`, or `gb` units, for example `55 1kb 100MB`.
`kb`, `mb`, or `gb` units.
- `56` is the `exclude` pattern list. Matching files are deleted directly.
- `57` is the `exclude_dir` pattern list. Matching directories bypass salvage.
- `58` is the `noversions` pattern list. Matching files are recycled, but old
recycle names are replaced instead of getting `Copy #x of NAME` history.
- `59` is reserved for cleanup/history policy.
## Repository layout
## Repository layout and metadata
With `k`/keeptree enabled, a deleted `SYS:PUBLIC/PMDFLTS.INI` owned by
`SUPERVISOR` is expected to produce:
With keeptree enabled, a deleted `SYS:PUBLIC/PMDFLTS.INI` owned by `SUPERVISOR`
is expected to produce:
```text
SYS/.recycle/SUPERVISOR/PUBLIC/PMDFLTS.INI
@@ -55,17 +60,13 @@ The `.recycle` tree contains deleted payload files. The `.salvage` tree
contains one JSON sidecar per deleted object. There is no large per-directory
index file.
The sidecar JSON must preserve mars_nwe server metadata needed for exact
recover, including:
- NetWare archive/fileinfo xattrs from `nwarchive`,
- AFP metadata from `nwatalk` when present,
- inherited rights mask and explicit trustee object/right pairs,
- selected recycle/salvage relative paths.
`finder_info_hex` is serialized as a fixed 32-byte AFP FinderInfo block encoded
as 64 hex characters. If mars_nwe has no FinderInfo xattr for the deleted
object, the JSON stores the all-zero 32-byte FinderInfo value.
The sidecar JSON preserves the mars_nwe server metadata needed for exact
recover, including NetWare archive/fileinfo xattrs, AFP metadata from nwatalk
when present, inherited rights, explicit trustee object/right pairs, and the
selected recycle/salvage relative paths. `finder_info_hex` is serialized as a
fixed 32-byte AFP FinderInfo block encoded as 64 hex characters. If mars_nwe
has no FinderInfo xattr for the deleted object, the JSON stores the all-zero
32-byte FinderInfo value.
## Samba-compatible version naming
@@ -85,27 +86,47 @@ SYS/.salvage/SUPERVISOR/PUBLIC/SLVGCHK.TXT.json
SYS/.salvage/SUPERVISOR/PUBLIC/Copy #1 of SLVGCHK.TXT.json
```
If `v` is not enabled, or a file matches the `noversions` list, the old recycle
payload/metadata is replaced instead of creating a `Copy #x of ...` history
entry. The `Copy #n of ...` prefix is intentionally not localized; it follows
Samba `vfs_recycle` literally and should be stable across server locales.
If versioning is disabled, or a file matches the `noversions` list, the previous
recycled payload/metadata is replaced instead of creating a `Copy #x of ...`
history entry. The `Copy #n of ...` prefix is intentionally not localized; it
follows Samba `vfs_recycle` literally and should be stable across server
locales.
## Layout smoke
## NCP endpoint scope
`salvage_layout_smoke.sh` is a local filesystem-only contract test. It does not
require a running mars_nwe server and does not use NCP.
The current NetWare 3.x salvage slice is implemented and covered by the smoke
suite:
```sh
./tests/salvage/salvage_layout_smoke.sh
```text
NCP 0x2222 / 87 / 16 Scan Salvageable Files
NCP 0x2222 / 87 / 17 Recover Salvageable File
NCP 0x2222 / 87 / 18 Purge Salvageable File
NCP 0x2222 / 22 / 27 Scan Salvageable Files (old bridge)
NCP 0x2222 / 22 / 28 Recover Salvageable File (old bridge)
NCP 0x2222 / 22 / 29 Purge Salvageable File (old bridge)
```
It verifies the basic `.recycle`/`.salvage` directory contract and stale JSON
detection. Runtime scans also treat `.salvage` JSON as a sidecar for the
matching `.recycle` payload: if the payload is removed externally, the entry
must disappear from `87/16` scan results and the stale JSON should be cleaned.
The combined smoke suite includes a manual pause that asks the tester to remove
the backend `.recycle` payload, then scans again and greps the server log for
`WARN SALVAGE 87/16 STALE`.
The old `22/*` calls remain thin adapters over the same shared backend. Later
NetWare 4.11+ list variants and UTF-8 extensions remain outside this 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
```
## Stale metadata cleanup
Samba or an administrator may delete files from `.recycle` while `.salvage`
metadata is still present. That is a real backend state, not a protocol error.
Runtime scans treat each `.salvage` JSON file as a sidecar for the matching
`.recycle` payload: if the payload is gone, `87/16` must not return the stale
entry and should remove the JSON. The server log should contain a greppable
line like:
```text
WARN SALVAGE 87/16 STALE ...
```
## NCP path visibility
@@ -116,40 +137,37 @@ leading-dot path components as special `.`/`..` syntax and rejects names such as
are also hidden by default in the NetWare attribute layer.
Smoke tests therefore must not validate backend payloads by opening
`SYS:.recycle/...` or metadata by opening `SYS:.salvage/...` through normal NCP
file calls. The correct NCP-level checks are:
`SYS:.recycle/...` or `SYS:.salvage/...` through normal NCP file calls. The
correct NCP-level checks are:
- create/write/read the live file through NCP,
- delete the live file through NCP,
- use salvage scan `87/16` to confirm that a salvageable entry exists,
- use recover `87/17` or purge `87/18` on the scan sequence,
- create/write/read the live file through NCP;
- delete the live file through NCP;
- use salvage scan `87/16` to confirm that a salvageable entry exists;
- use recover `87/17` or purge `87/18` on the scan sequence;
- read the restored live file through NCP to verify payload content.
Local filesystem layout tests may still inspect `.recycle` and `.salvage`
directly when they intentionally test backend layout and run with suitable Unix
permissions.
## Local layout smoke
`salvage_layout_smoke.sh` is a local filesystem-only contract test. It does not
require a running mars_nwe server and does not use NCP.
```sh
./tests/salvage/salvage_layout_smoke.sh
```
It verifies the basic `.recycle`/`.salvage` directory contract and stale JSON
detection.
## NCP smoke suite
`salvage_smoke_suite.sh` is the single integration check for the server-side
delete hook and Samba-compatible history behaviour. It uses `ncp_delete_smoke`,
a small libncp client, to create and delete the same NetWare path twice through
classic NetWare NCP file functions.
The suite appends all current integration checks into one report:
- first delete: verifies normal `.recycle` payload and `.salvage` JSON capture,
- second delete: verifies version naming with `Copy #1 of NAME` when option `53`
contains the `v` flag,
- NCP `0x2222 / 87 / 16`: scans the same directory through the official
`ncpfs` salvage scan API. The NCP reply reports the original deleted file
name, so the suite expects at least two entries named `SLVGCHK.TXT`; the
`Copy #1 of ...` history name is verified through the `.salvage` JSON path
above.
The script does not call local `rm`/`unlink` for the tested live path; local
filesystem access is used only after the NCP delete to inspect the expected
recycle payloads and JSON sidecars.
`salvage_smoke_suite.sh` is the single integration entry point for the
server-side delete hook, Samba-compatible history behaviour, scan, recover,
purge, hidden repository behaviour, stale sidecar cleanup, and report-file
generation.
Example:
@@ -162,28 +180,30 @@ Example:
--out /tmp/mars-salvage-report.txt
```
The script can run as a normal user. Best-effort pre-clean of stale test
artifacts may warn when existing `.recycle`/`.salvage` files are owned by the
server user or root; those warnings do not fail the smoke by themselves. For
cleanest results, use a fresh test filename or run cleanup with the same Unix
account that owns the mars_nwe volume files.
The suite creates multiple versions of the same file through NCP, deletes them
through NCP, scans salvageable entries, verifies duplicate sequence entries for
the original deleted name, purges selected entries, recovers the oldest sequence,
and checks the restored payload through NCP read. Backend history paths remain
hidden behind the salvage endpoints.
The old split scripts `salvage_ncp_delete_smoke.sh` and
`salvage_ncp_history_smoke.sh` were replaced by this single suite so the salvage
flow is exercised like the AFP smoke suite: one entry point, one report, and one
summary. New salvage checks should be appended to this suite instead of growing
separate top-level smoke scripts.
The suite includes a manual stale-payload pause: it prints a `sudo rm -f`
command for the backend `.recycle` payload, then waits for Enter. Remove that
payload in a second shell and continue; the next scan should clean the stale
sidecar and the log grep should find `WARN SALVAGE 87/16 STALE`.
## Still to implement
Best-effort pre-clean of stale test artifacts may warn when existing `.recycle`
or `.salvage` files are owned by the server user or root. Those warnings do not
fail the smoke by themselves. For cleanest results, use a fresh test filename
or run cleanup with the same Unix account that owns the mars_nwe volume files.
Runtime endpoint tests should be appended as the NCP salvage calls are
implemented. The suite already covers the initial `NCP 0x2222 / 87 / 16` scan
endpoint after the delete/history phases have created salvageable entries.
For duplicate original names, the scan endpoint exposes multiple sequence
entries with the same original name; the server-side `.salvage` metadata keeps
the selected recycle/history path.
## Completion status
- optional `NCP 0x2222 / 22 / 27` Scan Salvageable Files (old),
- `NCP 0x2222 / 87 / 17` Recover Salvageable File,
- `NCP 0x2222 / 87 / 18` Purge Salvageable File,
- AFP `0x13` as a thin adapter over the shared salvage backend.
The salvage test group is complete for the current compatibility slice. The
combined suite now covers NCP write/read payloads, delete capture, versioned
history naming, `87/16` scan, `87/17` recover, `87/18` purge, old `22/27` to
`22/29` bridges, hidden backend repository behaviour, stale sidecar cleanup, and
report-file generation.
Future salvage checks should be appended to `salvage_smoke_suite.sh` rather than
creating unrelated top-level smoke scripts. New helper binaries are acceptable
when the suite starts them directly.

View File

@@ -1,244 +0,0 @@
# 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 and the `versions` behaviour is enabled, mars_nwe uses
Samba `vfs_recycle` compatible names and the same selected name for the sidecar
JSON:
```text
SYS/.recycle/SUPERVISOR/PUBLIC/PMDFLTS.INI
SYS/.recycle/SUPERVISOR/PUBLIC/Copy #1 of PMDFLTS.INI
SYS/.salvage/SUPERVISOR/PUBLIC/PMDFLTS.INI.json
SYS/.salvage/SUPERVISOR/PUBLIC/Copy #1 of PMDFLTS.INI.json
```
If versioning is disabled, or a file matches the `noversions` list, the previous
recycled payload/metadata is replaced instead of creating a `Copy #x of ...`
entry.
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,
"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.
Optional AFP/Finder fields should only be present when the corresponding
mars_nwe-xattr metadata exists; missing FinderInfo must not be serialized as
synthetic all-zero data.
## 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 initial scanner implemented
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. The 87/16 scanner walks the existing
`.salvage` sidecar files and does not create a second index or trustee store:
```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; the JSON stores a fixed 32-byte
FinderInfo block, using all zeroes when mars_nwe has no FinderInfo xattr,
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 cover the backend without AFP:
- local layout contract,
- create/delete through the normal NCP server path,
- verify the file is moved to `.recycle`,
- verify the JSON exists in `.salvage`,
- verify Samba-compatible `Copy #x of NAME` history naming.
Follow-up tests should cover:
- cleanup removes stale JSON when the recycle file is deleted,
- recover restores the file,
- purge removes both file and JSON,
- scan endpoints enumerate the JSON records in NetWare-compatible order.
Only after those tests are stable should `tests/afp` gain an AFP `0x13` smoke.
## Configuration direction
The active low-numbered configuration block is:
```text
51 1 # enable salvage
52 .recycle .salvage # payload repository, metadata repository
53 kv # k=keeptree, v=versions, t=touch, m=touch_mtime
54 0700 0700 # repository/subdirectory modes
55 0 0 # minsize maxsize; bytes or kb/mb/gb suffixes
56 - # exclude patterns
57 - # exclude_dir patterns
58 - # noversions patterns
59 - # cleanup/history policy, reserved
```
The defaults should remain compatible with a Samba-style recycle layout and
should keep `.salvage` as metadata-only state.