From 6fd542e7ef3a52132d572241fb4aba4e63e046f5 Mon Sep 17 00:00:00 2001 From: Mario Fetka Date: Sun, 31 May 2026 04:44:04 +0000 Subject: [PATCH] tests: add AFP metadata entry-id smoke coverage --- tests/linux/afp_file_info_smoke.c | 55 +++++++++++++++++++++++++-- tests/linux/afp_set_file_info_smoke.c | 55 +++++++++++++++++++++++++-- tests/linux/afp_smoke_suite.sh | 20 ++++++++++ 3 files changed, 124 insertions(+), 6 deletions(-) diff --git a/tests/linux/afp_file_info_smoke.c b/tests/linux/afp_file_info_smoke.c index 92cdcf0..8ed5762 100644 --- a/tests/linux/afp_file_info_smoke.c +++ b/tests/linux/afp_file_info_smoke.c @@ -32,7 +32,7 @@ static void usage(const char *prog) { fprintf(stderr, "Usage: %s [--afp20] [--allow-invalid-namespace] [--allow-invalid-path] " - "[--volume N] [--entry-id ID] [--request-mask MASK] [--expect-rights-set MASK] [--expect-rights-clear MASK] [ncpfs options] PATH\n" + "[--volume N] [--entry-id ID] [--entry-id-only] [--request-mask MASK] [--expect-rights-set MASK] [--expect-rights-clear MASK] [ncpfs options] PATH\n" "\n" "ncpfs options are parsed by ncp_initialize(), for example:\n" " -S SERVER -U USER -P PASSWORD -n\n" @@ -85,6 +85,37 @@ static void cpu_to_be32(uint32_t v, uint8_t p[4]) p[3] = (uint8_t)v; } +static NWCCODE afp_get_entry_id_from_path(NWCONN_HANDLE conn, const char *path, + uint32_t *entry_id) +{ + NW_FRAGMENT reply; + uint8_t request[1 + 1 + 255]; + uint8_t reply_buf[4]; + size_t path_len = strlen(path); + NWCCODE err; + + if (path_len > 255) + return NWE_INVALID_PATH; + + request[0] = 0; /* directory handle 0, raw VOL:path */ + 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, 0x0c), + request, 2 + path_len, &reply); + if (err) + return err; + if (reply.fragSize < 4) + return NWE_INVALID_PATH; + + *entry_id = be32_to_cpu(reply_buf); + return 0; +} + static void copy_fixed_string(char *dst, size_t dstlen, const uint8_t *src, size_t srclen) { @@ -107,6 +138,7 @@ int main(int argc, char **argv) int allow_invalid_path = 0; uint32_t volume_number = 0; uint32_t entry_id = 0; + int entry_id_only = 0; uint32_t request_mask = AFP_GET_ALL; uint32_t expect_rights_set = 0; uint32_t expect_rights_clear = 0; @@ -150,6 +182,8 @@ int main(int argc, char **argv) ncp_close(conn); return 2; } + } else if (!strcmp(argv[i], "--entry-id-only")) { + entry_id_only = 1; } else if (!strcmp(argv[i], "--request-mask")) { if (++i >= argc || parse_u32(argv[i], &request_mask) || request_mask > 0xffff) { fprintf(stderr, "invalid --request-mask value\n"); @@ -196,6 +230,20 @@ int main(int argc, char **argv) return 2; } + if (entry_id_only) { + if (!entry_id) { + err = afp_get_entry_id_from_path(conn, path, &entry_id); + if (err) { + fprintf(stderr, + "AFP Get Entry ID From Path Name failed before entry-id-only getinfo: completion=0x%02x (%u) path=%s\n", + (unsigned int)err & 0xff, (unsigned int)err, path); + ncp_close(conn); + return 1; + } + } + path_len = 0; + } + memset(request, 0, sizeof(request)); request[0] = (uint8_t)volume_number; cpu_to_be32(entry_id, request + 1); @@ -273,7 +321,7 @@ int main(int argc, char **argv) } printf("AFP File Info subfunction=0x%02x path=%s entry_id=0x%08x parent_id=0x%08x attrs=0x%04x " - "data_len=%u resource_len=%u offspring=%u long_name=%s short_name=%s rights=0x%04x reply_len=%zu\n", + "data_len=%u resource_len=%u offspring=%u long_name=%s short_name=%s rights=0x%04x reply_len=%zu%s\n", (unsigned int)afp_subfunction, path, be32_to_cpu(reply_buf + 0), @@ -285,7 +333,8 @@ int main(int argc, char **argv) long_name, short_name, be16_to_cpu(reply_buf + 112), - reply.fragSize); + reply.fragSize, + entry_id_only ? " entry-id-only" : ""); ncp_close(conn); return 0; diff --git a/tests/linux/afp_set_file_info_smoke.c b/tests/linux/afp_set_file_info_smoke.c index 32e0bfe..9379abc 100644 --- a/tests/linux/afp_set_file_info_smoke.c +++ b/tests/linux/afp_set_file_info_smoke.c @@ -42,7 +42,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] " + "[--volume N] [--entry-id ID] [--entry-id-only] [--type FOUR] [--creator FOUR] " "[--hidden|--clear-hidden|--invisible|--clear-invisible|--system|--clear-system|--archive|--clear-archive] " "[--access-time-epoch SECONDS] [--create-time-epoch SECONDS] [--mtime-epoch SECONDS] [--backup-time-epoch SECONDS] [--finder-info-only|--attributes-only|--access-time-only|--create-time-only|--timestamp-only|--backup-time-only] " "[ncpfs options] PATH\n" @@ -160,6 +160,37 @@ static NWCCODE afp_get_file_info(NWCONN_HANDLE conn, const char *path, &reply); } +static NWCCODE afp_get_entry_id_from_path(NWCONN_HANDLE conn, const char *path, + uint32_t *entry_id) +{ + NW_FRAGMENT reply; + uint8_t request[1 + 1 + 255]; + uint8_t reply_buf[4]; + size_t path_len = strlen(path); + NWCCODE err; + + if (path_len > 255) + return NWE_INVALID_PATH; + + request[0] = 0; /* directory handle 0, raw VOL:path */ + 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, 0x0c), + request, 2 + path_len, &reply); + if (err) + return err; + if (reply.fragSize < 4) + return NWE_INVALID_PATH; + + *entry_id = be32_to_cpu(reply_buf); + return 0; +} + int main(int argc, char **argv) { NWCONN_HANDLE conn; @@ -170,6 +201,7 @@ int main(int argc, char **argv) int expect_completion = -1; uint32_t volume_number = 0; uint32_t entry_id = 0; + int entry_id_only = 0; uint8_t finder_info[32]; uint8_t set_subfunction = AFP20_SET_FILE_INFORMATION; uint16_t request_mask = AFP_FINDER_INFO_MASK; @@ -240,6 +272,8 @@ int main(int argc, char **argv) ncp_close(conn); return 2; } + } else if (!strcmp(argv[i], "--entry-id-only")) { + entry_id_only = 1; } else if (!strcmp(argv[i], "--hidden") || !strcmp(argv[i], "--invisible")) { request_mask |= AFP_ATTRIBUTES_MASK; attr_request = AFP_ATTR_SETCLR | AFP_ATTR_HIDDEN; @@ -362,6 +396,20 @@ int main(int argc, char **argv) return 2; } + if (entry_id_only) { + if (!entry_id) { + err = afp_get_entry_id_from_path(conn, path, &entry_id); + if (err) { + fprintf(stderr, + "AFP Get Entry ID From Path Name failed before entry-id-only setinfo: completion=0x%02x (%u) path=%s\n", + (unsigned int)err & 0xff, (unsigned int)err, path); + ncp_close(conn); + return 1; + } + } + path_len = 0; + } + memset(request, 0, sizeof(request)); request[0] = (uint8_t)volume_number; cpu_to_be32(entry_id, request + 1); @@ -525,12 +573,13 @@ int main(int argc, char **argv) return 1; } - printf("AFP Set File Info subfunction=0x%02x layout=websdk path=%s bitmap=0x%04x attrs=0x%04x create=0x%04x access=0x%04x modify=0x%04x%04x backup=0x%04x%04x finder_type=%.4s finder_creator=%.4s entry_id=0x%08x verified\n", + printf("AFP Set File Info subfunction=0x%02x layout=websdk path=%s bitmap=0x%04x attrs=0x%04x create=0x%04x access=0x%04x modify=0x%04x%04x backup=0x%04x%04x finder_type=%.4s finder_creator=%.4s entry_id=0x%08x verified%s\n", set_subfunction, path, request_mask, be16_to_cpu(verify_buf + 8), be16_to_cpu(verify_buf + 20), be16_to_cpu(verify_buf + 22), be16_to_cpu(verify_buf + 24), be16_to_cpu(verify_buf + 26), be16_to_cpu(verify_buf + 28), be16_to_cpu(verify_buf + 30), - finder_info + 0, finder_info + 4, be32_to_cpu(verify_buf + 0)); + finder_info + 0, finder_info + 4, be32_to_cpu(verify_buf + 0), + entry_id_only ? " entry-id-only" : ""); ncp_close(conn); return 0; diff --git a/tests/linux/afp_smoke_suite.sh b/tests/linux/afp_smoke_suite.sh index 27f74fc..eea3acd 100755 --- a/tests/linux/afp_smoke_suite.sh +++ b/tests/linux/afp_smoke_suite.sh @@ -611,12 +611,25 @@ run_cmd \ "$SCRIPT_DIR/afp_open_file_fork_smoke" --expect-completion 0x9c --fork 1 \ -S "$SERVER" -U "$USER_NAME" -P "$PASSWORD" "$NETWARE_PATH" +run_cmd \ + "AFP Get File Information by Entry ID" \ + "./afp_file_info_smoke --entry-id-only $COMMON_PRINT '$NETWARE_PATH'" \ + "$SCRIPT_DIR/afp_file_info_smoke" --entry-id-only \ + -S "$SERVER" -U "$USER_NAME" -P "$PASSWORD" "$NETWARE_PATH" + run_cmd \ "AFP Set File Information FinderInfo" \ "./afp_set_file_info_smoke $COMMON_PRINT --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" \ --finder-info-only --type "$FINDER_TYPE" --creator "$FINDER_CREATOR" "$NETWARE_PATH" +run_cmd \ + "AFP Set File Information FinderInfo by Entry ID" \ + "./afp_set_file_info_smoke --entry-id-only $COMMON_PRINT --finder-info-only --type '$FINDER_TYPE' --creator '$FINDER_CREATOR' '$NETWARE_PATH'" \ + "$SCRIPT_DIR/afp_set_file_info_smoke" --entry-id-only \ + -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'" \ @@ -629,6 +642,13 @@ run_cmd \ "$SCRIPT_DIR/afp_set_file_info_smoke" -S "$SERVER" -U "$USER_NAME" -P "$PASSWORD" \ --attributes-only --hidden "$NETWARE_PATH" +run_cmd \ + "AFP Set File Information Hidden by Entry ID" \ + "./afp_set_file_info_smoke --entry-id-only $COMMON_PRINT --attributes-only --hidden '$NETWARE_PATH'" \ + "$SCRIPT_DIR/afp_set_file_info_smoke" --entry-id-only \ + -S "$SERVER" -U "$USER_NAME" -P "$PASSWORD" \ + --attributes-only --hidden "$NETWARE_PATH" + run_cmd \ "AFP Set File Information Clear Hidden" \ "./afp_set_file_info_smoke $COMMON_PRINT --attributes-only --clear-hidden '$NETWARE_PATH'" \