nwconn: implement AFP entry id from NetWare handle
All checks were successful
Source release / source-package (push) Successful in 49s
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:
78
src/nwconn.c
78
src/nwconn.c
@@ -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);
|
||||
|
||||
@@ -23,8 +23,9 @@
|
||||
#define NCPC_SFN(FN, SFN) ((FN) | ((SFN) << 8) | NCPC_SUBFUNCTION)
|
||||
#endif
|
||||
|
||||
#define AFP_GET_ENTRY_ID_FROM_NAME 0x04
|
||||
#define AFP_GET_ENTRY_ID_FROM_PATH_NAME 0x0c
|
||||
#define AFP_GET_ENTRY_ID_FROM_NAME 0x04
|
||||
#define AFP_GET_ENTRY_ID_FROM_NETWARE_HANDLE 0x06
|
||||
#define AFP_GET_ENTRY_ID_FROM_PATH_NAME 0x0c
|
||||
#define NWE_INVALID_NAMESPACE 0xbf
|
||||
#define NWE_INVALID_PATH 0x9c
|
||||
#define AFP_TEMP_DH_NONE 0xff
|
||||
@@ -33,7 +34,7 @@ static void usage(const char *prog)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"Usage: %s [--allow-invalid-namespace] [--allow-invalid-path] "
|
||||
"[--from-name] [--volume N] [--entry-id ID] "
|
||||
"[--from-name] [--from-handle] [--volume N] [--entry-id ID] "
|
||||
"[--dir-handle N] [--alloc-handle] [--raw-path] [ncpfs options] PATH\n"
|
||||
"\n"
|
||||
"ncpfs options are parsed by ncp_initialize(), for example:\n"
|
||||
@@ -42,11 +43,12 @@ static void usage(const char *prog)
|
||||
"Examples:\n"
|
||||
" %s -S MARS -U SUPERVISOR -P secret SYS:PUBLIC\n"
|
||||
" %s --from-name -S MARS -U SUPERVISOR -P secret SYS:PUBLIC\n"
|
||||
" %s --from-handle -S MARS -U SUPERVISOR -P secret SYS:PUBLIC/pmdflts.ini\n"
|
||||
" %s --dir-handle 2 -S MARS -U SUPERVISOR -P secret PUBLIC\n"
|
||||
" %s --alloc-handle -S MARS -U SUPERVISOR -P secret SYS:PUBLIC\n"
|
||||
" %s --allow-invalid-namespace -S MARS SYS:PUBLIC\n"
|
||||
" %s --allow-invalid-path -S MARS SYS:NO_SUCH_PATH\n",
|
||||
prog, prog, prog, prog, prog, prog, prog);
|
||||
prog, prog, prog, prog, prog, prog, prog, prog);
|
||||
}
|
||||
|
||||
static int parse_u8(const char *text, unsigned int *value)
|
||||
@@ -194,13 +196,16 @@ int main(int argc, char **argv)
|
||||
int raw_path = 1;
|
||||
int alloc_handle = 0;
|
||||
int from_name = 0;
|
||||
int from_handle = 0;
|
||||
uint32_t volume_number = 0;
|
||||
uint32_t base_entry_id = 0;
|
||||
struct ncp_file_info opened_file;
|
||||
int opened_file_valid = 0;
|
||||
int i;
|
||||
size_t path_len;
|
||||
char volume[32];
|
||||
uint8_t request[1 + 4 + 1 + 255];
|
||||
uint8_t reply_buf[4];
|
||||
uint8_t reply_buf[6];
|
||||
NWCCODE err;
|
||||
|
||||
if (NWCallsInit(NULL, NULL)) {
|
||||
@@ -230,6 +235,12 @@ int main(int argc, char **argv)
|
||||
allow_invalid_path = 1;
|
||||
} else if (!strcmp(argv[i], "--from-name")) {
|
||||
from_name = 1;
|
||||
from_handle = 0;
|
||||
raw_path = 1;
|
||||
alloc_handle = 0;
|
||||
} else if (!strcmp(argv[i], "--from-handle")) {
|
||||
from_handle = 1;
|
||||
from_name = 0;
|
||||
raw_path = 1;
|
||||
alloc_handle = 0;
|
||||
} else if (!strcmp(argv[i], "--volume")) {
|
||||
@@ -300,16 +311,34 @@ int main(int argc, char **argv)
|
||||
allocated_dir_handle = dir_handle;
|
||||
}
|
||||
|
||||
if (from_handle) {
|
||||
memset(&opened_file, 0, sizeof(opened_file));
|
||||
err = ncp_open_file(conn, 0, request_path, 0, AR_READ_ONLY, &opened_file);
|
||||
if (err) {
|
||||
fprintf(stderr,
|
||||
"Open file failed before AFP request: completion=0x%02x (%u) path=%s request_path=%s\n",
|
||||
(unsigned int)err & 0xff, (unsigned int)err, path, request_path);
|
||||
deallocate_dir_handle(conn, allocated_dir_handle);
|
||||
ncp_close(conn);
|
||||
return 1;
|
||||
}
|
||||
opened_file_valid = 1;
|
||||
}
|
||||
|
||||
path_len = strlen(request_path);
|
||||
if (path_len > 255) {
|
||||
fprintf(stderr, "PATH is too long for AFP Get Entry ID From Path Name: %zu\n",
|
||||
path_len);
|
||||
if (opened_file_valid)
|
||||
(void)ncp_close_file(conn, opened_file.file_id);
|
||||
deallocate_dir_handle(conn, allocated_dir_handle);
|
||||
ncp_close(conn);
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (from_name) {
|
||||
if (from_handle) {
|
||||
memcpy(request, opened_file.file_id, 6);
|
||||
} else if (from_name) {
|
||||
request[0] = (uint8_t)volume_number;
|
||||
cpu_to_be32(base_entry_id, request + 1);
|
||||
request[5] = (uint8_t)path_len;
|
||||
@@ -325,17 +354,21 @@ int main(int argc, char **argv)
|
||||
reply.fragSize = sizeof(reply_buf);
|
||||
|
||||
err = NWRequestSimple(conn,
|
||||
NCPC_SFN(0x23, from_name
|
||||
? AFP_GET_ENTRY_ID_FROM_NAME
|
||||
: AFP_GET_ENTRY_ID_FROM_PATH_NAME),
|
||||
NCPC_SFN(0x23, from_handle
|
||||
? AFP_GET_ENTRY_ID_FROM_NETWARE_HANDLE
|
||||
: (from_name
|
||||
? AFP_GET_ENTRY_ID_FROM_NAME
|
||||
: AFP_GET_ENTRY_ID_FROM_PATH_NAME)),
|
||||
request,
|
||||
(from_name ? 6 : 2) + path_len,
|
||||
from_handle ? 6 : ((from_name ? 6 : 2) + path_len),
|
||||
&reply);
|
||||
|
||||
if (((unsigned int)err & 0xff) == NWE_INVALID_NAMESPACE && allow_invalid_namespace) {
|
||||
printf("AFP Get Entry ID returned invalid namespace "
|
||||
"as expected: path=%s request_path=%s dir_handle=%u\n",
|
||||
path, request_path, dir_handle);
|
||||
if (opened_file_valid)
|
||||
(void)ncp_close_file(conn, opened_file.file_id);
|
||||
deallocate_dir_handle(conn, allocated_dir_handle);
|
||||
ncp_close(conn);
|
||||
return 0;
|
||||
@@ -345,6 +378,8 @@ int main(int argc, char **argv)
|
||||
printf("AFP Get Entry ID returned invalid path "
|
||||
"as expected: path=%s request_path=%s dir_handle=%u\n",
|
||||
path, request_path, dir_handle);
|
||||
if (opened_file_valid)
|
||||
(void)ncp_close_file(conn, opened_file.file_id);
|
||||
deallocate_dir_handle(conn, allocated_dir_handle);
|
||||
ncp_close(conn);
|
||||
return 0;
|
||||
@@ -355,23 +390,37 @@ int main(int argc, char **argv)
|
||||
"AFP Get Entry ID From Path Name failed: completion=0x%02x (%u) path=%s request_path=%s dir_handle=%u\n",
|
||||
(unsigned int)err & 0xff, (unsigned int)err, path,
|
||||
request_path, dir_handle);
|
||||
if (opened_file_valid)
|
||||
(void)ncp_close_file(conn, opened_file.file_id);
|
||||
deallocate_dir_handle(conn, allocated_dir_handle);
|
||||
ncp_close(conn);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (reply.fragSize < 4) {
|
||||
if (reply.fragSize < (from_handle ? 6 : 4)) {
|
||||
fprintf(stderr, "short AFP reply: %zu bytes\n", reply.fragSize);
|
||||
if (opened_file_valid)
|
||||
(void)ncp_close_file(conn, opened_file.file_id);
|
||||
deallocate_dir_handle(conn, allocated_dir_handle);
|
||||
ncp_close(conn);
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("AFP Entry ID path=%s request_path=%s dir_handle=%u entry_id=0x%08x (%u)\n",
|
||||
path, request_path, dir_handle,
|
||||
(unsigned int)be32_to_cpu(reply_buf),
|
||||
(unsigned int)be32_to_cpu(reply_buf));
|
||||
if (from_handle) {
|
||||
printf("AFP Entry ID From NetWare Handle path=%s volume=%u entry_id=0x%08x (%u) fork=%u\n",
|
||||
path, (unsigned int)reply_buf[0],
|
||||
(unsigned int)be32_to_cpu(reply_buf + 1),
|
||||
(unsigned int)be32_to_cpu(reply_buf + 1),
|
||||
(unsigned int)reply_buf[5]);
|
||||
} else {
|
||||
printf("AFP Entry ID path=%s request_path=%s dir_handle=%u entry_id=0x%08x (%u)\n",
|
||||
path, request_path, dir_handle,
|
||||
(unsigned int)be32_to_cpu(reply_buf),
|
||||
(unsigned int)be32_to_cpu(reply_buf));
|
||||
}
|
||||
|
||||
if (opened_file_valid)
|
||||
(void)ncp_close_file(conn, opened_file.file_id);
|
||||
deallocate_dir_handle(conn, allocated_dir_handle);
|
||||
ncp_close(conn);
|
||||
return 0;
|
||||
|
||||
Reference in New Issue
Block a user