From faa44d060b8a976efd4619e20abe282c9fe1dc35 Mon Sep 17 00:00:00 2001 From: Mario Fetka Date: Sat, 30 May 2026 18:14:32 +0000 Subject: [PATCH] nwconn: derive AFP entry ids from NetWare handles --- src/nwconn.c | 103 ++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 89 insertions(+), 14 deletions(-) diff --git a/src/nwconn.c b/src/nwconn.c index 377484a..01cc66b 100644 --- a/src/nwconn.c +++ b/src/nwconn.c @@ -485,11 +485,35 @@ static int afp_resolve_path_volume(uint8 *path, int path_len, char *unixname, in } +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. + */ +{ + DEV_NAMESPACE_MAP dnm; + uint32 entry_id; + + if (!stb) return(0); + + dnm.dev = stb->st_dev; + dnm.namespace = NAME_DOS; + entry_id = nw_vol_inode_to_handle(volume, stb->st_ino, &dnm); + + /* Keep the old AFP fallback range and reserve zero as invalid. */ + if (!entry_id || (entry_id & 0x80000000U)) + return(0); + + return(entry_id); +} + static uint32 afp_fallback_entry_id(int volume, const struct stat *stb) /* - * Build a stable local AFP entry id from Unix identity data when libatalk has - * no stored CNID/AppleDouble id yet. This is not a NetWare-internal directory - * base number; it is only the AFP id returned by the path-name probe. + * Build a stable local AFP entry id from Unix identity data when the NetWare + * namespace handle cannot represent the object and libatalk has no stored + * CNID/AppleDouble id yet. This is only a legacy compatibility fallback. */ { uint32 hash = 2166136261U; @@ -518,17 +542,21 @@ static uint32 afp_get_or_create_entry_id(const char *unixname, int volume, const struct stat *stb, int *fallback_out) /* - * Return a persistent mars_nwe AFP entry id when available. If neither the - * mars_nwe xattr nor Netatalk/libatalk metadata contains an id yet, derive the - * existing stat-backed compatibility id and cache that id in mars_nwe's private - * AFP xattr namespace. The first caller still records fallback diagnostics so - * the log remains honest about the id origin; follow-up requests should read the - * xattr directly and no longer need the temporary stat derivation path. + * Return the mars_nwe namespace basehandle as AFP entry id whenever it can be + * represented. nwatalk/libatalk metadata remains a cache/legacy fallback for + * entries that cannot be mapped by the NetWare namespace table. */ { uint32 entry_id = 0; int result; + entry_id = afp_namespace_entry_id(volume, stb); + if (entry_id) { + if (fallback_out) *fallback_out = 0; + (void)nwatalk_set_entry_id(unixname, entry_id); + return(entry_id); + } + result = nwatalk_get_entry_id(unixname, &entry_id); if (!result && entry_id) { if (fallback_out) *fallback_out = 0; @@ -988,6 +1016,46 @@ static int afp_find_dos_name_from_entry_id_rec(int volume, return(-0xff); /* Failure, no files found */ } +static int afp_namespace_path_from_entry_id(int volume, uint32 entry_id, + char *path, int path_len) +/* + * First try the existing NetWare namespace reverse mapper. It returns + * length-prefixed DOS path components; AFP 0x12 wants a single DOSPathString, + * so join those components with '/'. + */ +{ + uint8 raw[512]; + int raw_len; + int in = 0; + int out = 0; + + if (!path || path_len < 1) return(-0xff); + *path = '\0'; + + raw_len = map_directory_number_to_path(volume, entry_id, NAME_DOS, + raw, sizeof(raw)); + if (raw_len < 0) + return(raw_len); + if (!raw_len) + return(0); + + while (in < raw_len) { + int len = raw[in++]; + + if (len < 0 || in + len > raw_len) return(-0xff); + if (out) { + if (out + 1 >= path_len) return(-0x96); + path[out++] = '/'; + } + if (out + len >= path_len) return(-0x96); + memcpy(path + out, raw + in, len); + out += len; + in += len; + } + path[out] = '\0'; + return(0); +} + static int afp_find_dos_name_from_entry_id(int volume, uint32 entry_id, char *path, int path_len) { @@ -1041,12 +1109,19 @@ static int afp_get_dos_name_from_entry_id(uint8 *afp_req, int afp_len, return(-0xbf); /* Invalid Namespace */ } - result = afp_find_dos_name_from_entry_id((int)volume_number, entry_id, - path, sizeof(path)); + result = afp_namespace_path_from_entry_id((int)volume_number, entry_id, + path, sizeof(path)); if (result) { - XDPRINTF((2,0, "AFP Get DOS Name From Entry ID lookup failed: vol=%d entry=0x%08x result=-0x%x", - (int)volume_number, entry_id, -result)); - return(result); + int legacy_result; + + legacy_result = afp_find_dos_name_from_entry_id((int)volume_number, + entry_id, path, + sizeof(path)); + if (legacy_result) { + XDPRINTF((2,0, "AFP Get DOS Name From Entry ID lookup failed: vol=%d entry=0x%08x namespace=-0x%x legacy=-0x%x", + (int)volume_number, entry_id, -result, -legacy_result)); + return(legacy_result); + } } len = strlen(path);