From 2eb6058b817589f5dfb94b28a55a66af9adf32c6 Mon Sep 17 00:00:00 2001 From: t Date: Sun, 31 May 2026 05:54:24 +0000 Subject: [PATCH] tests: verify AFP timestamp plausibility in smoke suite --- tests/afp/afp_set_file_info_smoke.c | 69 +++++++++++++++++++++++++++++ tests/afp/afp_smoke_suite.sh | 16 +++++++ 2 files changed, 85 insertions(+) diff --git a/tests/afp/afp_set_file_info_smoke.c b/tests/afp/afp_set_file_info_smoke.c index 12195e2..802488b 100644 --- a/tests/afp/afp_set_file_info_smoke.c +++ b/tests/afp/afp_set_file_info_smoke.c @@ -134,6 +134,39 @@ static int epoch_to_nw_time(uint32_t epoch, uint8_t out[4]) return 0; } + +static int nw_date_plausible(uint16_t date) +{ + unsigned int year = 1980 + ((date >> 9) & 0x7f); + unsigned int month = (date >> 5) & 0x0f; + unsigned int day = date & 0x1f; + + if (!date) + return 0; + if (year < 1990 || year > 2107) + return 0; + if (month < 1 || month > 12) + return 0; + if (day < 1 || day > 31) + return 0; + return 1; +} + +static int nw_timestamp_plausible(const uint8_t value[4]) +{ + uint16_t date = be16_to_cpu(value + 0); + uint16_t timev = be16_to_cpu(value + 2); + unsigned int hour = (timev >> 11) & 0x1f; + unsigned int minute = (timev >> 5) & 0x3f; + unsigned int second2 = timev & 0x1f; + + if (!nw_date_plausible(date)) + return 0; + if (hour > 23 || minute > 59 || second2 > 29) + return 0; + return 1; +} + static NWCCODE afp_get_file_info(NWCONN_HANDLE conn, const char *path, uint32_t volume_number, uint32_t entry_id, uint8_t reply_buf[AFP_REPLY_LEN]) @@ -524,6 +557,15 @@ int main(int argc, char **argv) return 1; } + if ((request_mask & AFP_ACCESS_DATE_MASK) && + !nw_date_plausible(be16_to_cpu(verify_buf + 22))) { + fprintf(stderr, + "AFP Set File Information access timestamp implausible: path=%s got=0x%04x\n", + path, be16_to_cpu(verify_buf + 22)); + ncp_close(conn); + return 1; + } + if ((request_mask & AFP_ACCESS_DATE_MASK) && memcmp(verify_buf + 22, access_time, 2)) { fprintf(stderr, @@ -534,6 +576,15 @@ int main(int argc, char **argv) return 1; } + if ((request_mask & AFP_CREATE_DATE_MASK) && + !nw_date_plausible(be16_to_cpu(verify_buf + 20))) { + fprintf(stderr, + "AFP Set File Information create timestamp implausible: path=%s got=0x%04x\n", + path, be16_to_cpu(verify_buf + 20)); + ncp_close(conn); + return 1; + } + if ((request_mask & AFP_CREATE_DATE_MASK) && memcmp(verify_buf + 20, create_time, 2)) { fprintf(stderr, @@ -544,6 +595,15 @@ int main(int argc, char **argv) return 1; } + if ((request_mask & AFP_MODIFY_DATE_MASK) && + !nw_timestamp_plausible(verify_buf + 24)) { + fprintf(stderr, + "AFP Set File Information modify timestamp implausible: path=%s got=0x%04x%04x\n", + path, be16_to_cpu(verify_buf + 24), be16_to_cpu(verify_buf + 26)); + ncp_close(conn); + return 1; + } + if ((request_mask & AFP_MODIFY_DATE_MASK) && memcmp(verify_buf + 24, modify_time, sizeof(modify_time))) { fprintf(stderr, @@ -554,6 +614,15 @@ int main(int argc, char **argv) return 1; } + if ((request_mask & AFP_BACKUP_DATE_MASK) && + !nw_timestamp_plausible(verify_buf + 28)) { + fprintf(stderr, + "AFP Set File Information backup timestamp implausible: path=%s got=0x%04x%04x\n", + path, be16_to_cpu(verify_buf + 28), be16_to_cpu(verify_buf + 30)); + ncp_close(conn); + return 1; + } + if ((request_mask & AFP_BACKUP_DATE_MASK) && memcmp(verify_buf + 28, backup_time, sizeof(backup_time))) { fprintf(stderr, diff --git a/tests/afp/afp_smoke_suite.sh b/tests/afp/afp_smoke_suite.sh index ec153a3..c60d3ae 100755 --- a/tests/afp/afp_smoke_suite.sh +++ b/tests/afp/afp_smoke_suite.sh @@ -282,6 +282,17 @@ cleanup_created_file() { fi } + +verify_mtime_epoch() { + local path=$1 + local expected=$2 + local actual + + actual=$(stat -c '%Y' "$path") || return 1 + printf 'mtime_epoch=%s expected=%s\n' "$actual" "$expected" + test "$actual" = "$expected" +} + run_optional_cmd() { local label=$1 local printable=$2 @@ -821,6 +832,11 @@ if command -v stat >/dev/null 2>&1; then "Linux stat: AFP Modify Timestamp" \ "stat -c 'mtime_epoch=%Y mtime=%y' '$UNIX_PATH'" \ stat -c 'mtime_epoch=%Y mtime=%y' "$UNIX_PATH" + + run_cmd \ + "Linux stat: AFP Modify Timestamp exact epoch" \ + "test \"$(stat -c '%Y' '$UNIX_PATH')\" = '$TIMESTAMP_EPOCH'" \ + verify_mtime_epoch "$UNIX_PATH" "$TIMESTAMP_EPOCH" fi if command -v getfattr >/dev/null 2>&1; then