nwconn: route legacy AFP set file information
All checks were successful
Source release / source-package (push) Successful in 47s

Wire the older WebSDK/NWAFP Set File Information subfunction (0x09) through the same deliberately narrow metadata-write implementation as AFP 2.0 Set File Information (0x10).  Both subfunctions now accept the path-backed VOL:-style smoke subset and persist only FinderInfo plus the metadata-only Invisible/System/Backup AFP attribute bits through mars_nwe's org.mars-nwe.afp.* xattrs.

This keeps the implementation conservative: 0x09 does not add timestamp writes, DOS/NetWare mode-bit mapping, create/delete/rename behavior, fork-write semantics, or entry-id-only lookup.  It simply exposes the same already-tested FinderInfo/attribute payload semantics to clients that issue the legacy AFP Set File Information opcode.

Update the Linux smoke helper with --afp09/--afp20 selection and include the legacy FinderInfo probe in afp_smoke_suite.sh so future reports cover both write opcodes automatically.

Tests:

- bash -n tests/linux/afp_smoke_suite.sh

- gcc -Iinclude -I/mnt/data/stubs -fsyntax-only tests/linux/afp_set_file_info_smoke.c

- git diff --check
This commit is contained in:
OpenAI
2026-05-30 11:13:35 +00:00
committed by Mario Fetka
parent 6cc380ec8c
commit 73d4a61a11
5 changed files with 58 additions and 20 deletions

11
TODO.md
View File

@@ -246,8 +246,9 @@ Current status:
privileged directories can show `rights=0x1ff` while the client prints
`rights=0xff`. Entry-ID-only allocation remains TODO until persistent
CNID/base-ID lookup exists.
- `AFP 2.0 Set File Information` is implemented only for path-backed file
metadata smoke writes: the FinderInfo bitmap (`0x0020`) and the AFP
- `AFP Set File Information` (`0x09`) and `AFP 2.0 Set File Information`
(`0x10`) are implemented only for path-backed file metadata smoke writes:
the FinderInfo bitmap (`0x0020`) and the AFP
Attributes bitmap (`0x0001`) restricted to metadata-only file bits: Finder
Invisible, System, and Backup. Linux
smoke coverage exists in `tests/linux/afp_set_file_info_smoke`; runtime
@@ -255,7 +256,8 @@ Current status:
`TEXT` and creator `MARS`. The helper writes 32 bytes of FinderInfo to
`org.mars-nwe.afp.finder-info`, stores the narrow attribute word in
`org.mars-nwe.afp.attributes`, and verifies the result through AFP 2.0 Get
File Information. The smoke-suite report helper now includes FinderInfo plus Invisible/System/Backup set/clear probes and has a green
File Information. The smoke-suite report helper now includes AFP 2.0 FinderInfo, legacy AFP `0x09` FinderInfo, plus Invisible/System/Backup set/clear probes
and has a green
`failures=0` run for `SYS:PUBLIC/pmdflts.ini`; that run confirms the corrected
FinderInfo payload alignment by reading
`user.org.mars-nwe.afp.finder-info=0x544558544d415253...` (`TEXTMARS` with no
@@ -312,7 +314,8 @@ Follow-up:
iteration based: `last_seen` skips past the previously returned object, but
the next returned Entry ID is not required to be numerically greater than the
continuation token. FinderInfo plus the Finder Invisible/System/Backup AFP attributes now have
deliberately narrow write paths through AFP 2.0 Set File Information; CNID
deliberately narrow write paths through AFP Set File Information `0x09` and
AFP 2.0 Set File Information `0x10`; CNID
allocation and broader AFP metadata writes still need a deliberate write-safe
design.
- Put additional future mars_nwe-owned AFP metadata under `org.mars-nwe.afp.*`

View File

@@ -423,6 +423,7 @@ static const char *afp_call_name(int ufunc)
case 0x06: return("AFP Get Entry ID From NetWare Handle");
case 0x07: return("AFP Rename");
case 0x08: return("AFP Open File Fork");
case 0x09: return("AFP Set File Information");
case 0x0a: return("AFP Scan File Information");
case 0x0b: return("AFP Alloc Temporary Dir Handle");
case 0x0c: return("AFP Get Entry ID From Path Name");
@@ -3340,7 +3341,8 @@ static int handle_ncp_serv(void)
* Information (0x05), Get Entry ID From
* NetWare Handle (0x06), Rename (0x07), Open File Fork
* (0x08), Alloc Temporary Dir Handle (0x0b), Get Entry ID
* From Path Name (0x0c), the AFP 2.0 create calls
* From Path Name (0x0c), the AFP Set File Information
* write call (0x09), the AFP 2.0 create calls
* (0x0d/0x0e), Get/Set File Information (0x0f/0x10), and
* Scan File Information (0x11).
*
@@ -3361,8 +3363,9 @@ static int handle_ncp_serv(void)
* returns a connection-local NetWare directory handle plus
* effective rights. Then expose
* the read-only AFP Get File Information query for the same
* SYS:-style path inputs. AFP 2.0 Set File Information
* accepts only FinderInfo plus the
* SYS:-style path inputs. AFP Set File Information (0x09)
* and AFP 2.0 Set File Information (0x10) accept only
* FinderInfo plus the
* metadata-only Invisible/System/Backup file attributes as
* xattr write smoke paths. AFP 2.0 Get File Information
* uses the same request/reply layout for this read-only
@@ -3403,7 +3406,7 @@ static int handle_ncp_serv(void)
afp_call_name(ufunc));
if (result > -1) data_len = result;
else completition = (uint8)-result;
} else if (ufunc == 0x10) {
} else if (ufunc == 0x09 || ufunc == 0x10) {
int result = afp_set_file_information(afp_req,
afp_len, afp_call_name(ufunc));
if (result > -1) data_len = result;

View File

@@ -56,7 +56,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, Invisible/System/Backup Set/Clear File
Fork, FinderInfo Set File Information for both AFP 2.0 (`0x10`) and the legacy AFP
Set File Information (`0x09`), Invisible/System/Backup Set/Clear File
Information, and the Linux xattr checks for:
```text
@@ -448,9 +449,12 @@ 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 2.0 request:
`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
```
@@ -474,10 +478,22 @@ Example:
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 path=SYS:PUBLIC/pmdflts.ini bitmap=0x0020 finder_type=TEXT finder_creator=MARS entry_id=0x23c8787d verified
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,
@@ -561,13 +577,17 @@ attribute word: Backup persisted as `0x0040`, so Invisible set/clear produced
`0x0041` and `0x0040` while still being correct for the Invisible bit.
```text
AFP Set File Info path=SYS:PUBLIC/pmdflts.ini bitmap=0x0001 attrs=0x0004 finder_type=TEXT finder_creator=MARS entry_id=0x62ecb463 verified
AFP Set File Info path=SYS:PUBLIC/pmdflts.ini bitmap=0x0001 attrs=0x0000 finder_type=TEXT finder_creator=MARS entry_id=0x62ecb463 verified
AFP Set File Info 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=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 2.0 Set File Information: vol=0 request_vol=0 entry=0x00000000 mask=0x0001 path='SYS:PUBLIC/pmdflts.ini' attributes attrs=0x8040
```
The legacy `0x09` endpoint is deliberately routed through the same narrow
metadata-only implementation as AFP 2.0 `0x10`; it does not add create, rename,
delete, 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 timestamp,

View File

@@ -1,5 +1,5 @@
/*
* Linux smoke test for NetWare AFP 2.0 Set File Information metadata writes.
* Linux smoke test for NetWare AFP Set File Information metadata writes.
*/
#include <errno.h>
@@ -20,6 +20,7 @@
#endif
#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_FINDER_INFO_MASK 0x0020
@@ -35,7 +36,7 @@
static void usage(const char *prog)
{
fprintf(stderr,
"Usage: %s [--allow-invalid-namespace] [--allow-invalid-path] "
"Usage: %s [--afp09|--afp20] [--allow-invalid-namespace] [--allow-invalid-path] "
"[--volume N] [--entry-id ID] [--type FOUR] [--creator FOUR] "
"[--invisible|--clear-invisible|--system|--clear-system|--backup|--clear-backup] "
"[--finder-info-only|--attributes-only] "
@@ -138,6 +139,7 @@ int main(int argc, char **argv)
uint32_t volume_number = 0;
uint32_t entry_id = 0;
uint8_t finder_info[32];
uint8_t set_subfunction = AFP20_SET_FILE_INFORMATION;
uint16_t request_mask = AFP_FINDER_INFO_MASK;
uint16_t attr_request = 0;
uint16_t attr_verify_mask = 0;
@@ -167,7 +169,11 @@ int main(int argc, char **argv)
}
for (i = 1; i < argc; i++) {
if (!strcmp(argv[i], "--allow-invalid-namespace")) {
if (!strcmp(argv[i], "--afp09")) {
set_subfunction = AFP_SET_FILE_INFORMATION;
} else if (!strcmp(argv[i], "--afp20")) {
set_subfunction = AFP20_SET_FILE_INFORMATION;
} else if (!strcmp(argv[i], "--allow-invalid-namespace")) {
allow_invalid_namespace = 1;
} else if (!strcmp(argv[i], "--allow-invalid-path")) {
allow_invalid_path = 1;
@@ -288,7 +294,7 @@ int main(int argc, char **argv)
}
err = NWRequestSimple(conn,
NCPC_SFN(0x23, AFP20_SET_FILE_INFORMATION),
NCPC_SFN(0x23, set_subfunction),
request,
data_off,
NULL);
@@ -337,8 +343,8 @@ int main(int argc, char **argv)
return 1;
}
printf("AFP Set File Info path=%s bitmap=0x%04x attrs=0x%04x finder_type=%.4s finder_creator=%.4s entry_id=0x%08x verified\n",
path, request_mask, be16_to_cpu(verify_buf + 8),
printf("AFP Set File Info subfunction=0x%02x path=%s bitmap=0x%04x attrs=0x%04x finder_type=%.4s finder_creator=%.4s entry_id=0x%08x verified\n",
set_subfunction, path, request_mask, be16_to_cpu(verify_buf + 8),
finder_info + 0, finder_info + 4, be32_to_cpu(verify_buf + 0));
ncp_close(conn);

View File

@@ -235,6 +235,12 @@ run_cmd \
"$SCRIPT_DIR/afp_set_file_info_smoke" -S "$SERVER" -U "$USER_NAME" -P "$PASSWORD" \
--finder-info-only --type "$FINDER_TYPE" --creator "$FINDER_CREATOR" "$NETWARE_PATH"
run_cmd \
"AFP Set File Information FinderInfo legacy" \
"./afp_set_file_info_smoke $COMMON_PRINT --afp09 --finder-info-only --type '$FINDER_TYPE' --creator '$FINDER_CREATOR' '$NETWARE_PATH'" \
"$SCRIPT_DIR/afp_set_file_info_smoke" -S "$SERVER" -U "$USER_NAME" -P "$PASSWORD" \
--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'" \