From 9032848c9adf2d4dcd689c2e4ea41b9eab7fe1e0 Mon Sep 17 00:00:00 2001 From: Mario Fetka Date: Sat, 30 May 2026 18:59:24 +0000 Subject: [PATCH] nwconn: keep AFP file entry IDs on nwatalk fallback --- TODO.md | 5 ++++ src/nwconn.c | 11 +++++---- tests/linux/afp_smoke_suite.sh | 45 +++++++++++++++++++++++++--------- 3 files changed, 44 insertions(+), 17 deletions(-) diff --git a/TODO.md b/TODO.md index 95b3e28..cf4493d 100644 --- a/TODO.md +++ b/TODO.md @@ -578,3 +578,8 @@ AFP Get/Scan AccessPrivileges convergence: Get File Information probe reported `rights=0x0500`, checked that Read was set and Write/Modify Status were clear, then revoked the temporary trustee assignment. The same run ended with `failures=0`. + +- Follow-up from AFP namespace entry ID smoke: directory AFP entry IDs may use + NetWare namespace/basehandles, but regular files currently keep nwatalk or + fallback AFP IDs because the existing directory-number reverse mapper is not + a reliable file-entry reverse mapper on DOS namespace volumes. diff --git a/src/nwconn.c b/src/nwconn.c index 23a9664..7292566 100644 --- a/src/nwconn.c +++ b/src/nwconn.c @@ -550,16 +550,17 @@ static int afp_build_base_relative_path(int volume, uint32 base_entry_id, static uint32 afp_namespace_entry_id(int volume, const struct stat *stb) /* - * AFP entry IDs should follow the same object identity mars_nwe already uses - * for namespace/basehandle calls whenever possible. That keeps AFP - * entry-id-based lookups on the existing NetWare object resolver instead of - * maintaining a parallel AFP path database. + * Use mars_nwe namespace/basehandle IDs only for directories. The existing + * reverse mapper is the right object-id -> path path for directory handles, + * but regular files can collide with directory-number mappings on DOS + * namespace volumes. File AFP entry IDs therefore stay on nwatalk/fallback + * IDs until a proven file-entry reverse mapper is available. */ { DEV_NAMESPACE_MAP dnm; uint32 entry_id; - if (!stb) return(0); + if (!stb || !S_ISDIR(stb->st_mode)) return(0); dnm.dev = stb->st_dev; dnm.namespace = NAME_DOS; diff --git a/tests/linux/afp_smoke_suite.sh b/tests/linux/afp_smoke_suite.sh index 7a8d366..c07ad9d 100755 --- a/tests/linux/afp_smoke_suite.sh +++ b/tests/linux/afp_smoke_suite.sh @@ -126,8 +126,13 @@ case "$NETWARE_PATH" in esac CREATE_DIR_PATH="$DIR_PATH/$CREATE_DIR_NAME" CREATE_DIR20_PATH="$DIR_PATH/${CREATE_DIR_NAME}2" -UNIX_DIR_PATH=$(dirname -- "$UNIX_PATH")/$CREATE_DIR_NAME -UNIX_DIR20_PATH=$(dirname -- "$UNIX_PATH")/${CREATE_DIR_NAME}2 +UNIX_PARENT_PATH=$(dirname -- "$UNIX_PATH") +CREATE_DIR_NAME_DOS=$(printf '%s' "$CREATE_DIR_NAME" | tr '[:lower:]' '[:upper:]') +CREATE_DIR20_NAME_DOS=$(printf '%s' "${CREATE_DIR_NAME}2" | tr '[:lower:]' '[:upper:]') +UNIX_DIR_PATH=$UNIX_PARENT_PATH/$CREATE_DIR_NAME +UNIX_DIR20_PATH=$UNIX_PARENT_PATH/${CREATE_DIR_NAME}2 +UNIX_DIR_PATH_DOS=$UNIX_PARENT_PATH/$CREATE_DIR_NAME_DOS +UNIX_DIR20_PATH_DOS=$UNIX_PARENT_PATH/$CREATE_DIR20_NAME_DOS REPORT_TMP=$(mktemp "${TMPDIR:-/tmp}/mars-afp-smoke.XXXXXX") LOG_TMP=$(mktemp "${TMPDIR:-/tmp}/mars-afp-log.XXXXXX") @@ -177,6 +182,20 @@ run_cmd() { fi } + +cleanup_created_dir() { + local path=$1 + local dos_path=$2 + + if [ -d "$path" ]; then + rmdir "$path" + elif [ -d "$dos_path" ]; then + rmdir "$dos_path" + else + rmdir "$path" + fi +} + run_optional_cmd() { local label=$1 local printable=$2 @@ -237,6 +256,8 @@ emit "create_dir_path=$CREATE_DIR_PATH" emit "create_dir20_path=$CREATE_DIR20_PATH" emit "unix_dir_path=$UNIX_DIR_PATH" emit "unix_dir20_path=$UNIX_DIR20_PATH" +emit "unix_dir_path_dos=$UNIX_DIR_PATH_DOS" +emit "unix_dir20_path_dos=$UNIX_DIR20_PATH_DOS" if [ -n "$READONLY_USER" ]; then emit "readonly_user=$READONLY_USER" if [ "$READONLY_NO_PASSWORD" -eq 1 ]; then @@ -325,17 +346,17 @@ run_cmd \ "./afp_temp_dir_handle_smoke $COMMON_PRINT '$DIR_PATH'" \ "$SCRIPT_DIR/afp_temp_dir_handle_smoke" -S "$SERVER" -U "$USER_NAME" -P "$PASSWORD" "$DIR_PATH" -if [ -d "$UNIX_DIR_PATH" ]; then +if [ -d "$UNIX_DIR_PATH" ] || [ -d "$UNIX_DIR_PATH_DOS" ]; then run_optional_cmd \ "Prepare AFP Create Directory cleanup" \ - "rmdir '$UNIX_DIR_PATH'" \ - rmdir "$UNIX_DIR_PATH" || true + "rmdir '$UNIX_DIR_PATH' or '$UNIX_DIR_PATH_DOS'" \ + cleanup_created_dir "$UNIX_DIR_PATH" "$UNIX_DIR_PATH_DOS" || true fi -if [ -d "$UNIX_DIR20_PATH" ]; then +if [ -d "$UNIX_DIR20_PATH" ] || [ -d "$UNIX_DIR20_PATH_DOS" ]; then run_optional_cmd \ "Prepare AFP 2.0 Create Directory cleanup" \ - "rmdir '$UNIX_DIR20_PATH'" \ - rmdir "$UNIX_DIR20_PATH" || true + "rmdir '$UNIX_DIR20_PATH' or '$UNIX_DIR20_PATH_DOS'" \ + cleanup_created_dir "$UNIX_DIR20_PATH" "$UNIX_DIR20_PATH_DOS" || true fi run_cmd \ @@ -351,13 +372,13 @@ run_cmd \ run_cmd \ "Cleanup AFP Create Directory" \ - "rmdir '$UNIX_DIR_PATH'" \ - rmdir "$UNIX_DIR_PATH" + "rmdir '$UNIX_DIR_PATH' or '$UNIX_DIR_PATH_DOS'" \ + cleanup_created_dir "$UNIX_DIR_PATH" "$UNIX_DIR_PATH_DOS" run_cmd \ "Cleanup AFP 2.0 Create Directory" \ - "rmdir '$UNIX_DIR20_PATH'" \ - rmdir "$UNIX_DIR20_PATH" + "rmdir '$UNIX_DIR20_PATH' or '$UNIX_DIR20_PATH_DOS'" \ + cleanup_created_dir "$UNIX_DIR20_PATH" "$UNIX_DIR20_PATH_DOS" run_cmd \ "AFP Open File Fork" \