From 5a8a7f3488e36cac9d98cc9b9f1380e831b87437 Mon Sep 17 00:00:00 2001 From: Mario Fetka Date: Sat, 30 May 2026 20:56:59 +0000 Subject: [PATCH] tests: verify WebSDK AFP get and scan info layouts --- tests/linux/afp_file_info_smoke.c | 30 ++++++++--- tests/linux/afp_scan_info_smoke.c | 88 +++++++++++++++++++++++-------- 2 files changed, 91 insertions(+), 27 deletions(-) diff --git a/tests/linux/afp_file_info_smoke.c b/tests/linux/afp_file_info_smoke.c index affbb53..92cdcf0 100644 --- a/tests/linux/afp_file_info_smoke.c +++ b/tests/linux/afp_file_info_smoke.c @@ -24,6 +24,8 @@ #define NWE_INVALID_NAMESPACE 0xbf #define NWE_INVALID_PATH 0x9c #define AFP_REPLY_LEN 120 +#define AFP_FILE_INFO_LEN 114 +#define AFP20_FILE_INFO_LEN 120 #define AFP_GET_ALL 0xffff static void usage(const char *prog) @@ -231,10 +233,25 @@ int main(int argc, char **argv) return 1; } - if (reply.fragSize < AFP_REPLY_LEN) { - fprintf(stderr, "short AFP file-info reply: %zu bytes\n", reply.fragSize); - ncp_close(conn); - return 1; + { + size_t expected_reply_len = + (afp_subfunction == AFP20_GET_FILE_INFORMATION) + ? AFP20_FILE_INFO_LEN + : AFP_FILE_INFO_LEN; + + if (reply.fragSize < expected_reply_len) { + fprintf(stderr, "short AFP file-info reply: %zu bytes expected_at_least=%zu\n", + reply.fragSize, expected_reply_len); + ncp_close(conn); + return 1; + } + if (afp_subfunction == AFP_GET_FILE_INFORMATION && + reply.fragSize > AFP_FILE_INFO_LEN) { + fprintf(stderr, "AFP Get File Information returned non-WebSDK legacy size: %zu bytes\n", + reply.fragSize); + ncp_close(conn); + return 1; + } } copy_fixed_string(long_name, sizeof(long_name), reply_buf + 64, 32); @@ -256,7 +273,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\n", + "data_len=%u resource_len=%u offspring=%u long_name=%s short_name=%s rights=0x%04x reply_len=%zu\n", (unsigned int)afp_subfunction, path, be32_to_cpu(reply_buf + 0), @@ -267,7 +284,8 @@ int main(int argc, char **argv) be16_to_cpu(reply_buf + 18), long_name, short_name, - be16_to_cpu(reply_buf + 112)); + be16_to_cpu(reply_buf + 112), + reply.fragSize); ncp_close(conn); return 0; diff --git a/tests/linux/afp_scan_info_smoke.c b/tests/linux/afp_scan_info_smoke.c index 9dd01cc..7026851 100644 --- a/tests/linux/afp_scan_info_smoke.c +++ b/tests/linux/afp_scan_info_smoke.c @@ -24,7 +24,9 @@ #define NWE_INVALID_NAMESPACE 0xbf #define NWE_INVALID_PATH 0x9c #define NWE_NO_FILES_FOUND 0xff -#define AFP_SCAN_REPLY_LEN 124 +#define AFP_SCAN_REPLY_LEN 122 +#define AFP_SCAN_INFO_LEN 114 +#define AFP20_SCAN_INFO_LEN 120 #define AFP_GET_ALL 0xffff #define AFP_SEARCH_ALL 0xffff @@ -229,9 +231,28 @@ int main(int argc, char **argv) 16 + path_len, &reply); if (err == NWE_INVALID_NAMESPACE && allow_invalid_namespace) { - printf("AFP Scan File Information subfunction=0x%02x returned invalid namespace as expected for path=%s\n", - (unsigned int)afp_subfunction, path); - ncp_close(conn); + printf("AFP Scan File Info subfunction=0x%02x path=%s last_seen=0x%08x desired=%u " + "actual_count=%u next_last_seen=0x%08x 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", + (unsigned int)afp_subfunction, + path, + last_seen_id, + (unsigned int)desired_count, + be16_to_cpu(reply_buf + 0), + be32_to_cpu(reply_buf + 2), + be32_to_cpu(reply_buf + 2), + be32_to_cpu(reply_buf + 2 + 4), + be16_to_cpu(reply_buf + 2 + 8), + be32_to_cpu(reply_buf + 2 + 10), + be32_to_cpu(reply_buf + 2 + 14), + be16_to_cpu(reply_buf + 2 + 18), + long_name, + short_name, + be16_to_cpu(reply_buf + 2 + 112), + reply.fragSize); + + ncp_close(conn); return 0; } if (err == NWE_INVALID_PATH && allow_invalid_path) { @@ -255,32 +276,57 @@ int main(int argc, char **argv) return 1; } - if (reply.fragSize < AFP_SCAN_REPLY_LEN) { - fprintf(stderr, "short AFP scan reply: %zu bytes\n", reply.fragSize); - ncp_close(conn); - return 1; + { + size_t expected_record_len = + (afp_subfunction == AFP20_SCAN_FILE_INFORMATION) + ? AFP20_SCAN_INFO_LEN + : AFP_SCAN_INFO_LEN; + size_t expected_reply_len = 2 + expected_record_len; + + if (reply.fragSize < expected_reply_len) { + fprintf(stderr, "short AFP scan reply: %zu bytes expected_at_least=%zu\n", + reply.fragSize, expected_reply_len); + ncp_close(conn); + return 1; + } + if (be16_to_cpu(reply_buf + 0) != 1) { + fprintf(stderr, "AFP scan reply count is not WebSDK compliant: count=%u\n", + be16_to_cpu(reply_buf + 0)); + ncp_close(conn); + return 1; + } + if (afp_subfunction == AFP_SCAN_FILE_INFORMATION && + reply.fragSize > 2 + AFP_SCAN_INFO_LEN) { + fprintf(stderr, "AFP Scan File Information returned non-WebSDK legacy size: %zu bytes\n", + reply.fragSize); + ncp_close(conn); + return 1; + } } - copy_fixed_string(long_name, sizeof(long_name), reply_buf + 4 + 64, 32); - copy_fixed_string(short_name, sizeof(short_name), reply_buf + 4 + 100, 12); + copy_fixed_string(long_name, sizeof(long_name), reply_buf + 2 + 64, 32); + copy_fixed_string(short_name, sizeof(short_name), reply_buf + 2 + 100, 12); - printf("AFP Scan File Info subfunction=0x%02x path=%s last_seen=0x%08x desired=%u next_last_seen=0x%08x " - "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\n", + printf("AFP Scan File Info subfunction=0x%02x path=%s last_seen=0x%08x desired=%u " + "actual_count=%u next_last_seen=0x%08x 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", (unsigned int)afp_subfunction, path, last_seen_id, (unsigned int)desired_count, - be32_to_cpu(reply_buf + 0), - be32_to_cpu(reply_buf + 4), - be32_to_cpu(reply_buf + 8), - be16_to_cpu(reply_buf + 12), - be32_to_cpu(reply_buf + 14), - be32_to_cpu(reply_buf + 18), - be16_to_cpu(reply_buf + 22), + be16_to_cpu(reply_buf + 0), + be32_to_cpu(reply_buf + 2), + be32_to_cpu(reply_buf + 2), + be32_to_cpu(reply_buf + 2 + 4), + be16_to_cpu(reply_buf + 2 + 8), + be32_to_cpu(reply_buf + 2 + 10), + be32_to_cpu(reply_buf + 2 + 14), + be16_to_cpu(reply_buf + 2 + 18), long_name, short_name, - be16_to_cpu(reply_buf + 4 + 112)); + be16_to_cpu(reply_buf + 2 + 112), + reply.fragSize); ncp_close(conn); return 0;