Files
mars-nwe/src/nwatalk.c
2026-05-31 06:15:03 +02:00

242 lines
5.8 KiB
C

/* mars_nwe AFP xattr metadata backend helpers. */
#include "net.h"
#include "config.h"
#include "nwatalk.h"
#include "nwxattr.h"
#include "tools.h"
#include <string.h>
#if XATTR_SUPPORT
#include <errno.h>
#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, &current);
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));
}