tests: record AFP namespace entry id smoke success
All checks were successful
Source release / source-package (push) Successful in 48s

This commit is contained in:
Mario Fetka
2026-05-30 18:21:51 +00:00
parent faa44d060b
commit ee2271c099
2 changed files with 101 additions and 117 deletions

92
TODO.md
View File

@@ -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:

View File

@@ -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.<domain>.*` 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