nwconn: align AFP attribute bits with WebSDK
All checks were successful
Source release / source-package (push) Successful in 46s

The WebSDK/NCP AFP File Information records use a distinct SetInfo request bitmap and attribute word.  The previous smoke-oriented implementation reused the low response-bit positions for Set Attributes, Modify Date/Time, FinderInfo, Hidden/Invisible, System, and Archive.  That made the current tests pass, but it was not faithful to the documented header semantics and risked keeping AFP metadata parallel to existing NetWare attributes.

Switch Set File Information to the documented request bitmap values: 0x0100 for Attributes, 0x1000 for Modify Date/Time, and 0x4000 for FinderInfo.  Switch the AFP attribute word to the documented NetWare-style bits: Hidden 0x0200, System 0x0400, Subdirectory 0x1000, and Archive 0x2000.

Map Hidden, System, and Archive through the existing NetWare attribute store via FILE_ATTR_H, FILE_ATTR_S, and FILE_ATTR_A.  This keeps AFP Set/Get/Scan aligned with mars_nwe's existing attribute helper instead of maintaining duplicate AFP-only xattr state.  FinderInfo remains AFP metadata and still uses the Modify-rights gate added earlier.

Update the Linux smoke helper and suite to use --hidden / --clear-hidden while keeping --invisible / --clear-invisible as compatibility aliases.  Document the corrected WebSDK bit values and the convergence rule that NetWare attributes must use mars_nwe NetWare helpers.

Tests: git diff --check; bash -n tests/linux/afp_smoke_suite.sh; gcc -Iinclude -I/mnt/data/stubs -fsyntax-only tests/linux/afp_set_file_info_smoke.c
This commit is contained in:
OpenAI
2026-05-30 15:46:23 +00:00
committed by Mario Fetka
parent fb4934fddc
commit 55fdf64c8e
6 changed files with 122 additions and 94 deletions

View File

@@ -63,8 +63,8 @@ Example from the build `tests/linux` directory:
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
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:
```text
@@ -75,7 +75,7 @@ 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`).
`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
@@ -115,7 +115,7 @@ 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
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.
@@ -125,7 +125,7 @@ A verified rights-negative smoke run with `--readonly-user NOPASSUSER`,
`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
Hidden, and System metadata writes with completion `0x8c` while the
SUPERVISOR positive path still succeeds:
```text
@@ -153,7 +153,7 @@ 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
Information, and Finder Hidden set/clear. The relevant Linux xattr checks
from that run were:
```text
@@ -166,13 +166,13 @@ 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.
`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 Invisible set/clear, 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:
@@ -182,7 +182,7 @@ AFP Set File Info subfunction=0x09 path=SYS:PUBLIC/pmdflts.ini bitmap=0x0001 att
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=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
@@ -569,7 +569,7 @@ 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,
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
@@ -637,12 +637,12 @@ For the verified FinderInfo smoke run, the FinderInfo xattr starts with
user.org.mars-nwe.afp.finder-info=0x544558544d415253000000000000000000000000000000000000000000000000
```
Finder Invisible can be tested without mutating DOS/NetWare mode bits:
AFP Hidden 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 \
--attributes-only --hidden \
SYS:PUBLIC/pmdflts.ini
getfattr -n user.org.mars-nwe.afp.attributes -e hex /var/mars_nwe/SYS/public/pmdflts.ini
@@ -655,7 +655,7 @@ is:
user.org.mars-nwe.afp.attributes=0x01000001
```
Use `--clear-invisible --attributes-only` to clear that bit; the same xattr then
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
@@ -687,21 +687,21 @@ 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
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=0x0040`, Clear Archive reported
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`.
```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 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=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=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
@@ -789,3 +789,14 @@ 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.
### 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.

View File

@@ -23,14 +23,14 @@
#define AFP20_GET_FILE_INFORMATION 0x0f
#define AFP_SET_FILE_INFORMATION 0x09
#define AFP20_SET_FILE_INFORMATION 0x10
#define AFP_ATTRIBUTES_MASK 0x0001
#define AFP_MODIFY_DATE_MASK 0x0010
#define AFP_FINDER_INFO_MASK 0x0020
#define AFP_ATTR_INVISIBLE 0x0001
#define AFP_ATTR_SYSTEM 0x0004
#define AFP_ATTR_ARCHIVE 0x0040
#define AFP_ATTRIBUTES_MASK 0x0100
#define AFP_MODIFY_DATE_MASK 0x1000
#define AFP_FINDER_INFO_MASK 0x4000
#define AFP_ATTR_HIDDEN 0x0200
#define AFP_ATTR_SYSTEM 0x0400
#define AFP_ATTR_ARCHIVE 0x2000
#define AFP_ATTR_SETCLR 0x8000
#define AFP_ATTR_STORED_MASK (AFP_ATTR_INVISIBLE | AFP_ATTR_SYSTEM | AFP_ATTR_ARCHIVE)
#define AFP_ATTR_STORED_MASK (AFP_ATTR_HIDDEN | AFP_ATTR_SYSTEM | AFP_ATTR_ARCHIVE)
#define AFP_REPLY_LEN 120
#define NWE_INVALID_NAMESPACE 0xbf
#define NWE_INVALID_PATH 0x9c
@@ -40,7 +40,7 @@ static void usage(const char *prog)
fprintf(stderr,
"Usage: %s [--afp09|--afp20] [--expect-completion CODE] [--allow-invalid-namespace] [--allow-invalid-path] "
"[--volume N] [--entry-id ID] [--type FOUR] [--creator FOUR] "
"[--invisible|--clear-invisible|--system|--clear-system|--archive|--clear-archive] "
"[--hidden|--clear-hidden|--invisible|--clear-invisible|--system|--clear-system|--archive|--clear-archive] "
"[--mtime-epoch SECONDS] [--finder-info-only|--attributes-only|--timestamp-only] "
"[ncpfs options] PATH\n"
"\n"
@@ -49,7 +49,7 @@ static void usage(const char *prog)
"\n"
"Examples:\n"
" %s -S MARS -U SUPERVISOR -P secret --type TEXT --creator MARS SYS:PUBLIC/pmdflts.ini\n"
" %s -S MARS -U SUPERVISOR -P secret --invisible --attributes-only SYS:PUBLIC/pmdflts.ini\n"
" %s -S MARS -U SUPERVISOR -P secret --hidden --attributes-only SYS:PUBLIC/pmdflts.ini\n"
" %s -S MARS -U SUPERVISOR -P secret --archive --attributes-only SYS:PUBLIC/pmdflts.ini\n"
" %s -S MARS -U SUPERVISOR -P secret --mtime-epoch 1700000000 --timestamp-only SYS:PUBLIC/pmdflts.ini\n"
" %s --allow-invalid-namespace -S MARS SYS:PUBLIC/pmdflts.ini\n"
@@ -226,15 +226,15 @@ int main(int argc, char **argv)
ncp_close(conn);
return 2;
}
} else if (!strcmp(argv[i], "--invisible")) {
} else if (!strcmp(argv[i], "--hidden") || !strcmp(argv[i], "--invisible")) {
request_mask |= AFP_ATTRIBUTES_MASK;
attr_request = AFP_ATTR_SETCLR | AFP_ATTR_INVISIBLE;
attr_verify_mask = AFP_ATTR_INVISIBLE;
attr_expected = AFP_ATTR_INVISIBLE;
} else if (!strcmp(argv[i], "--clear-invisible")) {
attr_request = AFP_ATTR_SETCLR | AFP_ATTR_HIDDEN;
attr_verify_mask = AFP_ATTR_HIDDEN;
attr_expected = AFP_ATTR_HIDDEN;
} else if (!strcmp(argv[i], "--clear-hidden") || !strcmp(argv[i], "--clear-invisible")) {
request_mask |= AFP_ATTRIBUTES_MASK;
attr_request = AFP_ATTR_INVISIBLE;
attr_verify_mask = AFP_ATTR_INVISIBLE;
attr_request = AFP_ATTR_HIDDEN;
attr_verify_mask = AFP_ATTR_HIDDEN;
attr_expected = 0;
} else if (!strcmp(argv[i], "--system")) {
request_mask |= AFP_ATTRIBUTES_MASK;

View File

@@ -339,28 +339,28 @@ run_cmd \
--afp09 --finder-info-only --type "$FINDER_TYPE" --creator "$FINDER_CREATOR" "$NETWARE_PATH"
run_cmd \
"AFP Set File Information Invisible" \
"./afp_set_file_info_smoke $COMMON_PRINT --attributes-only --invisible '$NETWARE_PATH'" \
"AFP Set File Information Hidden" \
"./afp_set_file_info_smoke $COMMON_PRINT --attributes-only --hidden '$NETWARE_PATH'" \
"$SCRIPT_DIR/afp_set_file_info_smoke" -S "$SERVER" -U "$USER_NAME" -P "$PASSWORD" \
--attributes-only --invisible "$NETWARE_PATH"
--attributes-only --hidden "$NETWARE_PATH"
run_cmd \
"AFP Set File Information Clear Invisible" \
"./afp_set_file_info_smoke $COMMON_PRINT --attributes-only --clear-invisible '$NETWARE_PATH'" \
"AFP Set File Information Clear Hidden" \
"./afp_set_file_info_smoke $COMMON_PRINT --attributes-only --clear-hidden '$NETWARE_PATH'" \
"$SCRIPT_DIR/afp_set_file_info_smoke" -S "$SERVER" -U "$USER_NAME" -P "$PASSWORD" \
--attributes-only --clear-invisible "$NETWARE_PATH"
--attributes-only --clear-hidden "$NETWARE_PATH"
run_cmd \
"AFP Set File Information Invisible legacy" \
"./afp_set_file_info_smoke $COMMON_PRINT --afp09 --attributes-only --invisible '$NETWARE_PATH'" \
"AFP Set File Information Hidden legacy" \
"./afp_set_file_info_smoke $COMMON_PRINT --afp09 --attributes-only --hidden '$NETWARE_PATH'" \
"$SCRIPT_DIR/afp_set_file_info_smoke" -S "$SERVER" -U "$USER_NAME" -P "$PASSWORD" \
--afp09 --attributes-only --invisible "$NETWARE_PATH"
--afp09 --attributes-only --hidden "$NETWARE_PATH"
run_cmd \
"AFP Set File Information Clear Invisible legacy" \
"./afp_set_file_info_smoke $COMMON_PRINT --afp09 --attributes-only --clear-invisible '$NETWARE_PATH'" \
"AFP Set File Information Clear Hidden legacy" \
"./afp_set_file_info_smoke $COMMON_PRINT --afp09 --attributes-only --clear-hidden '$NETWARE_PATH'" \
"$SCRIPT_DIR/afp_set_file_info_smoke" -S "$SERVER" -U "$USER_NAME" -P "$PASSWORD" \
--afp09 --attributes-only --clear-invisible "$NETWARE_PATH"
--afp09 --attributes-only --clear-hidden "$NETWARE_PATH"
run_cmd \
"AFP Set File Information Modify Timestamp" \
@@ -407,11 +407,11 @@ if [ -n "$READONLY_USER" ]; then
-S "$SERVER" -U "$READONLY_USER" "${READONLY_AUTH_ARGS[@]}" \
--finder-info-only --type "$FINDER_TYPE" --creator "$FINDER_CREATOR" "$NETWARE_PATH"
run_cmd \
"AFP metadata Modify rights rejected: Invisible" \
"./afp_set_file_info_smoke --expect-completion 0x8c $READONLY_PRINT --attributes-only --invisible '$NETWARE_PATH'" \
"AFP attribute Modify rights rejected: Hidden" \
"./afp_set_file_info_smoke --expect-completion 0x8c $READONLY_PRINT --attributes-only --hidden '$NETWARE_PATH'" \
"$SCRIPT_DIR/afp_set_file_info_smoke" --expect-completion 0x8c \
-S "$SERVER" -U "$READONLY_USER" "${READONLY_AUTH_ARGS[@]}" \
--attributes-only --invisible "$NETWARE_PATH"
--attributes-only --hidden "$NETWARE_PATH"
run_cmd \
"AFP metadata Modify rights rejected: System" \
"./afp_set_file_info_smoke --expect-completion 0x8c $READONLY_PRINT --attributes-only --system '$NETWARE_PATH'" \