From ee2271c099414376a2e9fc263b9a398cdcffee18 Mon Sep 17 00:00:00 2001 From: Mario Fetka Date: Sat, 30 May 2026 18:21:51 +0000 Subject: [PATCH] tests: record AFP namespace entry id smoke success --- TODO.md | 92 ++++++++++++++++-------------- tests/linux/README.md | 126 +++++++++++++++++------------------------- 2 files changed, 101 insertions(+), 117 deletions(-) diff --git a/TODO.md b/TODO.md index a6f76ed..5e80c63 100644 --- a/TODO.md +++ b/TODO.md @@ -215,14 +215,15 @@ Current status: - `NCP 0x23` still returns invalid namespace for AFP calls that are not implemented yet. - `AFP Get Entry ID From Path Name` is implemented when the optional - Netatalk/libatalk backend is available. Linux smoke coverage exists in - `tests/linux/afp_entry_id_smoke` and has been verified against `SYS:`, - `SYS:PUBLIC`, `SYS:SYSTEM`, and `SYS:BURST` with stat-derived fallback - entry IDs. + Netatalk/libatalk backend is available. Entry IDs are now derived first from + existing mars_nwe NetWare namespace/basehandle state rather than from a + parallel AFP/stat fallback generator. Linux smoke coverage exists in + `tests/linux/afp_entry_id_smoke`; the latest full-suite run against + `SYS:PUBLIC/pmdflts.ini` returned `entry_id=0x00000004`. - `AFP Get Entry ID From Name` is implemented for the same path-backed - smoke mode. Linux smoke coverage uses `tests/linux/afp_entry_id_smoke --from-name` - and has been verified against `SYS:`, `SYS:PUBLIC`, - `SYS:SYSTEM`, and `SYS:BURST` with stat-derived fallback entry IDs. + smoke mode. Linux smoke coverage uses + `tests/linux/afp_entry_id_smoke --from-name`; the identity source follows the + same NetWare namespace/basehandle path as Entry ID From Path Name. - `AFP Get File Information` is implemented for read-only path-based requests. Linux smoke coverage exists in `tests/linux/afp_file_info_smoke` and has been verified against `SYS:`, `SYS:PUBLIC`, `SYS:SYSTEM`, and `SYS:BURST`. @@ -237,14 +238,16 @@ Current status: endpoint. Runtime coverage has been verified against `SYS:PUBLIC` by walking multiple directory entries with the returned `next_last_seen` AFP Entry ID continuation value. The verified AFP 2.0 and older `0x0a` first - records both return `pmdflts.ini` (`entry_id=0x23c8787d`, `data_len=8161`) - on the sample tree, and an AFP 2.0 continuation with that Entry ID returns - `ohlogscr.bat` (`entry_id=0x260437f6`, `data_len=1296`). + records now expose NetWare namespace/basehandle-derived Entry IDs. The + latest full-suite run against `SYS:PUBLIC` returned + `next_last_seen=0x00000004` and `entry_id=0x00000004` for the first scanned + record while preserving the expected file metadata. - `AFP Get Entry ID From NetWare Handle` is implemented for read-only data-fork file handles that are opened in the same client connection. Linux smoke - coverage uses `tests/linux/afp_entry_id_smoke --from-handle` and has been - verified against `SYS:PUBLIC/pmdflts.ini` and `SYS:PUBLIC/ohlogscr.bat`, - returning volume 0, `fork=0`, and stat-derived fallback Entry IDs for now. + coverage uses `tests/linux/afp_entry_id_smoke --from-handle`. The latest + full-suite run verified `SYS:PUBLIC/pmdflts.ini`, returning volume 0, + `fork=0`, and the same NetWare namespace/basehandle-derived + `entry_id=0x00000004` as the path-backed lookup. - `AFP Open File Fork` is implemented for the same path-backed smoke subset. Raw `VOL:`-style paths resolve the effective NetWare volume from the path prefix instead of assuming volume 0, so the same smoke path can cover `SYS:` @@ -291,12 +294,11 @@ Current status: alignment by reading `user.org.mars-nwe.afp.finder-info=0x544558544d415253...` (`TEXTMARS` with no leading padding byte), confirms attribute set/clear via the versioned - attributes xattr ending clean at `0x01000000`, and confirms the cached - Entry ID xattr (`0x010000001ad06d3e` in the latest run). The first stat-derived AFP entry id - for a path is now cached in the versioned `org.mars-nwe.afp.entry-id` xattr; a - `fallback` marker on that first verification Get File Information diagnostic - describes the entry-id origin, not the FinderInfo write result. Follow-up - probes should read the cached mars_nwe entry id and omit the fallback marker. + attributes xattr ending clean when AFP-only bits are present. Current + Entry IDs are derived from the mars_nwe NetWare namespace/basehandle path and + only cached in `org.mars-nwe.afp.entry-id` as AFP compatibility metadata when + that write is permitted; an xattr cache write failure is non-fatal because + the namespace handle remains the source of truth. System remains on the narrow AFP xattr-only attribute path, while Archive is routed through the existing NetWare attribute path; runtime probes verified System set/clear and Archive set/clear with AFP-visible attrs `0x0004`, @@ -329,11 +331,11 @@ Current status: - NetWare AFP calls are NCP entry points for Mac namespace semantics on a NetWare volume, not transport-level AFP proxy calls to `afpd`. - AFP Get DOS Name From Entry ID (0x12) is implemented as a conservative - read-only reverse lookup over the existing mars_nwe volume table and the - `nwatalk_get_entry_id()` metadata probe. It returns the DOS/NetWare path - relative to the requested volume for entries that already have a cached - mars_nwe/Netatalk AFP ID, and deliberately does not create fallback IDs while - scanning a volume. + read-only reverse lookup that first uses the existing mars_nwe + `map_directory_number_to_path()` namespace/basehandle path. The old + `nwatalk_get_entry_id()` volume scan remains only as a legacy fallback for + cached AFP IDs. The latest smoke run confirmed `entry_id=0x00000004` + resolving to `PUBLIC/PMDFLTS.INI`. Follow-up: @@ -345,18 +347,20 @@ Follow-up: - Keep returning invalid namespace for AFP calls that still lack a real per-volume Mac namespace/AFP metadata layer. Do not return success for additional AFP calls without data/resource fork and Finder Info semantics. -- Replace the compatibility stat-derived AFP entry-id generator with a real - CNID/directory-id allocator once the libatalk/CNID backend is integrated. -- mars_nwe-owned AFP entry ids are probed first from the versioned - `org.mars-nwe.afp.entry-id` xattr before consulting Netatalk/libatalk - AppleDouble/CNID metadata. If neither source has an id, mars_nwe derives the - existing stat-compatible id and caches it in that xattr so subsequent probes - can use persistent mars_nwe metadata. Linux smoke coverage confirms the - versioned xattr payload shape, for example `0x010000007b9c42e1` for a cached - `0x7b9c42e1` Entry ID. AFP directory-scan continuation remains directory - iteration based: `last_seen` skips past the previously returned object, but - the next returned Entry ID is not required to be numerically greater than the - continuation token. FinderInfo plus the Finder Hidden/System/Archive AFP attributes now have +- AFP Entry IDs now prefer the existing mars_nwe NetWare namespace/basehandle + mapping before consulting cached AFP metadata or the old fallback path. A + future libatalk/CNID backend may still provide Apple-native identity, but AFP + must not grow a second mars_nwe object-id resolver in parallel to the existing + namespace machinery. +- The full smoke suite verifies namespace-derived identity end to end: + Entry ID From Path Name, Entry ID From NetWare Handle, Get File Information, + Scan File Information, Set File Information verification, and Get DOS Name + From Entry ID all returned or consumed `entry_id=0x00000004` for the sample + `SYS:PUBLIC/pmdflts.ini` path, with `failures=0`. AFP directory-scan + continuation remains directory iteration based: `last_seen` skips past the + previously returned object, but the next returned Entry ID is not required to + be numerically greater than the continuation token. FinderInfo plus the + Finder Hidden/System/Archive AFP attributes now have deliberately narrow write paths through AFP Set File Information `0x09` and AFP 2.0 Set File Information `0x10`; CNID allocation and broader AFP metadata writes still need a deliberate write-safe @@ -401,9 +405,11 @@ Design rule: Refactor/wrapper follow-up: -- Add a shared AFP object resolver that handles raw `VOL:PATH`, directory-handle - relative paths, volume plus entry id, and the WebSDK path modifier forms by - reusing existing mars_nwe volume, namespace, and directory-handle helpers. +- Continue reusing the existing mars_nwe volume, namespace, basehandle, and + directory-handle helpers for AFP object lookup. Do not add an AFP-local + object resolver where `conn_get_kpl_unxname()`, `nw_vol_inode_to_handle()`, + `map_directory_number_to_path()`, or related namespace helpers already cover + the case. - Route all AFP writes through existing mars_nwe policy checks before changing metadata. Archive and Modify timestamp already do this through NetWare helpers. FinderInfo and AFP-only Hidden/System xattr writes are now gated @@ -426,9 +432,11 @@ Refactor/wrapper follow-up: - Revisit Scan File Information after the resolver work and prefer mars_nwe's existing directory/search machinery over the current AFP-local directory walk for search attributes, namespace filtering, and multi-record replies. -- Replace the current volume-walk Get DOS Name From Entry ID path with a real - Entry ID/CNID index or an existing canonical path lookup once the entry-id - backend grows beyond xattr/stat-derived compatibility IDs. +- The current Get DOS Name From Entry ID path first uses the existing + `map_directory_number_to_path()` namespace/basehandle lookup and only falls + back to the legacy AFP metadata volume walk when necessary. Future CNID work + should plug into that same resolver order rather than reintroducing a + parallel path database. AFP Set File Information metadata-rights convergence: diff --git a/tests/linux/README.md b/tests/linux/README.md index 6ccb5ab..11c24cc 100644 --- a/tests/linux/README.md +++ b/tests/linux/README.md @@ -7,13 +7,12 @@ The tests use the ncpfs/libncp client library. They are not built by default because they require the host ncpfs development headers/library and a running NetWare-compatible server. -The AFP endpoints are intentionally conservative. mars_nwe-owned ids are read -from the versioned `org.mars-nwe.afp.entry-id` xattr before falling back to -Netatalk/libatalk AppleDouble/CNID metadata. When neither source has an id yet, -the existing stat-derived compatibility id is cached in that xattr so subsequent -AFP probes can reuse the same mars_nwe-owned id instead of re-entering the -temporary fallback path. The first AFP write smoke path is deliberately limited -to the FinderInfo bitmap of +The AFP endpoints are intentionally conservative. AFP Entry IDs now prefer the +existing mars_nwe NetWare namespace/basehandle mapping, with cached +`org.mars-nwe.afp.entry-id` metadata kept only as Apple/AFP compatibility state +and legacy fallback. This keeps object identity on the existing mars_nwe +namespace path instead of creating a parallel AFP resolver. The first AFP write +smoke path is deliberately limited to the FinderInfo bitmap of AFP 2.0 Set File Information; CNID allocation, DOS attribute mapping, resource fork writes, and data-fork writes remain separate write-safety work. mars_nwe source uses Netatalk-style `org.mars-nwe..*` xattr names; AFP @@ -222,10 +221,9 @@ Useful smoke cases for a standard MARS-NWE `SYS` volume are: ``` A successful reply prints the request path, directory handle, and returned -32-bit AFP Entry ID. Server-side diagnostics currently mark stat-derived -temporary IDs with `fallback`; that means the endpoint is reachable, but -persistent CNID/AppleDouble entry-id storage is still future Mac-namespace -work. +32-bit AFP Entry ID. Current AFP Entry IDs are normally derived from the +existing NetWare namespace/basehandle mapping. A full-suite run after that +change returned `entry_id=0x00000004` for `SYS:PUBLIC/pmdflts.ini`. If the server was built without the optional Netatalk/libatalk backend, the endpoint is expected to return invalid namespace. To treat that as a successful @@ -263,9 +261,8 @@ Useful smoke cases for a standard MARS-NWE `SYS` volume are: ``` A successful reply prints the same 32-bit AFP Entry ID format as the path-name -probe. Server-side diagnostics currently mark stat-derived temporary IDs with -`fallback`; real base-entry-id-relative lookup still depends on persistent -CNID/AppleDouble mapping. +probe and uses the same NetWare namespace/basehandle identity source for +path-backed requests. ### AFP Get Entry ID From NetWare Handle @@ -292,22 +289,18 @@ Useful smoke cases for a standard MARS-NWE `SYS:PUBLIC` directory are: Successful replies print the resolved volume number, 32-bit AFP Entry ID, and fork indicator. The current implementation reports the data fork (`fork=0`) -and server diagnostics mark the returned Entry ID as `fallback` when it is -derived from Unix `stat(2)` data rather than persistent CNID, AppleDouble, or -libatalk metadata: +and derives the Entry ID from the same mars_nwe namespace/basehandle mapping as +path-backed lookups: ```text -AFP Entry ID From NetWare Handle path=SYS:PUBLIC/pmdflts.ini volume=0 entry_id=0x23c8787d (600340605) fork=0 -AFP Entry ID From NetWare Handle path=SYS:PUBLIC/ohlogscr.bat volume=0 entry_id=0x260437f6 (637810678) fork=0 - -AFP Get Entry ID From NetWare Handle: handle=1 volume=0 unix='/var/mars_nwe/SYS/public/pmdflts.ini' entry=0x23c8787d fallback -AFP Get Entry ID From NetWare Handle: handle=1 volume=0 unix='/var/mars_nwe/SYS/public/ohlogscr.bat' entry=0x260437f6 fallback +AFP Entry ID From NetWare Handle path=SYS:PUBLIC/pmdflts.ini volume=0 entry_id=0x00000004 (4) fork=0 +AFP Get Entry ID From NetWare Handle: handle=1 volume=0 unix='/var/mars_nwe/SYS/public/pmdflts.ini' entry=0x00000004 ``` -The concrete fallback Entry IDs vary with filesystem metadata. Persistent -CNID/AppleDouble/libatalk-backed identity, parent Entry ID derivation, and AFP -resource-fork handle semantics remain future Mac-namespace work; the current -smoke coverage only verifies the conservative read-only data-fork mapping. +Persistent Apple CNID/AppleDouble/libatalk-backed identity, parent Entry ID +derivation, and AFP resource-fork handle semantics remain future Mac-namespace +work; the current smoke coverage verifies the conservative read-only data-fork +mapping through the existing NetWare namespace identity path. ## AFP Alloc Temporary Directory Handle smoke test @@ -517,11 +510,12 @@ Useful smoke cases for a standard MARS-NWE `SYS` volume are: The AFP 2.0 mode is selected with `--afp20`. It has been verified against the same `SYS:`, `SYS:PUBLIC`, `SYS:SYSTEM`, and `SYS:BURST` paths and currently exercises the same path-backed read-only reply as the older call. -The current implementation fills fields that can be derived from Unix `stat(2)` and the optional libatalk -helper wrappers. Server-side diagnostics mark -stat-derived temporary Entry IDs with `fallback`; Parent ID, persistent -CNID/AppleDouble IDs, and fuller Finder Info/resource-fork semantics remain -future Mac-namespace work. +The current implementation fills fields from the existing mars_nwe sources of +truth where possible: NetWare attributes, namespace/basehandle Entry IDs, +trustee-derived AccessPrivileges, Unix file sizes and timestamps, and optional +AFP/libatalk metadata such as FinderInfo. Parent ID, persistent Apple +CNID/AppleDouble IDs, and fuller resource-fork semantics remain future +Mac-namespace work. If the server was built without the optional Netatalk/libatalk backend, use `--allow-invalid-namespace` for the expected negative test. Use @@ -553,32 +547,24 @@ Useful smoke sequence for a standard MARS-NWE `SYS:PUBLIC` directory: ./tests/linux/afp_scan_info_smoke -S MARS -U SUPERVISOR -P secret --last-seen 0x6686342b SYS:PUBLIC ``` -Verified runtime output from the sample `SYS:PUBLIC` tree after mars_nwe had -cached persistent AFP entry ids in `org.mars-nwe.afp.entry-id` xattrs: +Verified runtime output from the sample `SYS:PUBLIC` tree after Entry IDs were +moved onto the existing mars_nwe namespace/basehandle path: ```text -AFP Scan File Info subfunction=0x11 path=SYS:PUBLIC last_seen=0x00000000 desired=1 next_last_seen=0x260437f6 entry_id=0x260437f6 parent_id=0x00000000 attrs=0x0000 data_len=1296 resource_len=0 offspring=0 long_name=ohlogscr.bat short_name=ohlogscr.bat rights=0x9700 -AFP Scan File Info subfunction=0x0a path=SYS:PUBLIC last_seen=0x00000000 desired=1 next_last_seen=0x23c8787d entry_id=0x23c8787d parent_id=0x00000000 attrs=0x0000 data_len=8161 resource_len=0 offspring=0 long_name=pmdflts.ini short_name=pmdflts.ini rights=0x9700 -AFP Scan File Info subfunction=0x11 path=SYS:PUBLIC last_seen=0x260437f6 desired=1 next_last_seen=0x6686342b entry_id=0x6686342b parent_id=0x00000000 attrs=0x0000 data_len=1024 resource_len=0 offspring=0 long_name=pmgate.sys short_name=pmgate.sys rights=0x9700 -AFP Scan File Info subfunction=0x11 path=SYS:PUBLIC last_seen=0x6686342b desired=1 next_last_seen=0x2d12d99c entry_id=0x2d12d99c parent_id=0x00000000 attrs=0x0000 data_len=1954 resource_len=0 offspring=0 long_name=pmail.bat short_name=pmail.bat rights=0x9700 +AFP Scan File Info subfunction=0x11 path=SYS:PUBLIC last_seen=0x00000000 desired=1 next_last_seen=0x00000004 entry_id=0x00000004 parent_id=0x00000000 attrs=0x2000 data_len=44424 resource_len=0 offspring=0 long_name=debug.exe short_name=debug.exe rights=0x9f00 ``` -The concrete Entry IDs vary by filesystem metadata. On first contact mars_nwe -can derive a compatibility id from `stat(2)` and cache it in the versioned -`org.mars-nwe.afp.entry-id` xattr; later probes of that object return the -cached id. The verified xattr payloads are versioned as one version byte, -three reserved bytes, and a big-endian 32-bit AFP Entry ID: - -```sh -getfattr -n user.org.mars-nwe.afp.entry-id -e hex /var/mars_nwe/SYS/public/pmdflts.ini -getfattr -n user.org.mars-nwe.afp.entry-id -e hex /var/mars_nwe/SYS/public/pmgate.sys -``` +The AFP entry-id xattr remains a compatibility/cache location rather than the +source of truth. A final xattr dump from the same run showed the cached value +matching the namespace-derived ID: ```text -user.org.mars-nwe.afp.entry-id=0x010000007b9c42e1 -user.org.mars-nwe.afp.entry-id=0x010000006686342b +user.org.mars-nwe.afp.entry-id=0x0100000000000004 ``` +If that cache write is rejected, the server logs it and continues because the +namespace/basehandle mapping can still resolve the object. + The scan continuation order is deliberately documented as server directory iteration order, not numeric Entry-ID order. `last_seen` identifies the Entry ID that was returned by the previous scan call so mars_nwe can skip entries @@ -643,26 +629,18 @@ subfunction: Verified runtime output: ```text -AFP Set File Info subfunction=0x10 path=SYS:PUBLIC/pmdflts.ini bitmap=0x0020 attrs=0x0000 finder_type=TEXT finder_creator=MARS entry_id=0x23c8787d verified +AFP Set File Info subfunction=0x10 path=SYS:PUBLIC/pmdflts.ini bitmap=0x4000 attrs=0x2000 create=0x5cbe access=0x5cbe modify=0x5cbea1ee backup=0x00000000 finder_type=TEXT finder_creator=MARS entry_id=0x00000004 verified ``` Server diagnostics show the effective resolved volume, the request volume byte, -the FinderInfo bitmap, and the first eight FinderInfo bytes: +the FinderInfo bitmap, and follow-up Get File Information verification with the +same namespace-derived Entry ID: ```text -AFP 2.0 Set File Information: vol=0 request_vol=0 entry=0x00000000 mask=0x0020 path='SYS:PUBLIC/pmdflts.ini' finder_type='TEXT' finder_creator='MARS' -AFP 2.0 Get File Information: vol=0 entry=0x00000000 mask=0xffff path='SYS:PUBLIC/pmdflts.ini' reply_entry=0x23c8787d fallback +AFP 2.0 Set File Information: vol=0 request_vol=0 entry=0x00000000 mask=0x4000 path='SYS:PUBLIC/pmdflts.ini' ... +AFP 2.0 Get File Information: vol=0 entry=0x00000000 mask=0xffff path='SYS:PUBLIC/pmdflts.ini' reply_entry=0x00000004 ``` -The `fallback` marker on the first verification Get File Information diagnostic -still refers to the entry-id source: the returned entry id was derived from the -stat-backed compatibility path because no CNID or mars_nwe entry-id xattr existed -yet. The server now caches that derived id in `org.mars-nwe.afp.entry-id`, so a -second probe of the same file should reuse the xattr-backed id and normally omit -the `fallback` marker. It does not mean the FinderInfo write was ignored; the -helper verifies the written FinderInfo through the follow-up Get File Information -reply. - Linux xattr checks for the FinderInfo and cached Entry ID look like this: ```sh @@ -807,28 +785,26 @@ Example: Expected output shape: ```text -AFP Get DOS Name From Entry ID volume=0 entry_id=0x440cb9b2 path=PUBLIC/PMDFLTS.INI verified +AFP Get DOS Name From Entry ID volume=0 entry_id=0x00000004 path=PUBLIC/PMDFLTS.INI verified ``` - - -A successful post-fix smoke-suite run confirmed the `namedos.c` alias path: +A successful post-fix smoke-suite run confirmed the `namedos.c` alias path via +the existing mars_nwe namespace/basehandle resolver: ```text -AFP Get DOS Name From Entry ID volume=0 entry_id=0x440cb9b2 path=PUBLIC/PMDFLTS.INI verified -AFP Get DOS Name From Entry ID: vol=0 entry=0x440cb9b2 path='PUBLIC/PMDFLTS.INI' +AFP Get DOS Name From Entry ID volume=0 entry_id=0x00000004 path=PUBLIC/PMDFLTS.INI verified +AFP Get DOS Name From Entry ID: vol=0 entry=0x00000004 path='PUBLIC/PMDFLTS.INI' ``` This intentionally returns DOS namespace spelling rather than the raw Unix realcase path (`public/pmdflts.ini`). -The server implementation deliberately reuses the existing mars_nwe volume table -and the `nwatalk_get_entry_id()` metadata probe. It does not create fallback -entry IDs while walking the volume; the target entry must already have a cached -mars_nwe/Netatalk AFP ID, which is the normal state after the Entry ID, Get File -Information, or Scan File Information smoke probes. This keeps the reverse -lookup read-only and avoids populating entry-id xattrs across a whole volume as a -side effect of one DOS-name lookup. +The server implementation deliberately reuses existing mars_nwe namespace +machinery. It first resolves the AFP Entry ID through +`map_directory_number_to_path()` and falls back to the old AFP metadata volume +walk only for legacy cached IDs. It does not create new AFP IDs while walking +the volume, keeping the reverse lookup read-only and avoiding a parallel AFP +path database. ### AFP attribute bit alignment with WebSDK