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. 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
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:
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_create_directory_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:
./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, AFP Create
Directory for both legacy (0x01) and AFP 2.0 (0x0d), Open File
Fork, FinderInfo Set File Information for both AFP 2.0 (0x10) and the legacy AFP
Set File Information (0x09), AFP 2.0 Hidden/System/Archive Set/Clear File
Information, legacy AFP 0x09 Hidden Set/Clear coverage, and the Linux xattr
checks for:
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: Hidden (0x0200), System (0x0400), and Archive (0x2000).
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:
./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 Hidden/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,
Hidden, and System metadata writes with completion 0x8c while the
SUPERVISOR positive path still succeeds:
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:
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 Hidden set/clear. The relevant Linux xattr checks
from that run were:
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 Hidden/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 Hidden set/clear, AFP 2.0
System set/clear, and AFP 2.0 Archive set/clear while leaving the final AFP
metadata attributes xattr clear:
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=0x2000 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 Create Directory smoke test
afp_create_directory_smoke sends the WebSDK/nwafp.h AFP Create Directory
requests through libncp:
NCP 0x2222/35/01 AFP Create Directory
NCP 0x2222/35/0d AFP 2.0 Create Directory
The helper derives the parent Entry ID with the existing AFP Entry ID From Path
Name endpoint, sends only the new leaf name to Create Directory, and verifies
the returned directory ID by looking the created path up again. This exercises
the server-side path through the existing mars_nwe namespace/basehandle mapping
and nw_mk_rd_dir() rather than an AFP-only directory resolver.
Example:
./tests/linux/afp_create_directory_smoke -S MARS -U SUPERVISOR -P secret SYS:PUBLIC/afpdirts
./tests/linux/afp_create_directory_smoke --afp20 -S MARS -U SUPERVISOR -P secret SYS:PUBLIC/afpdirts2
The full smoke suite creates temporary directories under the tested parent and
removes them through the local Unix path after each positive probe. Use
--create-dir-name NAME to override the default temporary leaf name.
AFP Entry ID smoke test
afp_entry_id_smoke sends the WebSDK-documented NetWare AFP request:
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:
./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:
./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. 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 negative smoke test, use:
./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:
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:
./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 and uses the same NetWare namespace/basehandle identity source for path-backed requests.
AFP Get Entry ID From NetWare Handle
afp_entry_id_smoke can also exercise the WebSDK-documented NetWare AFP
request:
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:
./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 derives the Entry ID from the same mars_nwe namespace/basehandle mapping as
path-backed lookups:
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
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
afp_temp_dir_handle_smoke sends the WebSDK-documented NetWare AFP request:
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:
./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:
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:
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:
./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:
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:
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:
./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:
AFP Open File Fork returned expected completion 0x84: path=SYS:PUBLIC/pmdflts.ini fork=0 access=0x02
A rejected resource-fork probe should print:
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:
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.
AFP Get/Scan AccessPrivileges smoke
AFP Get File Information and AFP Scan File Information now derive the
AccessPrivileges word from mars_nwe trustee/effective-rights state instead
of returning the old static compatibility masks. The WebSDK AccessPrivileges
bits exposed by the smoke helpers are:
0x0100 Read
0x0200 Write
0x0400 Open
0x0800 Create
0x1000 Delete
0x2000 Parental
0x4000 Search
0x8000 Modify File Status Flags
The AFP smoke suite exercises this with the same readonly trustee setup used by
the metadata negative tests. With --readonly-user NOPASSUSER,
--readonly-no-password, and --prepare-readonly-rights, the suite grants
[RF] on SYS:PUBLIC/pmdflts.ini and verifies that Get File Information
reports readable/openable rights while write and modify-status rights are not
set:
./afp_file_info_smoke \
--expect-rights-set 0x0100 \
--expect-rights-clear 0x9200 \
-S MARS -U NOPASSUSER -n \
SYS:PUBLIC/pmdflts.ini
Runtime status: the trustee-derived AccessPrivileges smoke run is verified
with failures=0. The report showed the Supervisor Get/Scan replies returning
rights=0x9f00, while the readonly NOPASSUSER probe returned rights=0x0500
under the temporary [RF] trustee assignment and satisfied the set/clear mask
checks.
Useful smoke cases for a standard MARS-NWE SYS volume are:
./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 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
--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:
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:
./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 Entry IDs were
moved onto the existing mars_nwe namespace/basehandle path:
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 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:
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
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:
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: AFP Hidden, 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:
./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:
./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:
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 follow-up Get File Information verification with the same namespace-derived Entry ID:
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
Linux xattr checks for the FinderInfo and cached Entry ID look like this:
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:
user.org.mars-nwe.afp.finder-info=0x544558544d415253000000000000000000000000000000000000000000000000
AFP Hidden can be tested without mutating DOS/NetWare mode bits:
./tests/linux/afp_set_file_info_smoke \
-S MARS -U SUPERVISOR -P secret \
--attributes-only --hidden \
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:
user.org.mars-nwe.afp.attributes=0x01000001
Use --clear-hidden --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:
./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 Hidden 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=0x2000, 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.
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=0x2000 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=0x2000 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:
./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:
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:
./afp_dos_name_smoke -S MARS -U SUPERVISOR -P secret SYS:PUBLIC/pmdflts.ini
Expected output shape:
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 via
the existing mars_nwe namespace/basehandle resolver:
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 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
AFP Set/Get File Information now uses the documented WebSDK bitmaps for the
SetInfo request and for the returned attribute word. SetInfo request bits are
0x0100 for Attributes, 0x1000 for Modify Date/Time, and 0x4000 for
FinderInfo. The attribute word maps Hidden (0x0200) to NetWare
FILE_ATTR_H, System (0x0400) to FILE_ATTR_S, and Archive (0x2000)
to FILE_ATTR_A. The smoke helper keeps --hidden as a compatibility
alias, but the suite uses --hidden / --clear-hidden because the value is the
NetWare/AFP Hidden attribute, not a separate Finder-only xattr.
Runtime status: the WebSDK attribute-bit smoke run is verified with
failures=0. The suite confirmed Hidden set/clear as 0x0200/0x0000,
System set/clear as 0x0400/0x0000, and Archive set/clear as
0x2000/0x0000. It also confirms the SetInfo request bitmaps 0x0100
Attributes, 0x1000 Modify Date/Time, and 0x4000 FinderInfo. Since these
attributes now use the existing NetWare attribute path, the final
user.org.mars-nwe.afp.attributes dump is optional and may report ENODATA;
that is expected when no AFP-only attribute bits remain set.
AFP Backup Date/Time smoke
afp_set_file_info_smoke supports the WebSDK Backup Date/Time request bitmap
0x2000 via:
./afp_set_file_info_smoke \
-S MARS -U SUPERVISOR -P secret \
--backup-time-only --backup-time-epoch 1700000000 \
SYS:PUBLIC/pmdflts.ini
This is intentionally separate from the Archive attribute bit in the Attributes
word. The server stores Backup Date/Time through nwarchive.c and the Linux
suite dumps the corresponding xattr as:
getfattr -n user.org.mars-nwe.netware.archive -e hex /var/mars_nwe/SYS/public/pmdflts.ini
The expected AFP reply shows the same Backup Date/Time at offsets 28/30 of the 120-byte file information record, while Archive/Hidden/System attributes remain mapped through the normal NetWare attribute store.
Runtime status: the Backup Date/Time smoke run is verified with failures=0.
The report showed bitmap=0x2000, backup=0x576eb9aa, and the backing xattr
user.org.mars-nwe.netware.archive=0x01036e57aab900000000 after setting epoch
1700000000.
AFP Access Date/Time smoke
afp_set_file_info_smoke supports the WebSDK Access Date/Time request bitmap
0x0400 via:
./afp_set_file_info_smoke \
-S MARS -U SUPERVISOR -P secret \
--access-time-only --access-time-epoch 1700000000 \
SYS:PUBLIC/pmdflts.ini
The server stores Access Date/Time through the existing POSIX st_atime path,
preserving st_mtime with utime() and enforcing trustee Modify rights before
changing the timestamp. The AFP file-information record exposes the Access
Date at offset 22; no AFP-specific xattr is added for this NetWare-semantic
timestamp.
Runtime status: the Access Date/Time smoke run is verified with failures=0.
The report showed bitmap=0x0400, access=0x576e, and no AFP-only xattr for
this timestamp after setting epoch 1700000000.
AFP Create Date/Time smoke
afp_set_file_info_smoke supports the WebSDK Create Date/Time request bitmap
0x0800 via:
./afp_set_file_info_smoke \
-S MARS -U SUPERVISOR -P secret \
--create-time-only --create-time-epoch 1700000000 \
SYS:PUBLIC/pmdflts.ini
The server stores Create Date/Time through nwarchive.c file-info metadata
(user.org.mars-nwe.netware.fileinfo) using mars_nwe_set_file_info(). The
AFP file-information record exposes the Create Date at offset 20; the matching
Create Time is still persisted in the shared NetWare file-info metadata so
classic NetWare file-info paths can return it. No AFP-specific xattr is added
for this NetWare-semantic timestamp.
Runtime status: the Create Date/Time smoke run is verified with failures=0.
The report showed bitmap=0x0800, create=0x576e, and the backing xattr
user.org.mars-nwe.netware.fileinfo=0x01036e57aab90000000000000000 after
setting epoch 1700000000.