All checks were successful
Source release / source-package (push) Successful in 45s
Document the verified Linux smoke-suite result for the AFP Set File Information metadata rights gate. The suite now uses the existing ncpfs trustee utilities to grant NOPASSUSER only read/file-scan rights on the smoke file, then verifies that FinderInfo, Invisible, and System metadata writes are rejected with completion 0x8c while the SUPERVISOR positive path remains green. This records the intended WebSDK/NWAFP adapter semantics: AFP-specific xattrs remain the storage for FinderInfo and AFP-only metadata bits, but writes to those xattrs are still file metadata changes and must pass mars_nwe's NetWare Modify trustee policy instead of bypassing it. Tests: - afp_smoke_suite.sh --readonly-user NOPASSUSER --readonly-no-password --prepare-readonly-rights - FinderInfo negative Set File Information -> 0x8c - Invisible negative Set File Information -> 0x8c - System negative Set File Information -> 0x8c - final nwrevoke cleanup succeeds - suite summary failures=0
792 lines
37 KiB
Markdown
792 lines
37 KiB
Markdown
# Linux NCP smoke tests
|
|
|
|
This directory contains optional Linux-side integration tests for endpoints that
|
|
are easier to exercise from a Unix host than from the DOS test utilities.
|
|
|
|
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
|
|
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
|
|
metadata stays under `org.mars-nwe.afp.*` while NetWare-core metadata uses
|
|
`org.mars-nwe.netware.*`. On Linux the local xattr helper stores those through
|
|
the portable `user.` namespace, matching Netatalk's `org.netatalk.*` EA
|
|
abstraction style.
|
|
|
|
Build with:
|
|
|
|
```sh
|
|
cmake -DMARS_NWE_BUILD_LINUX_TESTS=ON ...
|
|
cmake --build . --target afp_entry_id_smoke
|
|
cmake --build . --target afp_file_info_smoke
|
|
cmake --build . --target afp_scan_info_smoke
|
|
cmake --build . --target afp_temp_dir_handle_smoke
|
|
cmake --build . --target afp_set_file_info_smoke
|
|
```
|
|
|
|
|
|
## AFP smoke-suite report helper
|
|
|
|
`afp_smoke_suite.sh` runs the currently verified AFP Linux smoke helpers as one
|
|
collectable report. It is meant for interactive runtime validation after a
|
|
server rebuild: the script prints each helper with the password masked, captures
|
|
new AFP lines appended to the mars_nwe server log while the suite runs, and
|
|
adds `getfattr -e hex` checks for the mars_nwe AFP xattrs on the tested Unix
|
|
file.
|
|
|
|
When `MARS_NWE_BUILD_LINUX_TESTS=ON` is enabled, CMake copies the helper into
|
|
the build `tests/linux` directory through the `afp_smoke_suite` build target.
|
|
This keeps the runtime copy in sync with source changes, and `cmake --build
|
|
<build-dir> --target clean` removes the copied script so stale suite helpers do
|
|
not survive clean rebuilds.
|
|
|
|
Example from the build `tests/linux` directory:
|
|
|
|
```sh
|
|
./afp_smoke_suite.sh \
|
|
-S MARS -U SUPERVISOR -P secret \
|
|
--path SYS:PUBLIC/pmdflts.ini \
|
|
--unix-path /var/mars_nwe/SYS/public/pmdflts.ini \
|
|
--log /var/log/mars_nwe/nw.log \
|
|
--out /tmp/mars-afp-smoke.txt
|
|
```
|
|
|
|
The report includes AFP Entry ID, Entry ID From NetWare Handle, Get File
|
|
Information, Scan File Information, Alloc Temporary Directory Handle, Open File
|
|
Fork, FinderInfo Set File Information for both AFP 2.0 (`0x10`) and the legacy AFP
|
|
Set File Information (`0x09`), AFP 2.0 Invisible/System/Archive Set/Clear File
|
|
Information, legacy AFP `0x09` Invisible Set/Clear coverage, and the Linux xattr
|
|
checks for:
|
|
|
|
```text
|
|
user.org.mars-nwe.afp.finder-info
|
|
user.org.mars-nwe.afp.attributes
|
|
user.org.mars-nwe.afp.entry-id
|
|
```
|
|
|
|
|
|
The suite now also exercises the additional metadata-only AFP attribute bits that
|
|
`afp_set_file_info_smoke` supports: System (`0x0004`) and Archive (`0x0040`).
|
|
It additionally runs the legacy AFP `0x09` path for FinderInfo and the Invisible
|
|
attribute so both Set File Information entry points cover the metadata write
|
|
path. It clears each attribute bit again before the final xattr dump so repeated
|
|
runs leave the attribute payload in the clean `0x01000000` state unless a
|
|
previous command fails.
|
|
|
|
Use `--no-log` when the log file is unavailable or when the server log is being
|
|
collected separately. Use `--stop-on-failure` for strict bisect-style runs; by
|
|
default the script keeps going so one failing endpoint does not hide later AFP
|
|
output from the report.
|
|
|
|
The suite can optionally exercise the Modify-rights negative path with a second
|
|
user. For a no-password test user such as `NOPASSUSER`, run from the build
|
|
`tests/linux` directory:
|
|
|
|
```sh
|
|
./afp_smoke_suite.sh \
|
|
-S MARS -U SUPERVISOR -P secret \
|
|
--path SYS:PUBLIC/pmdflts.ini \
|
|
--unix-path /var/mars_nwe/SYS/public/pmdflts.ini \
|
|
--readonly-user NOPASSUSER --readonly-no-password \
|
|
--prepare-readonly-rights \
|
|
--out /tmp/mars-afp-smoke.txt
|
|
```
|
|
|
|
`--prepare-readonly-rights` uses the standard ncpfs trustee utilities instead
|
|
of ad-hoc test NCPs: it calls `nwrevoke` to remove any explicit assignment for
|
|
the readonly user on the smoke file, then `nwgrant -r '[RF]'` to grant read and
|
|
file-scan rights without Modify. After the negative probes it runs `nwrevoke`
|
|
again so the file returns to inherited rights. Use this only on smoke files or
|
|
paths where removing an explicit trustee assignment for the readonly test user
|
|
is acceptable.
|
|
|
|
AFP metadata writes and NetWare Modify rights:
|
|
|
|
FinderInfo and AFP-only attribute metadata are stored in `org.mars-nwe.afp.*`
|
|
xattrs, but those writes are still file metadata changes. The Set File
|
|
Information handler now resolves the target through the normal mars_nwe path and
|
|
checks the existing NetWare Modify trustee policy before updating FinderInfo or
|
|
AFP-only Invisible/System metadata. Archive uses the existing NetWare attribute
|
|
path, and Modify timestamp uses `nw_utime_node()`, so the smoke suite should
|
|
continue to pass for SUPERVISOR while non-supervisor negative coverage can later
|
|
exercise the same policy gate.
|
|
|
|
A verified rights-negative smoke run with `--readonly-user NOPASSUSER`,
|
|
`--readonly-no-password`, and `--prepare-readonly-rights` completed with
|
|
`failures=0`. The setup used `nwgrant -r '[RF]'` for the no-password test
|
|
user so the file remained readable and searchable but lacked Modify rights.
|
|
The suite then verified that AFP Set File Information rejects FinderInfo,
|
|
Invisible, and System metadata writes with completion `0x8c` while the
|
|
SUPERVISOR positive path still succeeds:
|
|
|
|
```text
|
|
AFP metadata Modify rights rejected: FinderInfo
|
|
AFP Set File Information returned expected completion 0x8c: subfunction=0x10 path=SYS:PUBLIC/pmdflts.ini bitmap=0x0020
|
|
AFP metadata Modify rights rejected: Invisible
|
|
AFP Set File Information returned expected completion 0x8c: subfunction=0x10 path=SYS:PUBLIC/pmdflts.ini bitmap=0x0001
|
|
AFP metadata Modify rights rejected: System
|
|
AFP Set File Information returned expected completion 0x8c: subfunction=0x10 path=SYS:PUBLIC/pmdflts.ini bitmap=0x0001
|
|
```
|
|
|
|
The server log for the same run showed the common policy gate for all three
|
|
probes:
|
|
|
|
```text
|
|
AFP 2.0 Set File Information rejected: no Modify rights for AFP metadata path='SYS:PUBLIC/pmdflts.ini'
|
|
```
|
|
|
|
The final `nwrevoke` cleanup returned successfully, and the final xattr/stat
|
|
checks remained intact. An initial pre-cleanup `nwrevoke` may report that no
|
|
explicit assignment existed yet; that is harmless as long as `nwgrant` and the
|
|
final cleanup both succeed.
|
|
|
|
A verified suite run after the FinderInfo payload-alignment fix completed with
|
|
`failures=0` for `SYS:PUBLIC/pmdflts.ini`. The report covered Entry ID by path,
|
|
Entry ID from NetWare handle, Get File Information, Scan File Information,
|
|
Alloc Temporary Directory Handle, Open File Fork, FinderInfo Set File
|
|
Information, and Finder Invisible set/clear. The relevant Linux xattr checks
|
|
from that run were:
|
|
|
|
```text
|
|
user.org.mars-nwe.afp.finder-info=0x544558544d415253000000000000000000000000000000000000000000000000
|
|
user.org.mars-nwe.afp.attributes=0x01000000
|
|
user.org.mars-nwe.afp.entry-id=0x0100000033f9a1ed
|
|
```
|
|
|
|
The FinderInfo value starts with `TEXTMARS` without a leading padding byte, so
|
|
the smoke helper and server now agree on the WebSDK/NWAFP Set File Information
|
|
payload alignment. The server log excerpt for the same run showed all AFP
|
|
operations returning successfully, including `mask=0x0020` for FinderInfo and
|
|
`mask=0x0001` for the Invisible/System/Archive attribute probes.
|
|
|
|
|
|
A later full-suite run after the smoke-suite copy/sync fix also completed with
|
|
`failures=0` from the build-tree script and confirmed that the legacy AFP Set
|
|
File Information endpoint (`0x09`) is exercised in the same report as AFP 2.0
|
|
`0x10`. The run covered legacy FinderInfo, legacy Invisible set/clear, AFP 2.0
|
|
System set/clear, and AFP 2.0 Archive set/clear while leaving the final AFP
|
|
metadata attributes xattr clear:
|
|
|
|
```text
|
|
AFP Set File Info subfunction=0x09 path=SYS:PUBLIC/pmdflts.ini bitmap=0x0020 attrs=0x0000 finder_type=TEXT finder_creator=MARS entry_id=0x1ad06d3e verified
|
|
AFP Set File Info subfunction=0x09 path=SYS:PUBLIC/pmdflts.ini bitmap=0x0001 attrs=0x0001 finder_type=TEXT finder_creator=MARS entry_id=0x1ad06d3e verified
|
|
AFP Set File Info subfunction=0x09 path=SYS:PUBLIC/pmdflts.ini bitmap=0x0001 attrs=0x0000 finder_type=TEXT finder_creator=MARS entry_id=0x1ad06d3e verified
|
|
AFP Set File Info subfunction=0x10 path=SYS:PUBLIC/pmdflts.ini bitmap=0x0001 attrs=0x0004 finder_type=TEXT finder_creator=MARS entry_id=0x1ad06d3e verified
|
|
AFP Set File Info subfunction=0x10 path=SYS:PUBLIC/pmdflts.ini bitmap=0x0001 attrs=0x0000 finder_type=TEXT finder_creator=MARS entry_id=0x1ad06d3e verified
|
|
AFP Set File Info subfunction=0x10 path=SYS:PUBLIC/pmdflts.ini bitmap=0x0001 attrs=0x0040 finder_type=TEXT finder_creator=MARS entry_id=0x1ad06d3e verified
|
|
AFP Set File Info subfunction=0x10 path=SYS:PUBLIC/pmdflts.ini bitmap=0x0001 attrs=0x0000 finder_type=TEXT finder_creator=MARS entry_id=0x1ad06d3e verified
|
|
user.org.mars-nwe.afp.finder-info=0x544558544d415253000000000000000000000000000000000000000000000000
|
|
user.org.mars-nwe.afp.attributes=0x01000000
|
|
user.org.mars-nwe.afp.entry-id=0x010000001ad06d3e
|
|
```
|
|
|
|
## AFP Entry ID smoke test
|
|
|
|
`afp_entry_id_smoke` sends the WebSDK-documented NetWare AFP request:
|
|
|
|
```text
|
|
NCP 0x2222/35/12 AFP Get Entry ID From Path Name
|
|
```
|
|
|
|
It uses libncp's `NWRequestSimple()` path, so it goes through the same client
|
|
transport stack as other Linux ncpfs utilities.
|
|
|
|
Example:
|
|
|
|
```sh
|
|
./tests/linux/afp_entry_id_smoke -S MARS -U SUPERVISOR -P secret SYS:PUBLIC
|
|
```
|
|
|
|
The test accepts NetWare-style `VOL:PATH` arguments. By default it sends the
|
|
supplied `SYS:`-style path directly with directory handle 0, matching the
|
|
verified mars_nwe smoke-test path. `--alloc-handle` is available only for
|
|
follow-up debugging of the separate directory-handle allocation path, and
|
|
`--dir-handle N` expects a handle that is valid in the current connection.
|
|
|
|
Useful smoke cases for a standard MARS-NWE `SYS` volume are:
|
|
|
|
```sh
|
|
./tests/linux/afp_entry_id_smoke -S MARS -U SUPERVISOR -P secret SYS:
|
|
./tests/linux/afp_entry_id_smoke -S MARS -U SUPERVISOR -P secret SYS:PUBLIC
|
|
./tests/linux/afp_entry_id_smoke -S MARS -U SUPERVISOR -P secret SYS:SYSTEM
|
|
./tests/linux/afp_entry_id_smoke -S MARS -U SUPERVISOR -P secret SYS:BURST
|
|
```
|
|
|
|
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.
|
|
|
|
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
|
|
negative smoke test, use:
|
|
|
|
```sh
|
|
./tests/linux/afp_entry_id_smoke --allow-invalid-namespace -S MARS -U SUPERVISOR -P secret SYS:PUBLIC
|
|
```
|
|
|
|
For path-resolution negative tests, use `--allow-invalid-path` to accept the
|
|
expected `0x9c` Invalid Path completion.
|
|
|
|
|
|
### AFP Get Entry ID From Name
|
|
|
|
`afp_entry_id_smoke` can also exercise the WebSDK-documented NetWare AFP
|
|
request:
|
|
|
|
```text
|
|
NCP 0x2222/35/04 AFP Get Entry ID From Name
|
|
```
|
|
|
|
Use `--from-name` to select this subfunction. The current mars_nwe
|
|
implementation supports the same verified path-backed smoke mode as
|
|
`AFP Get Entry ID From Path Name`: pass a raw `SYS:`-style path with directory
|
|
handle 0 and base Entry ID 0.
|
|
|
|
Useful smoke cases for a standard MARS-NWE `SYS` volume are:
|
|
|
|
```sh
|
|
./tests/linux/afp_entry_id_smoke --from-name -S MARS -U SUPERVISOR -P secret SYS:
|
|
./tests/linux/afp_entry_id_smoke --from-name -S MARS -U SUPERVISOR -P secret SYS:PUBLIC
|
|
./tests/linux/afp_entry_id_smoke --from-name -S MARS -U SUPERVISOR -P secret SYS:SYSTEM
|
|
./tests/linux/afp_entry_id_smoke --from-name -S MARS -U SUPERVISOR -P secret SYS:BURST
|
|
```
|
|
|
|
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.
|
|
|
|
### AFP Get Entry ID From NetWare Handle
|
|
|
|
`afp_entry_id_smoke` can also exercise the WebSDK-documented NetWare AFP
|
|
request:
|
|
|
|
```text
|
|
NCP 0x2222/35/06 AFP Get Entry ID From NetWare Handle
|
|
```
|
|
|
|
Use `--from-handle` to select this subfunction. The smoke test opens the
|
|
requested file through libncp in the same connection, passes the returned
|
|
6-byte NetWare file handle to the AFP request, and closes the file after the
|
|
AFP reply. This is important because NetWare file handles are connection-local:
|
|
`--dir-handle N` and file-handle values copied from server logs or unrelated
|
|
helper processes are not stable inputs for this request.
|
|
|
|
Useful smoke cases for a standard MARS-NWE `SYS:PUBLIC` directory are:
|
|
|
|
```sh
|
|
./tests/linux/afp_entry_id_smoke --from-handle -S MARS -U SUPERVISOR -P secret SYS:PUBLIC/pmdflts.ini
|
|
./tests/linux/afp_entry_id_smoke --from-handle -S MARS -U SUPERVISOR -P secret SYS:PUBLIC/ohlogscr.bat
|
|
```
|
|
|
|
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:
|
|
|
|
```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
|
|
```
|
|
|
|
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.
|
|
|
|
## AFP Alloc Temporary Directory Handle smoke test
|
|
|
|
`afp_temp_dir_handle_smoke` sends the WebSDK-documented NetWare AFP request:
|
|
|
|
```text
|
|
NCP 0x2222/35/11 AFP Alloc Temporary Directory Handle
|
|
```
|
|
|
|
The request layout is the AFP volume number, base AFP Entry ID, path length,
|
|
and AFP-style path. The current mars_nwe implementation supports the same
|
|
conservative path-backed subset as the Entry ID and File Information probes:
|
|
pass a raw `VOL:`-style path such as `SYS:` or `HOME:` and keep the
|
|
base Entry ID at zero. The compatibility server resolves the effective
|
|
NetWare volume from that path prefix instead of assuming volume 0; the request
|
|
volume byte is retained for WebSDK/header shape and for later Entry-ID-relative
|
|
lookup work. Pure Entry-ID-relative allocation is still rejected with Invalid
|
|
Path until persistent CNID/base-ID lookup exists.
|
|
|
|
Useful smoke cases for a standard MARS-NWE `SYS` volume are:
|
|
|
|
```sh
|
|
./tests/linux/afp_temp_dir_handle_smoke -S MARS -U SUPERVISOR -P secret SYS:
|
|
./tests/linux/afp_temp_dir_handle_smoke -S MARS -U SUPERVISOR -P secret SYS:PUBLIC
|
|
./tests/linux/afp_temp_dir_handle_smoke -S MARS -U SUPERVISOR -P secret SYS:SYSTEM
|
|
./tests/linux/afp_temp_dir_handle_smoke -S MARS -U SUPERVISOR -P secret SYS:BURST
|
|
```
|
|
|
|
On installations with another exported volume, the same helper can be run
|
|
against that raw prefix, for example `HOME:`. The server log should then show
|
|
the resolved volume number for `HOME:` rather than hard-coded `vol=0`.
|
|
|
|
A successful reply prints the allocated temporary NetWare directory handle and
|
|
the effective-rights mask returned by the server. The smoke helper immediately
|
|
deallocates the handle with the normal NetWare Deallocate Directory Handle call
|
|
before closing the connection, so the handle value is only useful inside that
|
|
client connection and must not be copied into later tests or server logs.
|
|
|
|
Runtime-verified output and server diagnostic shape:
|
|
|
|
```text
|
|
AFP Alloc Temporary Dir Handle path=SYS: dir_handle=2 rights=0xff
|
|
AFP Alloc Temporary Dir Handle path=SYS:PUBLIC dir_handle=2 rights=0xff
|
|
AFP Alloc Temporary Dir Handle path=SYS:SYSTEM dir_handle=2 rights=0xff
|
|
AFP Alloc Temporary Dir Handle path=SYS:BURST dir_handle=2 rights=0xff
|
|
AFP Alloc Temporary Dir Handle: vol=0 request_vol=0 entry=0x00000000 path='SYS:' dir_handle=2 rights=0x1ff
|
|
AFP Alloc Temporary Dir Handle: vol=0 request_vol=0 entry=0x00000000 path='SYS:PUBLIC' dir_handle=2 rights=0x1ff
|
|
AFP Alloc Temporary Dir Handle: vol=0 request_vol=0 entry=0x00000000 path='SYS:SYSTEM' dir_handle=2 rights=0x1ff
|
|
AFP Alloc Temporary Dir Handle: vol=0 request_vol=0 entry=0x00000000 path='SYS:BURST' dir_handle=2 rights=0x1ff
|
|
```
|
|
|
|
The AFP reply carries the one-byte access-rights field consumed by the smoke
|
|
helper, so the client prints `0xff`. The server diagnostic logs the internal
|
|
NetWare effective-rights mask before that AFP reply narrowing, so a fully
|
|
privileged directory can appear as `0x1ff` in `mars_nwe.log`.
|
|
|
|
If the server was built without the optional Netatalk/libatalk backend, use
|
|
`--allow-invalid-namespace` for the expected negative test. Use
|
|
`--allow-invalid-path` for path-resolution negative tests.
|
|
|
|
|
|
## AFP Open File Fork smoke test
|
|
|
|
`afp_open_file_fork_smoke` sends the WebSDK-documented NetWare AFP open fork
|
|
request:
|
|
|
|
```text
|
|
NCP 0x2222/35/08 AFP Open File Fork
|
|
```
|
|
|
|
The first mars_nwe implementation is deliberately conservative. It supports
|
|
raw `VOL:`-style path requests such as `SYS:` or `HOME:` with base Entry ID
|
|
zero, opens only the AFP data fork, and only for read access. For path-backed
|
|
requests, mars_nwe resolves the effective NetWare volume from the raw path
|
|
prefix instead of assuming volume 0. On success the server returns the
|
|
normal six-byte NetWare file handle shape used by AFP handle APIs plus the
|
|
current data-fork length. The smoke helper immediately closes the returned
|
|
NetWare file handle in the same connection.
|
|
|
|
Useful smoke cases for a standard MARS-NWE `SYS` volume are:
|
|
|
|
```sh
|
|
./tests/linux/afp_open_file_fork_smoke -S MARS -U SUPERVISOR -P secret SYS:PUBLIC/pmdflts.ini
|
|
./tests/linux/afp_open_file_fork_smoke -S MARS -U SUPERVISOR -P secret SYS:PUBLIC/ohlogscr.bat
|
|
```
|
|
|
|
A file on another exported volume should be tested with its raw volume prefix
|
|
(for example `HOME:...`). The matching server log should report that resolved
|
|
volume number, while still showing the request volume byte separately.
|
|
|
|
A successful reply prints the returned NetWare handle, the requested fork, the
|
|
read access mode, and the data-fork length. A verified runtime smoke run
|
|
against the standard DOS utility files produced:
|
|
|
|
```text
|
|
AFP Open File Fork path=SYS:PUBLIC/pmdflts.ini handle=1 fork=0 access=0x01 fork_len=8161
|
|
AFP Open File Fork path=SYS:PUBLIC/ohlogscr.bat handle=1 fork=0 access=0x01 fork_len=1296
|
|
```
|
|
|
|
The matching server log records the path-backed open and the same data-fork
|
|
lengths:
|
|
|
|
```text
|
|
AFP Open File Fork: vol=0 request_vol=0 entry=0x00000000 fork=0 access=0x01 path='SYS:PUBLIC/pmdflts.ini' handle=1 fork_len=8161
|
|
AFP Open File Fork: vol=0 request_vol=0 entry=0x00000000 fork=0 access=0x01 path='SYS:PUBLIC/ohlogscr.bat' handle=1 fork_len=1296
|
|
```
|
|
|
|
The exact handle number is connection-local and must not be reused across
|
|
processes. The exact `fork_len` depends on the backing file contents.
|
|
Resource-fork opens (`--fork 1`), write access (`--access 2`), and
|
|
Entry-ID-only open remain unsupported until persistent CNID/base-ID lookup,
|
|
AppleDouble/resource-fork, and AFP write-open semantics are available. The
|
|
smoke helper can assert those conservative rejections explicitly:
|
|
|
|
```sh
|
|
./tests/linux/afp_open_file_fork_smoke --expect-completion 0x84 --access 0x02 -S MARS -U SUPERVISOR -P secret SYS:PUBLIC/pmdflts.ini
|
|
./tests/linux/afp_open_file_fork_smoke --expect-completion 0x9c --fork 1 -S MARS -U SUPERVISOR -P secret SYS:PUBLIC/pmdflts.ini
|
|
```
|
|
|
|
A rejected write-open probe should print:
|
|
|
|
```text
|
|
AFP Open File Fork returned expected completion 0x84: path=SYS:PUBLIC/pmdflts.ini fork=0 access=0x02
|
|
```
|
|
|
|
A rejected resource-fork probe should print:
|
|
|
|
```text
|
|
AFP Open File Fork returned expected completion 0x9c: path=SYS:PUBLIC/pmdflts.ini fork=1 access=0x01
|
|
```
|
|
|
|
If the server was built without the optional Netatalk/libatalk backend, use
|
|
`--allow-invalid-namespace` for the expected negative test. Use
|
|
`--allow-invalid-path` for path-resolution or Entry-ID-only negative tests.
|
|
|
|
## AFP File Information smoke test
|
|
|
|
`afp_file_info_smoke` sends the WebSDK-documented NetWare AFP file
|
|
information requests:
|
|
|
|
```text
|
|
NCP 0x2222/35/05 AFP Get File Information
|
|
NCP 0x2222/35/15 AFP 2.0 Get File Information
|
|
```
|
|
|
|
It uses the same libncp `NWRequestSimple()` transport path as the Entry ID
|
|
smoke test and sends raw `SYS:`-style path requests with directory handle 0.
|
|
The server replies with the read-only AFP file information record currently
|
|
implemented by mars_nwe: Entry ID, Parent ID, attributes, data/resource fork
|
|
lengths, offspring count, fixed long/short names, and access rights.
|
|
|
|
Useful smoke cases for a standard MARS-NWE `SYS` volume are:
|
|
|
|
```sh
|
|
./tests/linux/afp_file_info_smoke -S MARS -U SUPERVISOR -P secret SYS:
|
|
./tests/linux/afp_file_info_smoke -S MARS -U SUPERVISOR -P secret SYS:PUBLIC
|
|
./tests/linux/afp_file_info_smoke -S MARS -U SUPERVISOR -P secret SYS:SYSTEM
|
|
./tests/linux/afp_file_info_smoke -S MARS -U SUPERVISOR -P secret SYS:BURST
|
|
|
|
# AFP 2.0 variant using the same path-backed read-only reply
|
|
./tests/linux/afp_file_info_smoke --afp20 -S MARS -U SUPERVISOR -P secret SYS:
|
|
./tests/linux/afp_file_info_smoke --afp20 -S MARS -U SUPERVISOR -P secret SYS:PUBLIC
|
|
./tests/linux/afp_file_info_smoke --afp20 -S MARS -U SUPERVISOR -P secret SYS:SYSTEM
|
|
./tests/linux/afp_file_info_smoke --afp20 -S MARS -U SUPERVISOR -P secret SYS:BURST
|
|
```
|
|
|
|
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.
|
|
|
|
If the server was built without the optional Netatalk/libatalk backend, use
|
|
`--allow-invalid-namespace` for the expected negative test. Use
|
|
`--allow-invalid-path` for path-resolution negative tests.
|
|
|
|
## AFP Scan File Information smoke test
|
|
|
|
`afp_scan_info_smoke` sends the WebSDK-documented NetWare AFP scan requests:
|
|
|
|
```text
|
|
NCP 0x2222/35/10 AFP Scan File Information
|
|
NCP 0x2222/35/17 AFP 2.0 Scan File Information
|
|
```
|
|
|
|
The helper defaults to the AFP 2.0 subfunction (`0x11`) and uses `--afp10`
|
|
to exercise the older `0x0a` endpoint. Both variants include the documented
|
|
DesiredResponseCount word; mars_nwe currently returns one path-backed read-only
|
|
entry per request, using the same AFP file information record as
|
|
`afp_file_info_smoke`. The test sends raw `SYS:`-style path requests with
|
|
directory handle 0 and uses the returned `next_last_seen` AFP Entry ID as the
|
|
continuation token for the next call.
|
|
|
|
Useful smoke sequence for a standard MARS-NWE `SYS:PUBLIC` directory:
|
|
|
|
```sh
|
|
./tests/linux/afp_scan_info_smoke -S MARS -U SUPERVISOR -P secret SYS:PUBLIC
|
|
./tests/linux/afp_scan_info_smoke --afp10 -S MARS -U SUPERVISOR -P secret SYS:PUBLIC
|
|
./tests/linux/afp_scan_info_smoke -S MARS -U SUPERVISOR -P secret --last-seen 0x260437f6 SYS:PUBLIC
|
|
./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:
|
|
|
|
```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
|
|
```
|
|
|
|
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
|
|
```
|
|
|
|
```text
|
|
user.org.mars-nwe.afp.entry-id=0x010000007b9c42e1
|
|
user.org.mars-nwe.afp.entry-id=0x010000006686342b
|
|
```
|
|
|
|
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
|
|
until that object is seen and then return the next directory entry. Therefore
|
|
the next returned Entry ID is not guaranteed to be numerically greater than the
|
|
`last_seen` value; in the verified run, `last_seen=0x6686342b` returns
|
|
`pmail.bat` with `entry_id=0x2d12d99c`. The older `0x0a` path intentionally
|
|
shares the same conservative scan implementation so older AFP callers can probe
|
|
the same read-only directory listing semantics before fuller multi-response and
|
|
CNID-backed scans are implemented.
|
|
|
|
If the server was built without the optional Netatalk/libatalk backend, use
|
|
`--allow-invalid-namespace` for the expected negative test. Use
|
|
`--allow-invalid-path` for path-resolution negative tests, and `--allow-empty`
|
|
when a scan continuation is expected to reach the end of the directory.
|
|
|
|
|
|
## AFP Set File Information metadata smoke test
|
|
|
|
`afp_set_file_info_smoke` sends the WebSDK-documented NetWare AFP Set File
|
|
Information requests. It defaults to the AFP 2.0 subfunction and can exercise
|
|
the older AFP subfunction with `--afp09`:
|
|
|
|
```text
|
|
NCP 0x2222/35/09 AFP Set File Information
|
|
NCP 0x2222/35/16 AFP 2.0 Set File Information
|
|
```
|
|
|
|
The helper exercises two deliberately narrow write-safe AFP metadata subsets:
|
|
the file FinderInfo bitmap (`0x0020`), the file Attributes bitmap (`0x0001`)
|
|
restricted to metadata-only file flags: Finder Invisible, System, and Archive,
|
|
and the file modification timestamp bitmap (`0x0010`). It sends path-backed
|
|
raw `VOL:`-style requests, writes the 32-byte FinderInfo block to mars_nwe's
|
|
private `org.mars-nwe.afp.finder-info` metadata key, writes the narrow AFP
|
|
attribute word to `org.mars-nwe.afp.attributes`, routes modification timestamp
|
|
writes through the existing NetWare timestamp helper, and immediately verifies
|
|
the updates through AFP 2.0 Get File Information. On Linux the source-level `org.mars-nwe.afp.*` name is stored via the
|
|
portable `user.` xattr namespace by mars_nwe's local xattr wrapper, the same
|
|
pattern Netatalk uses for its `org.netatalk.*` metadata names.
|
|
|
|
Example:
|
|
|
|
```sh
|
|
./tests/linux/afp_set_file_info_smoke \
|
|
-S MARS -U SUPERVISOR -P secret \
|
|
--type TEXT --creator MARS \
|
|
SYS:PUBLIC/pmdflts.ini
|
|
```
|
|
|
|
|
|
|
|
The same FinderInfo payload can be sent through the older Set File Information
|
|
subfunction:
|
|
|
|
```sh
|
|
./tests/linux/afp_set_file_info_smoke \
|
|
-S MARS -U SUPERVISOR -P secret \
|
|
--afp09 --finder-info-only --type TEXT --creator MARS \
|
|
SYS:PUBLIC/pmdflts.ini
|
|
```
|
|
|
|
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
|
|
```
|
|
|
|
Server diagnostics show the effective resolved volume, the request volume byte,
|
|
the FinderInfo bitmap, and the first eight FinderInfo bytes:
|
|
|
|
```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
|
|
```
|
|
|
|
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
|
|
getfattr -n user.org.mars-nwe.afp.finder-info -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/pmdflts.ini
|
|
```
|
|
|
|
For the verified FinderInfo smoke run, the FinderInfo xattr starts with
|
|
`TEXTMARS`:
|
|
|
|
```text
|
|
user.org.mars-nwe.afp.finder-info=0x544558544d415253000000000000000000000000000000000000000000000000
|
|
```
|
|
|
|
Finder Invisible can be tested without mutating DOS/NetWare mode bits:
|
|
|
|
```sh
|
|
./tests/linux/afp_set_file_info_smoke \
|
|
-S MARS -U SUPERVISOR -P secret \
|
|
--attributes-only --invisible \
|
|
SYS:PUBLIC/pmdflts.ini
|
|
|
|
getfattr -n user.org.mars-nwe.afp.attributes -e hex /var/mars_nwe/SYS/public/pmdflts.ini
|
|
```
|
|
|
|
The xattr payload is versioned. For an invisible file the expected Linux form
|
|
is:
|
|
|
|
```text
|
|
user.org.mars-nwe.afp.attributes=0x01000001
|
|
```
|
|
|
|
Use `--clear-invisible --attributes-only` to clear that bit; the same xattr then
|
|
stores `0x01000000`. The same helper can exercise the two additional
|
|
additional file attribute bits. System remains AFP metadata-only; Archive is
|
|
routed through the existing NetWare file attribute store (`FILE_ATTR_A`) rather
|
|
than the AFP metadata xattr:
|
|
|
|
```sh
|
|
./tests/linux/afp_set_file_info_smoke \
|
|
-S MARS -U SUPERVISOR -P secret \
|
|
--attributes-only --system \
|
|
SYS:PUBLIC/pmdflts.ini
|
|
|
|
./tests/linux/afp_set_file_info_smoke \
|
|
-S MARS -U SUPERVISOR -P secret \
|
|
--attributes-only --archive \
|
|
SYS:PUBLIC/pmdflts.ini
|
|
```
|
|
|
|
For System the AFP metadata xattr stores `0x01000004`. Archive is verified
|
|
through AFP Get File Information after updating the NetWare attribute store; it
|
|
no longer lives in `user.org.mars-nwe.afp.attributes`. Use `--clear-system`
|
|
and `--clear-archive` to remove those bits.
|
|
The older helper spellings `--backup` and `--clear-backup` remain accepted
|
|
as compatibility aliases, but the suite and documentation use Archive because
|
|
this bit is the AFP file attribute, not the separate AFP backup date/time field.
|
|
The helper verifies only the bit that a single probe sets or clears. Other
|
|
stored metadata bits are intentionally preserved, so a run can legitimately
|
|
report a combined attribute word while verifying only the targeted bit.
|
|
|
|
Verified runtime probes for the additional bits showed the expected AFP-visible
|
|
attribute words and server diagnostics. A later full-suite run also confirmed
|
|
that the helper must mask the targeted bit rather than compare the whole
|
|
attribute word: previously stored metadata bits can remain visible, so Invisible set/clear may
|
|
produce a combined attribute word while still being correct for the Invisible
|
|
bit. After Archive was mapped to the existing NetWare `FILE_ATTR_A` store, the
|
|
suite was rerun from the build-tree helper and completed with `failures=0`:
|
|
Archive set reported AFP-visible `attrs=0x0040`, Clear Archive reported
|
|
`attrs=0x0000`, and the final AFP metadata xattr stayed at `0x01000000`, proving
|
|
that Archive no longer lives in `user.org.mars-nwe.afp.attributes`.
|
|
|
|
```text
|
|
AFP Set File Info subfunction=0x10 path=SYS:PUBLIC/pmdflts.ini bitmap=0x0001 attrs=0x0004 finder_type=TEXT finder_creator=MARS entry_id=0x62ecb463 verified
|
|
AFP Set File Info subfunction=0x10 path=SYS:PUBLIC/pmdflts.ini bitmap=0x0001 attrs=0x0000 finder_type=TEXT finder_creator=MARS entry_id=0x62ecb463 verified
|
|
AFP Set File Info subfunction=0x10 path=SYS:PUBLIC/pmdflts.ini bitmap=0x0001 attrs=0x0040 finder_type=TEXT finder_creator=MARS entry_id=0x62ecb463 verified
|
|
AFP 2.0 Set File Information: vol=0 request_vol=0 entry=0x00000000 mask=0x0001 path='SYS:PUBLIC/pmdflts.ini' attributes attrs=0x8004
|
|
AFP 2.0 Set File Information: vol=0 request_vol=0 entry=0x00000000 mask=0x0001 path='SYS:PUBLIC/pmdflts.ini' attributes attrs=0x0004
|
|
AFP Set File Info subfunction=0x10 path=SYS:PUBLIC/pmdflts.ini bitmap=0x0001 attrs=0x0040 modify=0x576eb9aa finder_type=TEXT finder_creator=MARS entry_id=0x399193ed verified
|
|
AFP Set File Info subfunction=0x10 path=SYS:PUBLIC/pmdflts.ini bitmap=0x0001 attrs=0x0000 modify=0x576eb9aa finder_type=TEXT finder_creator=MARS entry_id=0x399193ed verified
|
|
user.org.mars-nwe.afp.attributes=0x01000000
|
|
AFP 2.0 Set File Information: vol=0 request_vol=0 entry=0x00000000 mask=0x0001 path='SYS:PUBLIC/pmdflts.ini' attributes attrs=0x8040
|
|
```
|
|
|
|
Modification timestamp writes are deliberately routed through the existing
|
|
NetWare `nw_utime_node()` path so trustee Modify rights and the established
|
|
`utime(2)` fallback behavior stay shared with classic NCP timestamp updates.
|
|
The first timestamp smoke uses a fixed Unix epoch that the helper converts into
|
|
the AFP/NW DOS date+time fields and verifies through the follow-up Get File
|
|
Information response:
|
|
|
|
```sh
|
|
./tests/linux/afp_set_file_info_smoke \
|
|
-S MARS -U SUPERVISOR -P secret \
|
|
--timestamp-only --mtime-epoch 1700000000 \
|
|
SYS:PUBLIC/pmdflts.ini
|
|
|
|
stat -c 'mtime_epoch=%Y mtime=%y' /var/mars_nwe/SYS/public/pmdflts.ini
|
|
```
|
|
|
|
This currently remains file-only and path-backed, just like the FinderInfo and
|
|
metadata-attribute Set File Information probes; directory timestamps and
|
|
Entry-ID-only Set File Information are left for later resolver work.
|
|
|
|
The legacy `0x09` endpoint is deliberately routed through the same narrow
|
|
implementation as AFP 2.0 `0x10`; it does not add create, rename, delete,
|
|
directory timestamp, or fork-write semantics.
|
|
|
|
All other Set File Information bitmap bits and AFP attribute bits, including
|
|
NoWrite, NoRename, NoDelete, NoCopy, and the computed data/resource-fork-open
|
|
flags, are intentionally rejected for now. That keeps create/access/backup
|
|
timestamps, DOS/NetWare mode-bit mapping, enforcement, resource-fork, and
|
|
Entry-ID-only write semantics out of this conservative smoke path.
|
|
|
|
If the server was built without the optional Netatalk/libatalk backend, use
|
|
`--allow-invalid-namespace` for the expected negative test. Use
|
|
`--allow-invalid-path` for path-resolution negative tests.
|
|
|
|
## AFP Get DOS Name From Entry ID smoke test
|
|
|
|
`afp_dos_name_smoke` exercises the WebSDK-documented NetWare AFP reverse
|
|
lookup:
|
|
|
|
```text
|
|
NCP 0x2222/35/18 AFP Get DOS Name From Entry ID
|
|
```
|
|
|
|
The request carries the AFP volume number and a 32-bit Macintosh directory
|
|
entry ID. The reply is a one-byte DOS path length followed by the DOS path
|
|
string for the matching entry. The smoke helper first resolves the supplied
|
|
`VOL:PATH` through AFP Get Entry ID From Path Name when `--entry-id` is not
|
|
provided, then calls AFP Get DOS Name From Entry ID and verifies that the
|
|
returned path matches the existing mars_nwe DOS namespace spelling without the
|
|
volume prefix.
|
|
|
|
Example:
|
|
|
|
```sh
|
|
./afp_dos_name_smoke -S MARS -U SUPERVISOR -P secret SYS:PUBLIC/pmdflts.ini
|
|
```
|
|
|
|
Expected output shape:
|
|
|
|
```text
|
|
AFP Get DOS Name From Entry ID volume=0 entry_id=0x440cb9b2 path=PUBLIC/PMDFLTS.INI verified
|
|
```
|
|
|
|
|
|
|
|
A successful post-fix smoke-suite run confirmed the `namedos.c` alias path:
|
|
|
|
```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'
|
|
```
|
|
|
|
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.
|