/* mars_nwe AFP xattr metadata backend helpers. */ #include "net.h" #include "config.h" #include "nwatalk.h" #include "nwxattr.h" #include "tools.h" #include #if XATTR_SUPPORT #include #endif #define MARS_NWE_AFP_ENTRY_ID_XATTR "org.mars-nwe.afp.entry-id" #define MARS_NWE_AFP_FINDER_INFO_XATTR "org.mars-nwe.afp.finder-info" #define MARS_NWE_AFP_ATTRIBUTES_XATTR "org.mars-nwe.afp.attributes" #define MARS_NWE_AFP_ENTRY_ID_VERSION 1 #define MARS_NWE_AFP_ATTRIBUTES_VERSION 1 #define NWATALK_AFP_ATTR_HIDDEN 0x0200 #define NWATALK_AFP_ATTR_SYSTEM 0x0400 #define NWATALK_AFP_ATTR_SETCLR 0x8000 #define NWATALK_AFP_ATTR_STORED_MASK \ (NWATALK_AFP_ATTR_HIDDEN | NWATALK_AFP_ATTR_SYSTEM) typedef struct { uint8 version; uint8 reserved[3]; uint8 entry_id[4]; } MARS_NWE_AFP_ENTRY_ID_XATTR_DATA; typedef struct { uint8 version; uint8 reserved; uint8 attributes[2]; } MARS_NWE_AFP_ATTRIBUTES_XATTR_DATA; int nwatalk_backend_available(void) { #if XATTR_SUPPORT return(1); #else return(0); #endif } #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 = mars_nwe_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_get_finder_info(const char *path, uint8 *finder_info, int finder_info_len) { #if XATTR_SUPPORT ssize_t len; #endif if (!finder_info || finder_info_len < NWATALK_FINDER_INFO_LEN) { return(-0x9c); } memset(finder_info, 0, finder_info_len); #if XATTR_SUPPORT if (path && *path) { len = mars_nwe_getxattr(path, MARS_NWE_AFP_FINDER_INFO_XATTR, finder_info, NWATALK_FINDER_INFO_LEN); if (len == NWATALK_FINDER_INFO_LEN) return(0); memset(finder_info, 0, finder_info_len); } #else (void)path; #endif /* Missing FinderInfo is a valid AFP state; absent metadata reads as zeroes. */ return(0); } int nwatalk_set_finder_info(const char *path, const uint8 *finder_info, int finder_info_len) { #if XATTR_SUPPORT if (!path || !*path || !finder_info || finder_info_len < NWATALK_FINDER_INFO_LEN) return(-0x9c); if (mars_nwe_setxattr(path, MARS_NWE_AFP_FINDER_INFO_XATTR, finder_info, NWATALK_FINDER_INFO_LEN, 0)) { int err = errno; XDPRINTF((3,0,"AFP FinderInfo xattr write failed for %s errno=%d", path, err)); return(-0x8c); /* no write privileges / cannot persist metadata */ } return(0); #else (void)path; (void)finder_info; (void)finder_info_len; return(-0xbf); /* invalid namespace / xattrs unavailable */ #endif } int nwatalk_get_afp_attributes(const char *path, uint16 *attributes) { #if XATTR_SUPPORT MARS_NWE_AFP_ATTRIBUTES_XATTR_DATA d; ssize_t len; #endif if (!attributes) return(-0x9c); *attributes = 0; if (!path || !*path) return(-0x9c); #if XATTR_SUPPORT memset(&d, 0, sizeof(d)); len = mars_nwe_getxattr(path, MARS_NWE_AFP_ATTRIBUTES_XATTR, &d, sizeof(d)); if (len == sizeof(d) && d.version == MARS_NWE_AFP_ATTRIBUTES_VERSION) { *attributes = GET_BE16(d.attributes) & NWATALK_AFP_ATTR_STORED_MASK; return(0); } #else (void)path; #endif return(-0x9c); } int nwatalk_set_afp_attributes(const char *path, uint16 attributes) { #if XATTR_SUPPORT MARS_NWE_AFP_ATTRIBUTES_XATTR_DATA d; uint16 stored = 0; uint16 requested = attributes & ~NWATALK_AFP_ATTR_SETCLR; uint16 current = 0; if (!path || !*path) return(-0x9c); if (requested & ~NWATALK_AFP_ATTR_STORED_MASK) { XDPRINTF((3,0,"AFP attributes xattr write rejected for %s attrs=0x%04x", path, attributes)); return(-0x9c); } (void)nwatalk_get_afp_attributes(path, ¤t); if (attributes & NWATALK_AFP_ATTR_SETCLR) stored = current | requested; else stored = current & ~requested; memset(&d, 0, sizeof(d)); d.version = MARS_NWE_AFP_ATTRIBUTES_VERSION; U16_TO_BE16(stored, d.attributes); if (mars_nwe_setxattr(path, MARS_NWE_AFP_ATTRIBUTES_XATTR, &d, sizeof(d), 0)) { int err = errno; XDPRINTF((3,0,"AFP attributes xattr write failed for %s attrs=0x%04x errno=%d", path, stored, err)); return(-0x8c); } return(0); #else (void)path; (void)attributes; return(-0xbf); #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) { (void)path; if (!resource_size) return(-0x9c); *resource_size = 0; return(0); } int nwatalk_get_entry_id(const char *path, uint32 *entry_id) { if (!entry_id) return(-0x9c); *entry_id = 0; if (!path || !*path) return(-0x9c); return(nwatalk_get_mars_entry_id_xattr(path, entry_id)); }