From ca610c110061680be62efbe0a0e47993d469e599 Mon Sep 17 00:00:00 2001 From: ChatGPT Date: Sat, 30 May 2026 09:09:07 +0000 Subject: [PATCH] nwatalk: probe mars_nwe AFP entry ids from xattrs Add the first mars_nwe-owned AFP metadata xattr reader before expanding the AFP write surface. The new versioned org.mars-nwe.afp.entry-id payload gives the compatibility layer a stable, project-owned namespace for persistent AFP entry ids without reusing the unreleased user.mars_nwe.* test names or pretending that Netatalk-owned org.netatalk.* keys are ours to mutate. The lookup order remains conservative: an existing mars_nwe entry-id xattr wins, then the optional Netatalk/libatalk AppleDouble/CNID helper is consulted, and the AFP handlers continue to fall back to their stat-derived temporary id when no persistent metadata exists. No Set File Information, CNID allocation, Finder Info write, or resource-fork write path is introduced here. This keeps the WebSDK/NWAFP read-only endpoint semantics intact while preparing the metadata storage boundary needed by later AFP Set File Information and CNID work. ENABLE_NETATALK_LIBATALK=OFF still rejects AFP calls at the handler guard, and the xattr reader has an XATTR_SUPPORT-disabled stub so non-xattr builds keep compiling. Tests: - git diff --check - cmake --build build-xattr-off --target nwconn - cmake -S . -B build-afp-on -DENABLE_NETATALK_LIBATALK=ON -DCMAKE_PREFIX_PATH=/mnt/data/afp_build_prefix - cmake --build build-afp-on --target nwconn TODO: - Add a deliberate write-safe AFP metadata writer/allocator before enabling AFP 2.0 Set File Information. - Decide whether future mars_nwe AFP metadata stays split across org.mars-nwe.afp.* keys or moves into a compact org.mars-nwe.afp.metadata record. --- TODO.md | 11 ++++-- src/nwatalk.c | 80 +++++++++++++++++++++++++++++++++++-------- tests/linux/README.md | 7 ++++ 3 files changed, 81 insertions(+), 17 deletions(-) diff --git a/TODO.md b/TODO.md index 5dd810c..32074fb 100644 --- a/TODO.md +++ b/TODO.md @@ -271,9 +271,14 @@ Follow-up: data/resource fork and Finder Info semantics. - Replace the temporary stat-derived AFP entry-id fallback with a persistent CNID/directory-id mapping once the libatalk/CNID backend is integrated. -- Put future mars_nwe-owned AFP metadata under `org.mars-nwe.afp.*` (or a - compact `org.mars-nwe.afp.metadata` record) and keep Netatalk-owned metadata - under Netatalk's own `org.netatalk.*` keys. +- mars_nwe-owned AFP entry ids are probed first from the versioned + `org.mars-nwe.afp.entry-id` xattr before consulting Netatalk/libatalk + AppleDouble/CNID metadata and, finally, the stat-derived fallback. No AFP + metadata write path exists yet; Set File Information and CNID allocation + still need a deliberate write-safe design. +- Put additional future mars_nwe-owned AFP metadata under `org.mars-nwe.afp.*` + (or a compact `org.mars-nwe.afp.metadata` record) and keep Netatalk-owned + metadata under Netatalk's own `org.netatalk.*` keys. - Extend the Linux AFP smoke tests once additional AFP subfunctions are implemented, especially Finder Info updates, fork open/read/write paths, resource-fork handling, and broader directory-scan edge cases. diff --git a/src/nwatalk.c b/src/nwatalk.c index 3aeeeb9..4f937d0 100644 --- a/src/nwatalk.c +++ b/src/nwatalk.c @@ -6,12 +6,58 @@ #include +#if XATTR_SUPPORT +#include +#include +#endif + #if NETATALK_SUPPORT -#include #include #include #endif +#define MARS_NWE_AFP_ENTRY_ID_XATTR "org.mars-nwe.afp.entry-id" +#define MARS_NWE_AFP_ENTRY_ID_VERSION 1 + +typedef struct { + uint8 version; + uint8 reserved[3]; + uint8 entry_id[4]; +} MARS_NWE_AFP_ENTRY_ID_XATTR_DATA; + + +#if XATTR_SUPPORT +static int nwatalk_get_mars_entry_id_xattr(const char *path, uint32 *entry_id) +{ + MARS_NWE_AFP_ENTRY_ID_XATTR_DATA d; + ssize_t len; + uint32 id; + + if (!entry_id) return(-0x9c); + *entry_id = 0; + if (!path || !*path) return(-0x9c); + + memset(&d, 0, sizeof(d)); + len = getxattr(path, MARS_NWE_AFP_ENTRY_ID_XATTR, &d, sizeof(d)); + if (len != sizeof(d) || d.version != MARS_NWE_AFP_ENTRY_ID_VERSION) + return(-0x9c); + + id = GET_BE32(d.entry_id); + id &= 0x7fffffffU; + if (!id) return(-0x9c); + + *entry_id = id; + return(0); +} +#else +static int nwatalk_get_mars_entry_id_xattr(const char *path, uint32 *entry_id) +{ + (void)path; + if (entry_id) *entry_id = 0; + return(-0xbf); +} +#endif + int nwatalk_backend_available(void) { #if NETATALK_SUPPORT @@ -104,29 +150,35 @@ int nwatalk_get_resource_fork_size(const char *path, uint32 *resource_size) int nwatalk_get_entry_id(const char *path, uint32 *entry_id) { -#if NETATALK_SUPPORT - struct adouble ad; - struct stat stbuff; - uint32_t id; int result; if (!entry_id) return(-0x9c); *entry_id = 0; if (!path || !*path) return(-0x9c); - if (stat(path, &stbuff)) return(-0x9c); + result = nwatalk_get_mars_entry_id_xattr(path, entry_id); + if (!result && *entry_id) + return(0); - result = nwatalk_open_adouble(path, &ad); - if (result < 0) return(result); +#if NETATALK_SUPPORT + { + struct adouble ad; + struct stat stbuff; + uint32_t id; - id = ad_getid(&ad, stbuff.st_dev, stbuff.st_ino, 0, NULL); - if (id) *entry_id = (uint32)id; + if (stat(path, &stbuff)) return(-0x9c); - ad_close(&ad, 0); - return(id ? 0 : -0x9c); + result = nwatalk_open_adouble(path, &ad); + if (result < 0) return(result); + + id = ad_getid(&ad, stbuff.st_dev, stbuff.st_ino, 0, NULL); + if (id) *entry_id = (uint32)id; + + ad_close(&ad, 0); + return(id ? 0 : -0x9c); + } #else - (void)path; - (void)entry_id; + (void)result; return(-0xbf); /* invalid namespace / backend unavailable */ #endif } diff --git a/tests/linux/README.md b/tests/linux/README.md index c0507ec..e1a4cb4 100644 --- a/tests/linux/README.md +++ b/tests/linux/README.md @@ -7,6 +7,13 @@ The tests use the ncpfs/libncp client library. They are not built by default because they require the host ncpfs development headers/library and a running NetWare-compatible server. +The AFP endpoints are intentionally conservative. When persistent AFP entry +ids become available, mars_nwe-owned ids are read from the versioned +`org.mars-nwe.afp.entry-id` xattr before falling back to Netatalk/libatalk +AppleDouble/CNID metadata and then the temporary stat-derived fallback. The +current smoke tests do not write AFP metadata; Set File Information and CNID +allocation remain separate write-safety work. + Build with: ```sh