From 77a40f9ed2e409c8bc1a926de33de1ab6a226d7e Mon Sep 17 00:00:00 2001 From: Mario Fetka Date: Sun, 31 May 2026 04:40:27 +0000 Subject: [PATCH] nwconn: share AFP entry-id resolver with metadata paths --- src/nwconn.c | 196 +++++++++++++++++++++++++++++++++++---------------- 1 file changed, 137 insertions(+), 59 deletions(-) diff --git a/src/nwconn.c b/src/nwconn.c index 030860c..f4c5731 100644 --- a/src/nwconn.c +++ b/src/nwconn.c @@ -491,6 +491,10 @@ static int afp_namespace_path_from_entry_id(int volume, uint32 entry_id, char *path, int path_len); static int afp_find_dos_name_from_entry_id(int volume, uint32 entry_id, char *path, int path_len); +static int afp_resolve_entry_id_path(int volume, uint32 entry_id, + char *entry_path, int entry_path_len, + char *unixname, int unixname_len, + int *resolved_volume, int *used_len); static int afp_build_base_relative_path(int volume, uint32 base_entry_id, uint8 *path, int path_len, @@ -802,40 +806,20 @@ static int afp_open_file_fork(uint8 *afp_req, int afp_len, } if (!path_len) { - char dos_path[256]; char entry_path[512]; - int dos_result; int used; + int entry_result; - if (!request_entry_id) { - XDPRINTF((2,0, "AFP Open File Fork rejected: missing path and entry id vol=%d fork=%d access=0x%02x", - (int)volume_number, (int)fork_indicator, (int)access_mode)); - return(-0x9c); - } - - dos_result = afp_find_dos_name_from_entry_id((int)volume_number, - request_entry_id, - dos_path, sizeof(dos_path)); - if (dos_result) { + entry_result = afp_resolve_entry_id_path((int)volume_number, + request_entry_id, + entry_path, sizeof(entry_path), + unixname, sizeof(unixname), + &path_volume, &used); + if (entry_result) { XDPRINTF((2,0, "AFP Open File Fork entry-id lookup failed: vol=%d entry=0x%08x fork=%d access=0x%02x result=-0x%x", (int)volume_number, request_entry_id, (int)fork_indicator, - (int)access_mode, -dos_result)); - return(dos_result); - } - if (volume_number >= used_nw_volumes || !nw_volumes[volume_number].sysname) - return(-0x98); - - used = slprintf(entry_path, sizeof(entry_path), "%s:%s", - nw_volumes[volume_number].sysname, dos_path); - if (used < 0 || used >= (int)sizeof(entry_path)) return(-0x96); - - path_volume = afp_resolve_path_volume((uint8 *)entry_path, used, - unixname, sizeof(unixname)); - if (path_volume < 0) { - XDPRINTF((2,0, "AFP Open File Fork entry-id path resolve failed: request_vol=%d entry=0x%08x fork=%d access=0x%02x path='%s' result=-0x%x", - (int)volume_number, request_entry_id, (int)fork_indicator, - (int)access_mode, entry_path, -path_volume)); - return(path_volume); + (int)access_mode, -entry_result)); + return(entry_result); } memset(&fileinfo, 0, sizeof(fileinfo)); @@ -943,9 +927,34 @@ static int afp_alloc_temporary_dir_handle(uint8 *afp_req, int afp_len, } if (!path_len) { - XDPRINTF((2,0, "AFP Alloc Temporary Dir Handle rejected: entry-id-only lookup unsupported vol=%d entry=0x%08x", - (int)volume_number, request_entry_id)); - return(-0x9c); /* Invalid Path until persistent entry-id lookup exists */ + char entry_path[512]; + int entry_len; + int entry_result; + + entry_result = afp_resolve_entry_id_path((int)volume_number, + request_entry_id, + entry_path, sizeof(entry_path), + unixname, sizeof(unixname), + &path_volume, &entry_len); + if (entry_result) { + XDPRINTF((2,0, "AFP Alloc Temporary Dir Handle entry-id lookup failed: vol=%d entry=0x%08x result=-0x%x", + (int)volume_number, request_entry_id, -entry_result)); + return(entry_result); + } + dirhandle = nw_alloc_dir_handle(0, (uint8 *)entry_path, entry_len, 0, 1, + (int)(ncprequest->task), &eff_rights); + if (dirhandle < 0) { + XDPRINTF((2,0, "AFP Alloc Temporary Dir Handle entry-id allocation failed: request_vol=%d resolved_vol=%d entry=0x%08x path='%s' result=-0x%x", + (int)volume_number, path_volume, request_entry_id, + entry_path, -dirhandle)); + return(dirhandle); + } + response[0] = (uint8)dirhandle; + response[1] = (uint8)eff_rights; + XDPRINTF((3,0, "AFP Alloc Temporary Dir Handle: vol=%d request_vol=%d entry=0x%08x path='%s' dir_handle=%d rights=0x%x entry-id", + path_volume, (int)volume_number, request_entry_id, + entry_path, dirhandle, eff_rights)); + return(2); } path_volume = afp_resolve_path_volume(afp_req + 7, path_len, @@ -1625,6 +1634,49 @@ static int afp_find_dos_name_from_entry_id(int volume, uint32 entry_id, return(-0xff); } +static int afp_resolve_entry_id_path(int volume, uint32 entry_id, + char *entry_path, int entry_path_len, + char *unixname, int unixname_len, + int *resolved_volume, int *used_len) +/* + * Resolve a documented AFP entry-id-only request to a normal VOL:PATH string + * and Unix path. The reverse lookup is deliberately based on mars_nwe's AFP + * xattr entry-id cache rather than treating regular file IDs as DOS namespace + * directory numbers. Callers can then reuse the normal mars_nwe wrappers for + * rights, attributes, open/share and timestamp semantics. + */ +{ + char dos_path[256]; + int result; + int used; + + if (!entry_path || entry_path_len < 1 || !unixname || unixname_len < 1) + return(-0x7e); + if (volume < 0 || volume >= used_nw_volumes || !nw_volumes[volume].sysname) + return(-0x98); + if (!entry_id) + return(-0x9c); + + result = afp_find_dos_name_from_entry_id(volume, entry_id, + dos_path, sizeof(dos_path)); + if (result) + return(result); + + used = slprintf(entry_path, entry_path_len, "%s:%s", + nw_volumes[volume].sysname, dos_path); + if (used < 0 || used >= entry_path_len) + return(-0x96); + + result = afp_resolve_path_volume((uint8 *)entry_path, used, + unixname, unixname_len); + if (result < 0) + return(result); + + if (resolved_volume) *resolved_volume = result; + if (used_len) *used_len = used; + return(0); +} + static int afp_get_dos_name_from_entry_id(uint8 *afp_req, int afp_len, uint8 *response) { @@ -1922,7 +1974,9 @@ static int afp_get_file_information(uint8 *afp_req, int afp_len, int path_len; int volume; char unixname[PATH_MAX]; - uint8 empty_path = 0; + char entry_path[512]; + uint8 *path_data; + int path_data_len; uint32 entry_id = 0; int fallback = 0; int result; @@ -1949,34 +2003,43 @@ static int afp_get_file_information(uint8 *afp_req, int afp_len, } if (!path_len) { - XDPRINTF((2,0, "%s rejected: entry-id-only lookup unsupported vol=%d entry=0x%08x mask=0x%04x", - call_name, (int)volume_number, request_entry_id, request_mask)); - return(-0x9c); /* Invalid Path until persistent entry-id lookup exists */ + result = afp_resolve_entry_id_path((int)volume_number, request_entry_id, + entry_path, sizeof(entry_path), + unixname, sizeof(unixname), + &volume, &path_data_len); + if (result) { + XDPRINTF((2,0, "%s entry-id lookup failed: vol=%d entry=0x%08x mask=0x%04x result=-0x%x", + call_name, (int)volume_number, request_entry_id, + request_mask, -result)); + return(result); + } + path_data = (uint8 *)entry_path; + } else { + path_data = afp_req + 9; + path_data_len = path_len; + volume = conn_get_kpl_unxname(unixname, sizeof(unixname), 0, + path_data, path_data_len); + if (volume < 0) { + XDPRINTF((2,0, "%s path resolve failed: vol=%d entry=0x%08x path='%s' result=-0x%x", + call_name, (int)volume_number, request_entry_id, + visable_data(path_data, path_data_len), -volume)); + return(volume); + } } - volume = conn_get_kpl_unxname(unixname, sizeof(unixname), 0, - path_len ? afp_req + 9 : &empty_path, - path_len); - if (volume < 0) { - XDPRINTF((2,0, "%s path resolve failed: vol=%d entry=0x%08x path='%s' result=-0x%x", - call_name, (int)volume_number, request_entry_id, - visable_data(afp_req + 9, path_len), -volume)); - return(volume); - } - - result = afp_fill_file_info_response(unixname, afp_req + 9, path_len, + result = afp_fill_file_info_response(unixname, path_data, path_data_len, volume, afp_req[0] == 0x0f, response, &entry_id, &fallback); if (result < 0) { XDPRINTF((2,0, "%s stat failed: vol=%d entry=0x%08x path='%s' unix='%s' result=-0x%x errno=%d", call_name, (int)volume_number, request_entry_id, - visable_data(afp_req + 9, path_len), unixname, -result, errno)); + visable_data(path_data, path_data_len), unixname, -result, errno)); return(result); } XDPRINTF((3,0, "%s: vol=%d entry=0x%08x mask=0x%04x path='%s' reply_entry=0x%08x%s", call_name, (int)volume_number, request_entry_id, request_mask, - visable_data(afp_req + 9, path_len), entry_id, + visable_data(path_data, path_data_len), entry_id, fallback ? " fallback" : "")); return(result); } @@ -2064,6 +2127,9 @@ static int afp_set_file_information(uint8 *afp_req, int afp_len, int path_off; int path_volume; char unixname[PATH_MAX]; + char entry_path[512]; + int entry_path_len = 0; + int resolved_by_entry_id = 0; struct stat stbuff; int result; uint16 log_attrs = 0; @@ -2128,9 +2194,19 @@ static int afp_set_file_information(uint8 *afp_req, int afp_len, } if (!path_len) { - XDPRINTF((2,0, "%s rejected: entry-id-only lookup unsupported vol=%d entry=0x%08x mask=0x%04x", - call_name, (int)volume_number, request_entry_id, request_mask)); - return(-0x9c); /* Invalid Path until persistent entry-id lookup exists */ + result = afp_resolve_entry_id_path((int)volume_number, request_entry_id, + entry_path, sizeof(entry_path), + unixname, sizeof(unixname), + &path_volume, &entry_path_len); + if (result) { + XDPRINTF((2,0, "%s entry-id lookup failed: vol=%d entry=0x%08x mask=0x%04x result=-0x%x", + call_name, (int)volume_number, request_entry_id, + request_mask, -result)); + return(result); + } + path_data = (uint8 *)entry_path; + path_len = entry_path_len; + resolved_by_entry_id = 1; } if (request_mask & ~(AFP_FILE_BITMAP_ATTRIBUTES | AFP_FILE_BITMAP_ACCESS_DATE | @@ -2165,13 +2241,15 @@ static int afp_set_file_information(uint8 *afp_req, int afp_len, if (request_mask & AFP_FILE_BITMAP_FINDER_INFO) needs_afp_metadata_modify = 1; - path_volume = afp_resolve_path_volume(path_data, path_len, - unixname, sizeof(unixname)); - if (path_volume < 0) { - XDPRINTF((2,0, "%s path resolve failed: request_vol=%d entry=0x%08x mask=0x%04x path='%s' result=-0x%x", - call_name, (int)volume_number, request_entry_id, request_mask, - visable_data(path_data, path_len), -path_volume)); - return(path_volume); + if (!resolved_by_entry_id) { + path_volume = afp_resolve_path_volume(path_data, path_len, + unixname, sizeof(unixname)); + if (path_volume < 0) { + XDPRINTF((2,0, "%s path resolve failed: request_vol=%d entry=0x%08x mask=0x%04x path='%s' result=-0x%x", + call_name, (int)volume_number, request_entry_id, request_mask, + visable_data(path_data, path_len), -path_volume)); + return(path_volume); + } } if (stat(unixname, &stbuff)) {