nwatalk: cache AFP fallback entry ids in xattrs
All checks were successful
Source release / source-package (push) Successful in 48s
All checks were successful
Source release / source-package (push) Successful in 48s
The AFP smoke endpoints can now read mars_nwe-owned entry ids from the versioned org.mars-nwe.afp.entry-id xattr, but a newly discovered file still had to fall back to the temporary stat-derived id on every request until a real CNID allocator exists. Preserve the existing WebSDK/NWAFP response semantics while making that fallback sticky: when Get Entry ID, Get File Information, or Scan File Information has no mars_nwe xattr and no Netatalk/libatalk AppleDouble/CNID id, derive the existing compatibility id and cache it through nwatalk_set_entry_id(). The first request still logs fallback so diagnostics remain honest about the id origin; subsequent requests should read the xattr directly and avoid re-entering the stat fallback path. Keep the write narrowly scoped to mars_nwe's private AFP metadata namespace. The payload is versioned, big-endian, and stored through the nwxattr helper, so Linux persists it as user.org.mars-nwe.afp.entry-id while source-level code continues to use the Netatalk-style org.mars-nwe.afp.entry-id name. This does not implement CNID allocation, parent-id lookup, entry-id-only resolution, FinderInfo mutation beyond the existing smoke path, or resource-fork semantics. Tests: - git diff --check - cmake --build build-xattr-off --target nwconn with ENABLE_NETATALK_LIBATALK=OFF - cmake --build build-xattr-on --target nwconn with ENABLE_NETATALK_LIBATALK=ON against Netatalk 4.4.3 headers plus local link stubs
This commit is contained in:
@@ -156,6 +156,36 @@ int nwatalk_set_finder_info(const char *path, const uint8 *finder_info,
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int nwatalk_set_entry_id(const char *path, uint32 entry_id)
|
||||
{
|
||||
#if XATTR_SUPPORT
|
||||
MARS_NWE_AFP_ENTRY_ID_XATTR_DATA d;
|
||||
|
||||
if (!path || !*path) return(-0x9c);
|
||||
entry_id &= 0x7fffffffU;
|
||||
if (!entry_id) return(-0x9c);
|
||||
|
||||
memset(&d, 0, sizeof(d));
|
||||
d.version = MARS_NWE_AFP_ENTRY_ID_VERSION;
|
||||
U32_TO_BE32(entry_id, d.entry_id);
|
||||
|
||||
if (mars_nwe_setxattr(path, MARS_NWE_AFP_ENTRY_ID_XATTR,
|
||||
&d, sizeof(d), 0)) {
|
||||
int err = errno;
|
||||
XDPRINTF((5,0,"AFP entry-id xattr write ignored for %s entry=0x%08x errno=%d",
|
||||
path, entry_id, err));
|
||||
return(-0x8c);
|
||||
}
|
||||
|
||||
return(0);
|
||||
#else
|
||||
(void)path;
|
||||
(void)entry_id;
|
||||
return(-0xbf);
|
||||
#endif
|
||||
}
|
||||
|
||||
int nwatalk_get_resource_fork_size(const char *path, uint32 *resource_size)
|
||||
{
|
||||
#if NETATALK_SUPPORT
|
||||
|
||||
61
src/nwconn.c
61
src/nwconn.c
@@ -507,6 +507,34 @@ static uint32 afp_fallback_entry_id(int volume, const struct stat *stb)
|
||||
}
|
||||
|
||||
|
||||
|
||||
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.
|
||||
*/
|
||||
{
|
||||
uint32 entry_id = 0;
|
||||
int result;
|
||||
|
||||
result = nwatalk_get_entry_id(unixname, &entry_id);
|
||||
if (!result && entry_id) {
|
||||
if (fallback_out) *fallback_out = 0;
|
||||
return(entry_id);
|
||||
}
|
||||
|
||||
entry_id = afp_fallback_entry_id(volume, stb);
|
||||
if (fallback_out) *fallback_out = 1;
|
||||
(void)nwatalk_set_entry_id(unixname, entry_id);
|
||||
return(entry_id);
|
||||
}
|
||||
|
||||
static int afp_get_entry_id_from_name(uint8 *afp_req, int afp_len,
|
||||
uint8 *response)
|
||||
{
|
||||
@@ -561,15 +589,13 @@ static int afp_get_entry_id_from_name(uint8 *afp_req, int afp_len,
|
||||
return(-0x9c); /* Invalid Path */
|
||||
}
|
||||
|
||||
result = nwatalk_get_entry_id(unixname, &entry_id);
|
||||
if (result < 0 || !entry_id)
|
||||
entry_id = afp_fallback_entry_id(volume, &stbuff);
|
||||
entry_id = afp_get_or_create_entry_id(unixname, volume, &stbuff, &result);
|
||||
|
||||
U32_TO_BE32(entry_id, response);
|
||||
XDPRINTF((3,0, "AFP Get Entry ID From Name: vol=%d entry=0x%08x path='%s' reply_entry=0x%08x%s",
|
||||
(int)volume_number, request_entry_id,
|
||||
visable_data(afp_req + 7, path_len), entry_id,
|
||||
(result < 0) ? " fallback" : ""));
|
||||
result ? " fallback" : ""));
|
||||
return(4);
|
||||
}
|
||||
|
||||
@@ -612,9 +638,7 @@ static int afp_get_entry_id_from_netware_handle(uint8 *afp_req, int afp_len,
|
||||
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);
|
||||
entry_id = afp_get_or_create_entry_id((char *)unixname, volume, &stbuff, &result);
|
||||
|
||||
response[0] = (uint8)volume;
|
||||
U32_TO_BE32(entry_id, response + 1);
|
||||
@@ -622,7 +646,7 @@ static int afp_get_entry_id_from_netware_handle(uint8 *afp_req, int afp_len,
|
||||
|
||||
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" : ""));
|
||||
result ? " fallback" : ""));
|
||||
return(6);
|
||||
}
|
||||
|
||||
@@ -844,14 +868,12 @@ static int afp_get_entry_id_from_path_name(uint8 *afp_req, int afp_len,
|
||||
return(-0x9c); /* Invalid Path */
|
||||
}
|
||||
|
||||
result = nwatalk_get_entry_id(unixname, &entry_id);
|
||||
if (result < 0 || !entry_id)
|
||||
entry_id = afp_fallback_entry_id(volume, &stbuff);
|
||||
entry_id = afp_get_or_create_entry_id(unixname, volume, &stbuff, &result);
|
||||
|
||||
U32_TO_BE32(entry_id, response);
|
||||
XDPRINTF((3,0, "AFP Get Entry ID From Path Name: dh=%d path='%s' entry=0x%08x%s",
|
||||
(int)dir_handle, visable_data(afp_req + 3, path_len), entry_id,
|
||||
(result < 0) ? " fallback" : ""));
|
||||
result ? " fallback" : ""));
|
||||
return(4);
|
||||
}
|
||||
|
||||
@@ -956,16 +978,11 @@ static int afp_fill_file_info_response(const char *unixname,
|
||||
uint32 parent_id = 0;
|
||||
uint32 resource_size = 0;
|
||||
uint8 finder_info[NWATALK_FINDER_INFO_LEN];
|
||||
int result;
|
||||
|
||||
if (stat(unixname, &stbuff))
|
||||
return(-0x9c); /* Invalid Path */
|
||||
|
||||
result = nwatalk_get_entry_id(unixname, &entry_id);
|
||||
if (result < 0 || !entry_id) {
|
||||
entry_id = afp_fallback_entry_id(volume, &stbuff);
|
||||
if (fallback_out) *fallback_out = 1;
|
||||
} else if (fallback_out) *fallback_out = 0;
|
||||
entry_id = afp_get_or_create_entry_id(unixname, volume, &stbuff, fallback_out);
|
||||
|
||||
memset(response, 0, 120);
|
||||
U32_TO_BE32(entry_id, response + 0);
|
||||
@@ -1280,7 +1297,6 @@ static int afp_scan_file_information(uint8 *afp_req, int afp_len,
|
||||
struct stat stbuff;
|
||||
int child_fallback = 0;
|
||||
uint32 child_entry_id = 0;
|
||||
int child_result;
|
||||
|
||||
if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
|
||||
continue;
|
||||
@@ -1289,11 +1305,8 @@ static int afp_scan_file_information(uint8 *afp_req, int afp_len,
|
||||
if (stat(childname, &stbuff))
|
||||
continue;
|
||||
|
||||
child_result = nwatalk_get_entry_id(childname, &child_entry_id);
|
||||
if (child_result < 0 || !child_entry_id) {
|
||||
child_entry_id = afp_fallback_entry_id(volume, &stbuff);
|
||||
child_fallback = 1;
|
||||
}
|
||||
child_entry_id = afp_get_or_create_entry_id(childname, volume, &stbuff,
|
||||
&child_fallback);
|
||||
|
||||
if (last_seen_id && !seen) {
|
||||
if (child_entry_id == last_seen_id)
|
||||
|
||||
Reference in New Issue
Block a user