From 73d4a61a11aa86707ab66626a77cfd2434254ba5 Mon Sep 17 00:00:00 2001 From: OpenAI Date: Sat, 30 May 2026 11:13:35 +0000 Subject: [PATCH] nwconn: route legacy AFP set file information 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 --- TODO.md | 11 +++++---- src/nwconn.c | 11 +++++---- tests/linux/README.md | 32 ++++++++++++++++++++++----- tests/linux/afp_set_file_info_smoke.c | 18 ++++++++++----- tests/linux/afp_smoke_suite.sh | 6 +++++ 5 files changed, 58 insertions(+), 20 deletions(-) diff --git a/TODO.md b/TODO.md index d60adec..0756af0 100644 --- a/TODO.md +++ b/TODO.md @@ -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.*` diff --git a/src/nwconn.c b/src/nwconn.c index f4af0e8..f3fbc91 100644 --- a/src/nwconn.c +++ b/src/nwconn.c @@ -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; diff --git a/tests/linux/README.md b/tests/linux/README.md index 8b2e735..fbf0aff 100644 --- a/tests/linux/README.md +++ b/tests/linux/README.md @@ -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, diff --git a/tests/linux/afp_set_file_info_smoke.c b/tests/linux/afp_set_file_info_smoke.c index e4a3a70..0d4f0b0 100644 --- a/tests/linux/afp_set_file_info_smoke.c +++ b/tests/linux/afp_set_file_info_smoke.c @@ -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 @@ -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); diff --git a/tests/linux/afp_smoke_suite.sh b/tests/linux/afp_smoke_suite.sh index 500470d..0dd80a4 100755 --- a/tests/linux/afp_smoke_suite.sh +++ b/tests/linux/afp_smoke_suite.sh @@ -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'" \