From a4104ece341b6b6d1897c43c7f198fcc2736f9c0 Mon Sep 17 00:00:00 2001 From: Mario Fetka Date: Sun, 31 May 2026 05:37:10 +0000 Subject: [PATCH] tests: add AFP entry-id-relative name lookup smoke --- tests/afp/README.md | 18 ++++++--- tests/afp/afp_entry_id_smoke.c | 71 +++++++++++++++++++++++++++++++--- tests/afp/afp_smoke_suite.sh | 11 +++++- 3 files changed, 88 insertions(+), 12 deletions(-) diff --git a/tests/afp/README.md b/tests/afp/README.md index 6df87de..b477f51 100644 --- a/tests/afp/README.md +++ b/tests/afp/README.md @@ -375,23 +375,29 @@ 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. +Use `--from-name` to select this subfunction. mars_nwe supports both the +path-backed smoke mode and the documented entry-id-relative form. The +path-backed form passes a raw `SYS:`-style path with base Entry ID 0. The +entry-id-relative form first resolves a directory base with +`AFP Get Entry ID From Path Name`, then sends the leaf name with that base +Entry ID and no `VOL:` prefix. Useful smoke cases for a standard MARS-NWE `SYS` volume are: ```sh ./tests/afp/afp_entry_id_smoke --from-name -S MARS -U SUPERVISOR -P secret SYS: ./tests/afp/afp_entry_id_smoke --from-name -S MARS -U SUPERVISOR -P secret SYS:PUBLIC +./tests/afp/afp_entry_id_smoke --from-name --base-path SYS:PUBLIC -S MARS -U SUPERVISOR -P secret pmdflts.ini ./tests/afp/afp_entry_id_smoke --from-name -S MARS -U SUPERVISOR -P secret SYS:SYSTEM ./tests/afp/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. +probe. Path-backed requests use the normal raw `VOL:PATH` resolver. +Entry-id-relative requests use the directory Entry ID only as a base directory, +resolve that base through the mars_nwe namespace/basehandle path, and then feed +the composed `VOL:BASE/NAME` path back into the normal mars_nwe resolver. +Regular file Entry IDs are not treated as directory bases. ### AFP Get Entry ID From NetWare Handle diff --git a/tests/afp/afp_entry_id_smoke.c b/tests/afp/afp_entry_id_smoke.c index e527370..0e102f9 100644 --- a/tests/afp/afp_entry_id_smoke.c +++ b/tests/afp/afp_entry_id_smoke.c @@ -28,13 +28,16 @@ #define AFP_GET_ENTRY_ID_FROM_PATH_NAME 0x0c #define NWE_INVALID_NAMESPACE 0xbf #define NWE_INVALID_PATH 0x9c +#ifndef NWE_INVALID_NCP_PACKET_LENGTH +#define NWE_INVALID_NCP_PACKET_LENGTH 0x7e +#endif #define AFP_TEMP_DH_NONE 0xff static void usage(const char *prog) { fprintf(stderr, "Usage: %s [--allow-invalid-namespace] [--allow-invalid-path] " - "[--from-name] [--from-handle] [--volume N] [--entry-id ID] " + "[--from-name] [--from-handle] [--volume N] [--entry-id ID] [--base-path PATH] " "[--dir-handle N] [--alloc-handle] [--raw-path] [ncpfs options] PATH\n" "\n" "ncpfs options are parsed by ncp_initialize(), for example:\n" @@ -43,12 +46,13 @@ static void usage(const char *prog) "Examples:\n" " %s -S MARS -U SUPERVISOR -P secret SYS:PUBLIC\n" " %s --from-name -S MARS -U SUPERVISOR -P secret SYS:PUBLIC\n" + " %s --from-name --base-path SYS:PUBLIC -S MARS -U SUPERVISOR -P secret pmdflts.ini\n" " %s --from-handle -S MARS -U SUPERVISOR -P secret SYS:PUBLIC/pmdflts.ini\n" " %s --dir-handle 2 -S MARS -U SUPERVISOR -P secret PUBLIC\n" " %s --alloc-handle -S MARS -U SUPERVISOR -P secret SYS:PUBLIC\n" " %s --allow-invalid-namespace -S MARS SYS:PUBLIC\n" " %s --allow-invalid-path -S MARS SYS:NO_SUCH_PATH\n", - prog, prog, prog, prog, prog, prog, prog, prog); + prog, prog, prog, prog, prog, prog, prog, prog, prog); } static int parse_u8(const char *text, unsigned int *value) @@ -182,6 +186,38 @@ static void deallocate_dir_handle(NWCONN_HANDLE conn, unsigned int dir_handle) (void)NWRequestSimple(conn, NCPC_SFN(0x16, 0x14), rq, sizeof(rq), NULL); } +static NWCCODE afp_lookup_entry_id_from_path(NWCONN_HANDLE conn, const char *path, + uint32_t *entry_id) +{ + uint8_t request[2 + 255]; + uint8_t reply_buf[4]; + NW_FRAGMENT reply; + size_t path_len = strlen(path); + NWCCODE err; + + if (path_len > 255) + return NWE_INVALID_PATH; + + request[0] = 0; + request[1] = (uint8_t)path_len; + memcpy(request + 2, path, path_len); + + memset(reply_buf, 0, sizeof(reply_buf)); + reply.fragAddr.rw = reply_buf; + reply.fragSize = sizeof(reply_buf); + + err = NWRequestSimple(conn, + NCPC_SFN(0x23, AFP_GET_ENTRY_ID_FROM_PATH_NAME), + request, 2 + path_len, &reply); + if (err) + return err; + if (reply.fragSize < 4) + return NWE_INVALID_NCP_PACKET_LENGTH; + + *entry_id = be32_to_cpu(reply_buf); + return 0; +} + int main(int argc, char **argv) { NWCONN_HANDLE conn; @@ -189,6 +225,7 @@ int main(int argc, char **argv) long init_err = 0; const char *path = NULL; const char *request_path = NULL; + const char *base_path = NULL; unsigned int dir_handle = 0; unsigned int allocated_dir_handle = AFP_TEMP_DH_NONE; int allow_invalid_namespace = 0; @@ -255,6 +292,17 @@ int main(int argc, char **argv) ncp_close(conn); return 2; } + } else if (!strcmp(argv[i], "--base-path")) { + if (++i >= argc) { + fprintf(stderr, "missing --base-path value\n"); + ncp_close(conn); + return 2; + } + base_path = argv[i]; + from_name = 1; + from_handle = 0; + raw_path = 1; + alloc_handle = 0; } else if (!strcmp(argv[i], "--raw-path")) { raw_path = 1; alloc_handle = 0; @@ -311,6 +359,18 @@ int main(int argc, char **argv) allocated_dir_handle = dir_handle; } + if (base_path) { + err = afp_lookup_entry_id_from_path(conn, base_path, &base_entry_id); + if (err) { + fprintf(stderr, + "AFP base-path lookup failed before From Name: completion=0x%02x (%u) base_path=%s\n", + (unsigned int)err & 0xff, (unsigned int)err, base_path); + deallocate_dir_handle(conn, allocated_dir_handle); + ncp_close(conn); + return 1; + } + } + if (from_handle) { memset(&opened_file, 0, sizeof(opened_file)); err = ncp_open_file(conn, 0, request_path, 0, AR_READ_ONLY, &opened_file); @@ -413,10 +473,11 @@ int main(int argc, char **argv) (unsigned int)be32_to_cpu(reply_buf + 1), (unsigned int)reply_buf[5]); } else { - printf("AFP Entry ID path=%s request_path=%s dir_handle=%u entry_id=0x%08x (%u)\n", - path, request_path, dir_handle, + printf("AFP Entry ID path=%s request_path=%s dir_handle=%u base_entry_id=0x%08x entry_id=0x%08x (%u)%s\n", + path, request_path, dir_handle, (unsigned int)base_entry_id, (unsigned int)be32_to_cpu(reply_buf), - (unsigned int)be32_to_cpu(reply_buf)); + (unsigned int)be32_to_cpu(reply_buf), + base_path ? " entry-id-relative" : ""); } if (opened_file_valid) diff --git a/tests/afp/afp_smoke_suite.sh b/tests/afp/afp_smoke_suite.sh index 56bf9d2..ec153a3 100755 --- a/tests/afp/afp_smoke_suite.sh +++ b/tests/afp/afp_smoke_suite.sh @@ -176,8 +176,12 @@ case "$RENAME_FILE_NAME" in esac DIR_PATH=$NETWARE_PATH +NETWARE_LEAF=$NETWARE_PATH case "$NETWARE_PATH" in - */*) DIR_PATH=${NETWARE_PATH%/*} ;; + */*) + DIR_PATH=${NETWARE_PATH%/*} + NETWARE_LEAF=${NETWARE_PATH##*/} + ;; esac CREATE_DIR_PATH="$DIR_PATH/$CREATE_DIR_NAME" CREATE_DIR20_PATH="$DIR_PATH/${CREATE_DIR_NAME}2" @@ -441,6 +445,11 @@ run_cmd \ "./afp_entry_id_smoke --from-handle $COMMON_PRINT '$NETWARE_PATH'" \ "$SCRIPT_DIR/afp_entry_id_smoke" --from-handle -S "$SERVER" -U "$USER_NAME" -P "$PASSWORD" "$NETWARE_PATH" +run_cmd \ + "AFP Entry ID From Name relative to Entry ID" \ + "./afp_entry_id_smoke --from-name --base-path '$DIR_PATH' $COMMON_PRINT '$NETWARE_LEAF'" \ + "$SCRIPT_DIR/afp_entry_id_smoke" --from-name --base-path "$DIR_PATH" -S "$SERVER" -U "$USER_NAME" -P "$PASSWORD" "$NETWARE_LEAF" + run_cmd \ "AFP 2.0 Get File Information" \ "./afp_file_info_smoke $COMMON_PRINT '$NETWARE_PATH'" \