nwconn: implement AFP entry id from NetWare handle
All checks were successful
Source release / source-package (push) Successful in 49s

Wire NCP 0x23/0x06 AFP Get Entry ID From NetWare Handle to the existing AFP entry-id backend.

The WebSDK documents NCP 0x2222/35/06 as taking a 6-byte NetWare file handle and returning the volume number, a 32-bit AFP Entry ID, and a fork indicator. The SDK headers expose the same operation as AFPGetEntryIDFromNetWareHandle() and NWAFPGetEntryIDFromNetWareHandle().

Use the connection-local mars_nwe file handle table to map the supplied NetWare file handle back to its Unix path, require the optional libatalk backend as for the other AFP calls, and then return a libatalk Entry ID when available or the existing stat-derived fallback ID otherwise. Report the data fork for now because mars_nwe does not yet expose AFP resource-fork open semantics.

Extend the Linux AFP entry-id smoke test with --from-handle. The test opens the requested file through libncp in the same connection, sends the returned 6-byte NetWare file handle to the AFP call, and closes the file afterwards.

This implements the read-only data-fork handle-to-entry-id path; persistent CNID mapping and resource-fork handle semantics remain future work.
This commit is contained in:
Mario Fetka
2026-05-30 07:07:32 +00:00
parent 8cd0cad6fb
commit a10f256b77
2 changed files with 140 additions and 17 deletions

View File

@@ -450,6 +450,20 @@ static int afp_request_offset(void)
return(0);
}
static int afp_volume_from_unixname(const char *unixname)
{
int k;
if (!unixname) return(-1);
for (k = 0; k < used_nw_volumes; k++) {
int len = nw_volumes[k].unixnamlen;
if (len > 0 && !strncmp(unixname, (char *)nw_volumes[k].unixname, len))
return(k);
}
return(-1);
}
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
@@ -544,6 +558,59 @@ static int afp_get_entry_id_from_name(uint8 *afp_req, int afp_len,
return(4);
}
static int afp_get_entry_id_from_netware_handle(uint8 *afp_req, int afp_len,
uint8 *response)
{
uint32 fhandle;
uint8 *unixname;
int volume;
struct stat stbuff;
uint32 entry_id = 0;
int result;
if (afp_len < 7) {
XDPRINTF((2,0, "AFP Get Entry ID From NetWare Handle rejected: short request len=%d",
afp_len));
return(-0x7e); /* NCP Boundary Check Failed */
}
fhandle = GET_32(afp_req + 3); /* bytes 1..2 are the extended handle */
unixname = file_get_unix_name(fhandle);
if (!unixname) {
XDPRINTF((2,0, "AFP Get Entry ID From NetWare Handle rejected: bad handle=%u",
fhandle));
return(-0x88); /* Invalid File Handle */
}
if (!nwatalk_backend_available()) {
XDPRINTF((3,0, "AFP Get Entry ID From NetWare Handle rejected: libatalk backend unavailable"));
return(-0xbf); /* invalid namespace */
}
if (stat((char *)unixname, &stbuff)) {
XDPRINTF((2,0, "AFP Get Entry ID From NetWare Handle stat failed: handle=%u unix='%s' errno=%d",
fhandle, unixname, errno));
return(-0x88); /* Invalid File Handle */
}
volume = afp_volume_from_unixname((char *)unixname);
if (volume < 0) volume = 0;
result = nwatalk_get_entry_id((char *)unixname, &entry_id);
if (result < 0 || !entry_id)
entry_id = afp_fallback_entry_id(volume, &stbuff);
response[0] = (uint8)volume;
U32_TO_BE32(entry_id, response + 1);
response[5] = 0; /* data fork */
XDPRINTF((3,0, "AFP Get Entry ID From NetWare Handle: handle=%u volume=%d unix='%s' entry=0x%08x%s",
fhandle, volume, unixname, entry_id,
(result < 0) ? " fallback" : ""));
return(6);
}
static int afp_get_entry_id_from_path_name(uint8 *afp_req, int afp_len,
uint8 *response)
{
@@ -2900,8 +2967,10 @@ static int handle_ncp_serv(void)
* Get Entry ID From Name call accepts a volume/base AFP ID
* plus a modifying path string; until persistent CNID/base
* lookup exists, support the same path-backed SYS:-style
* smoke-test subset. Then expose the
* read-only AFP Get File Information query for the same
* smoke-test subset. Get Entry ID From NetWare Handle
* maps an already-open mars_nwe file handle back to its
* Unix path and returns the corresponding AFP ID. Then expose
* the read-only AFP Get File Information query for the same
* SYS:-style path inputs. AFP 2.0 Get File Information
* uses the same request/reply layout for this read-only
* path-backed subset, so route it through the same helper
@@ -2915,6 +2984,11 @@ static int handle_ncp_serv(void)
afp_len, responsedata);
if (result > -1) data_len = result;
else completition = (uint8)-result;
} else if (ufunc == 0x06) {
int result = afp_get_entry_id_from_netware_handle(afp_req,
afp_len, responsedata);
if (result > -1) data_len = result;
else completition = (uint8)-result;
} else if (ufunc == 0x0c) {
int result = afp_get_entry_id_from_path_name(afp_req,
afp_len, responsedata);