tests: consolidate AFP and salvage markdown docs
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
1511
tests/afp/README.md
1511
tests/afp/README.md
File diff suppressed because it is too large
Load Diff
@@ -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`
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
Reference in New Issue
Block a user