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