This commit is contained in:
+14
-11
@@ -2289,14 +2289,15 @@ MAC_METADATA_LAYOUT packed layout value 1
|
||||
MAC_RF data-stream name for the Mac resource fork
|
||||
```
|
||||
|
||||
Therefore the post-pl27 mars-nwe AFP target is to replace
|
||||
`org.mars-nwe.afp.*` xattrs with NSS-style metadata/data-stream storage. Since
|
||||
this code has not been released to users since the pl27 line, there is no need
|
||||
for fallback, migration, or mirror support for those private xattrs. If Mac
|
||||
metadata packing requires changes to `netware.metadata` writer logic, trustee
|
||||
variable-length handling, or root-variable-data packing, improve those pieces; do
|
||||
not create a parallel `netware.macmetadata` convenience store unless later full
|
||||
NSS evidence proves that is the actual Linux xattr boundary.
|
||||
Therefore mars-nwe AFP metadata must not use the old private
|
||||
`org.mars-nwe.afp.*` xattr family. On real NSS, AFP/Mac state belongs in
|
||||
NSS-style `zMacInfo_s`/`PackedMacInfo_s` metadata and `MAC_RF` streams. On the
|
||||
OtherFS/xattr backend, store the same AFP-facing state through Netatalk-family
|
||||
xattrs: `org.netatalk.Metadata` for AppleDouble `adouble:ea` FinderInfo and
|
||||
CNID/entry-id metadata, `org.netatalk.ProDOS` for AFP 2.0 ProDOSInfo, and
|
||||
`org.netatalk.ResourceFork` for resource-fork data. Since the private xattr
|
||||
code has not been released to users since the pl27 line, there is no need for
|
||||
fallback, migration, or mirror support for those private xattrs.
|
||||
|
||||
Salvage must preserve and restore the same NSS-style Mac metadata and later the
|
||||
`MAC_RF` resource fork stream. The current AFP NCP handlers may remain the
|
||||
@@ -2403,8 +2404,9 @@ nss/public_core/comn/namespace/
|
||||
|
||||
nss/public_core/comn/namespace/macNSpace.c and shared/sdk/internal/macNSpace.h
|
||||
Mac metadata packing/unpacking and namespace rules. Use the NSS
|
||||
zMacInfo_s/PackedMacInfo_s/RVD_MAC_META_DATA model; replace private
|
||||
org.mars-nwe.afp.* xattrs instead of migrating them.
|
||||
zMacInfo_s/PackedMacInfo_s/RVD_MAC_META_DATA model for real NSS volumes;
|
||||
OtherFS/xattr AFP metadata uses Netatalk-family xattrs instead of private
|
||||
org.mars-nwe.afp.* xattrs.
|
||||
|
||||
nss/public_core/comn/common/comnMacintosh.c
|
||||
Mac resource fork data-stream lookup/creation and the `MAC_RF` stream name.
|
||||
@@ -2621,7 +2623,8 @@ release:
|
||||
5. nwattrib.c -> read/write fileAttributes through libnwfs metadata
|
||||
6. trustee.c -> store trustees and inherited-rights-mask in netware.metadata
|
||||
7. nwatalk/AFP -> replace private org.mars-nwe.afp.* xattrs with NSS-style
|
||||
zMacInfo_s/PackedMacInfo_s metadata and MAC_RF streams
|
||||
zMacInfo_s/PackedMacInfo_s metadata on NSS and
|
||||
Netatalk-family xattrs on OtherFS
|
||||
8. nwarchive.c -> merge private mars-nwe archive/fileinfo xattrs into metadata
|
||||
9. salvage -> snapshot/restore the same metadata, including AFP/archive state
|
||||
10. MARS_NWE_4 -> keep NetWare 4.x namespace-aware variants, compression
|
||||
|
||||
+234
-91
@@ -14,7 +14,7 @@
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
/* mars_nwe AFP xattr metadata backend helpers. */
|
||||
/* Netatalk adouble:ea AFP xattr metadata backend helpers. */
|
||||
#include "net.h"
|
||||
#include "config.h"
|
||||
#include "nwatalk.h"
|
||||
@@ -22,17 +22,56 @@
|
||||
#include "tools.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <sys/stat.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_PRODOS_INFO_XATTR "org.mars-nwe.afp.prodos-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_AD_EA_META_XATTR "org.netatalk.Metadata"
|
||||
#define NWATALK_AD_EA_RESO_XATTR "org.netatalk.ResourceFork"
|
||||
#define NWATALK_AD_EA_PRODOS_XATTR "org.netatalk.ProDOS"
|
||||
|
||||
#define NWATALK_AD_MAGIC 0x00051607U
|
||||
#define NWATALK_AD_VERSION_EA 0x00020002U
|
||||
#define NWATALK_AD_HEADER_LEN 26
|
||||
#define NWATALK_AD_ENTRY_LEN 12
|
||||
#define NWATALK_AD_ENTRY_COUNT 8
|
||||
#define NWATALK_AD_DATASZ_EA 402
|
||||
|
||||
#define NWATALK_ADEID_FINDERI 9U
|
||||
#define NWATALK_ADEID_COMMENT 4U
|
||||
#define NWATALK_ADEID_FILEDATESI 8U
|
||||
#define NWATALK_ADEID_AFPFILEI 14U
|
||||
#define NWATALK_ADEID_PRIVDEV 0x80444556U
|
||||
#define NWATALK_ADEID_PRIVINO 0x80494e4fU
|
||||
#define NWATALK_ADEID_PRIVSYN 0x8053594eU
|
||||
#define NWATALK_ADEID_PRIVID 0x8053567eU
|
||||
|
||||
#define NWATALK_ADEDLEN_COMMENT 200
|
||||
#define NWATALK_ADEDLEN_FILEDATESI 16
|
||||
#define NWATALK_ADEDLEN_AFPFILEI 4
|
||||
#define NWATALK_ADEDLEN_PRIVDEV 8
|
||||
#define NWATALK_ADEDLEN_PRIVINO 8
|
||||
#define NWATALK_ADEDLEN_PRIVSYN 8
|
||||
#define NWATALK_ADEDLEN_PRIVID 4
|
||||
|
||||
#define NWATALK_ADEDOFF_FINDERI \
|
||||
(NWATALK_AD_HEADER_LEN + NWATALK_AD_ENTRY_COUNT * NWATALK_AD_ENTRY_LEN)
|
||||
#define NWATALK_ADEDOFF_COMMENT \
|
||||
(NWATALK_ADEDOFF_FINDERI + NWATALK_FINDER_INFO_LEN)
|
||||
#define NWATALK_ADEDOFF_FILEDATESI \
|
||||
(NWATALK_ADEDOFF_COMMENT + NWATALK_ADEDLEN_COMMENT)
|
||||
#define NWATALK_ADEDOFF_AFPFILEI \
|
||||
(NWATALK_ADEDOFF_FILEDATESI + NWATALK_ADEDLEN_FILEDATESI)
|
||||
#define NWATALK_ADEDOFF_PRIVDEV \
|
||||
(NWATALK_ADEDOFF_AFPFILEI + NWATALK_ADEDLEN_AFPFILEI)
|
||||
#define NWATALK_ADEDOFF_PRIVINO \
|
||||
(NWATALK_ADEDOFF_PRIVDEV + NWATALK_ADEDLEN_PRIVDEV)
|
||||
#define NWATALK_ADEDOFF_PRIVSYN \
|
||||
(NWATALK_ADEDOFF_PRIVINO + NWATALK_ADEDLEN_PRIVINO)
|
||||
#define NWATALK_ADEDOFF_PRIVID \
|
||||
(NWATALK_ADEDOFF_PRIVSYN + NWATALK_ADEDLEN_PRIVSYN)
|
||||
|
||||
#define NWATALK_AFP_ATTR_HIDDEN 0x0200
|
||||
#define NWATALK_AFP_ATTR_SYSTEM 0x0400
|
||||
@@ -40,18 +79,6 @@
|
||||
#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
|
||||
@@ -62,22 +89,162 @@ int nwatalk_backend_available(void)
|
||||
}
|
||||
|
||||
#if XATTR_SUPPORT
|
||||
static int nwatalk_get_mars_entry_id_xattr(const char *path, uint32 *entry_id)
|
||||
typedef struct {
|
||||
uint32 id;
|
||||
uint32 off;
|
||||
uint32 len;
|
||||
} NWATALK_AD_ENTRY;
|
||||
|
||||
static const NWATALK_AD_ENTRY nwatalk_ad_entries[NWATALK_AD_ENTRY_COUNT] = {
|
||||
{ NWATALK_ADEID_FINDERI, NWATALK_ADEDOFF_FINDERI, NWATALK_FINDER_INFO_LEN },
|
||||
{ NWATALK_ADEID_COMMENT, NWATALK_ADEDOFF_COMMENT, NWATALK_ADEDLEN_COMMENT },
|
||||
{ NWATALK_ADEID_FILEDATESI, NWATALK_ADEDOFF_FILEDATESI, NWATALK_ADEDLEN_FILEDATESI },
|
||||
{ NWATALK_ADEID_AFPFILEI, NWATALK_ADEDOFF_AFPFILEI, NWATALK_ADEDLEN_AFPFILEI },
|
||||
{ NWATALK_ADEID_PRIVDEV, NWATALK_ADEDOFF_PRIVDEV, NWATALK_ADEDLEN_PRIVDEV },
|
||||
{ NWATALK_ADEID_PRIVINO, NWATALK_ADEDOFF_PRIVINO, NWATALK_ADEDLEN_PRIVINO },
|
||||
{ NWATALK_ADEID_PRIVSYN, NWATALK_ADEDOFF_PRIVSYN, NWATALK_ADEDLEN_PRIVSYN },
|
||||
{ NWATALK_ADEID_PRIVID, NWATALK_ADEDOFF_PRIVID, NWATALK_ADEDLEN_PRIVID }
|
||||
};
|
||||
|
||||
static void nwatalk_put_be16(uint8 *p, uint16 value)
|
||||
{
|
||||
p[0] = (uint8)((value >> 8) & 0xff);
|
||||
p[1] = (uint8)(value & 0xff);
|
||||
}
|
||||
|
||||
static void nwatalk_put_be32(uint8 *p, uint32 value)
|
||||
{
|
||||
p[0] = (uint8)((value >> 24) & 0xff);
|
||||
p[1] = (uint8)((value >> 16) & 0xff);
|
||||
p[2] = (uint8)((value >> 8) & 0xff);
|
||||
p[3] = (uint8)(value & 0xff);
|
||||
}
|
||||
|
||||
static uint16 nwatalk_get_be16(const uint8 *p)
|
||||
{
|
||||
return((uint16)(((uint16)p[0] << 8) | p[1]));
|
||||
}
|
||||
|
||||
static uint32 nwatalk_get_be32(const uint8 *p)
|
||||
{
|
||||
return(((uint32)p[0] << 24) | ((uint32)p[1] << 16) |
|
||||
((uint32)p[2] << 8) | (uint32)p[3]);
|
||||
}
|
||||
|
||||
static void nwatalk_init_ad_metadata(uint8 data[NWATALK_AD_DATASZ_EA])
|
||||
{
|
||||
size_t i;
|
||||
uint8 *p;
|
||||
|
||||
memset(data, 0, NWATALK_AD_DATASZ_EA);
|
||||
nwatalk_put_be32(data, NWATALK_AD_MAGIC);
|
||||
nwatalk_put_be32(data + 4, NWATALK_AD_VERSION_EA);
|
||||
nwatalk_put_be16(data + 24, NWATALK_AD_ENTRY_COUNT);
|
||||
|
||||
p = data + NWATALK_AD_HEADER_LEN;
|
||||
for (i = 0; i < NWATALK_AD_ENTRY_COUNT; i++) {
|
||||
nwatalk_put_be32(p, nwatalk_ad_entries[i].id);
|
||||
nwatalk_put_be32(p + 4, nwatalk_ad_entries[i].off);
|
||||
nwatalk_put_be32(p + 8, nwatalk_ad_entries[i].len);
|
||||
p += NWATALK_AD_ENTRY_LEN;
|
||||
}
|
||||
}
|
||||
|
||||
static int nwatalk_valid_ad_metadata(const uint8 data[NWATALK_AD_DATASZ_EA])
|
||||
{
|
||||
uint16 nentries;
|
||||
uint16 i;
|
||||
|
||||
if (nwatalk_get_be32(data) != NWATALK_AD_MAGIC ||
|
||||
nwatalk_get_be32(data + 4) != NWATALK_AD_VERSION_EA)
|
||||
return(0);
|
||||
|
||||
nentries = nwatalk_get_be16(data + 24);
|
||||
if (nentries > NWATALK_AD_ENTRY_COUNT)
|
||||
return(0);
|
||||
|
||||
for (i = 0; i < nentries; i++) {
|
||||
const uint8 *p = data + NWATALK_AD_HEADER_LEN + i * NWATALK_AD_ENTRY_LEN;
|
||||
uint32 off = nwatalk_get_be32(p + 4);
|
||||
uint32 len = nwatalk_get_be32(p + 8);
|
||||
if (off > NWATALK_AD_DATASZ_EA || len > NWATALK_AD_DATASZ_EA ||
|
||||
off + len > NWATALK_AD_DATASZ_EA)
|
||||
return(0);
|
||||
}
|
||||
|
||||
return(1);
|
||||
}
|
||||
|
||||
static int nwatalk_read_ad_metadata(const char *path,
|
||||
uint8 data[NWATALK_AD_DATASZ_EA],
|
||||
int create_if_missing)
|
||||
{
|
||||
MARS_NWE_AFP_ENTRY_ID_XATTR_DATA d;
|
||||
ssize_t len;
|
||||
|
||||
if (!path || !*path) return(-0x9c);
|
||||
|
||||
memset(data, 0, NWATALK_AD_DATASZ_EA);
|
||||
len = mars_nwe_getxattr(path, NWATALK_AD_EA_META_XATTR,
|
||||
data, NWATALK_AD_DATASZ_EA);
|
||||
if (len == NWATALK_AD_DATASZ_EA && nwatalk_valid_ad_metadata(data))
|
||||
return(0);
|
||||
|
||||
if (create_if_missing) {
|
||||
nwatalk_init_ad_metadata(data);
|
||||
return(0);
|
||||
}
|
||||
|
||||
return(-0x9c);
|
||||
}
|
||||
|
||||
static int nwatalk_write_ad_metadata(const char *path,
|
||||
const uint8 data[NWATALK_AD_DATASZ_EA])
|
||||
{
|
||||
if (mars_nwe_setxattr(path, NWATALK_AD_EA_META_XATTR,
|
||||
data, NWATALK_AD_DATASZ_EA, 0))
|
||||
return(-1);
|
||||
return(0);
|
||||
}
|
||||
|
||||
static void nwatalk_store_host_value(uint8 *dst, size_t dst_len,
|
||||
const void *src, size_t src_len)
|
||||
{
|
||||
memset(dst, 0, dst_len);
|
||||
if (src_len > dst_len) src_len = dst_len;
|
||||
memcpy(dst, src, src_len);
|
||||
}
|
||||
|
||||
static void nwatalk_set_file_identity(const char *path,
|
||||
uint8 data[NWATALK_AD_DATASZ_EA],
|
||||
uint32 entry_id)
|
||||
{
|
||||
struct stat st;
|
||||
|
||||
if (stat(path, &st) == 0) {
|
||||
nwatalk_store_host_value(data + NWATALK_ADEDOFF_PRIVDEV,
|
||||
NWATALK_ADEDLEN_PRIVDEV,
|
||||
&st.st_dev, sizeof(st.st_dev));
|
||||
nwatalk_store_host_value(data + NWATALK_ADEDOFF_PRIVINO,
|
||||
NWATALK_ADEDLEN_PRIVINO,
|
||||
&st.st_ino, sizeof(st.st_ino));
|
||||
}
|
||||
memset(data + NWATALK_ADEDOFF_PRIVSYN, 0, NWATALK_ADEDLEN_PRIVSYN);
|
||||
nwatalk_put_be32(data + NWATALK_ADEDOFF_PRIVID, entry_id);
|
||||
}
|
||||
|
||||
static int nwatalk_get_netatalk_entry_id_xattr(const char *path, uint32 *entry_id)
|
||||
{
|
||||
uint8 data[NWATALK_AD_DATASZ_EA];
|
||||
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)
|
||||
if (nwatalk_read_ad_metadata(path, data, 0) < 0)
|
||||
return(-0x9c);
|
||||
|
||||
id = GET_BE32(d.entry_id);
|
||||
id = nwatalk_get_be32(data + NWATALK_ADEDOFF_PRIVID);
|
||||
id &= 0x7fffffffU;
|
||||
if (!id) return(-0x9c);
|
||||
|
||||
@@ -85,7 +252,7 @@ static int nwatalk_get_mars_entry_id_xattr(const char *path, uint32 *entry_id)
|
||||
return(0);
|
||||
}
|
||||
#else
|
||||
static int nwatalk_get_mars_entry_id_xattr(const char *path, uint32 *entry_id)
|
||||
static int nwatalk_get_netatalk_entry_id_xattr(const char *path, uint32 *entry_id)
|
||||
{
|
||||
(void)path;
|
||||
if (entry_id) *entry_id = 0;
|
||||
@@ -97,7 +264,7 @@ int nwatalk_get_finder_info(const char *path, uint8 *finder_info,
|
||||
int finder_info_len)
|
||||
{
|
||||
#if XATTR_SUPPORT
|
||||
ssize_t len;
|
||||
uint8 data[NWATALK_AD_DATASZ_EA];
|
||||
#endif
|
||||
|
||||
if (!finder_info || finder_info_len < NWATALK_FINDER_INFO_LEN) {
|
||||
@@ -107,13 +274,10 @@ int nwatalk_get_finder_info(const char *path, uint8 *finder_info,
|
||||
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);
|
||||
}
|
||||
if (path && *path &&
|
||||
nwatalk_read_ad_metadata(path, data, 0) == 0)
|
||||
memcpy(finder_info, data + NWATALK_ADEDOFF_FINDERI,
|
||||
NWATALK_FINDER_INFO_LEN);
|
||||
#else
|
||||
(void)path;
|
||||
#endif
|
||||
@@ -126,11 +290,18 @@ int nwatalk_set_finder_info(const char *path, const uint8 *finder_info,
|
||||
int finder_info_len)
|
||||
{
|
||||
#if XATTR_SUPPORT
|
||||
uint8 data[NWATALK_AD_DATASZ_EA];
|
||||
|
||||
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)) {
|
||||
if (nwatalk_read_ad_metadata(path, data, 1) < 0)
|
||||
return(-0x9c);
|
||||
|
||||
memcpy(data + NWATALK_ADEDOFF_FINDERI, finder_info,
|
||||
NWATALK_FINDER_INFO_LEN);
|
||||
|
||||
if (nwatalk_write_ad_metadata(path, data)) {
|
||||
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 */
|
||||
@@ -161,7 +332,7 @@ int nwatalk_get_prodos_info(const char *path, uint8 *prodos_info,
|
||||
|
||||
#if XATTR_SUPPORT
|
||||
if (path && *path) {
|
||||
len = mars_nwe_getxattr(path, MARS_NWE_AFP_PRODOS_INFO_XATTR,
|
||||
len = mars_nwe_getxattr(path, NWATALK_AD_EA_PRODOS_XATTR,
|
||||
prodos_info, NWATALK_PRODOS_INFO_LEN);
|
||||
if (len == NWATALK_PRODOS_INFO_LEN)
|
||||
return(0);
|
||||
@@ -182,7 +353,7 @@ int nwatalk_set_prodos_info(const char *path, const uint8 *prodos_info,
|
||||
if (!path || !*path || !prodos_info || prodos_info_len < NWATALK_PRODOS_INFO_LEN)
|
||||
return(-0x9c);
|
||||
|
||||
if (mars_nwe_setxattr(path, MARS_NWE_AFP_PRODOS_INFO_XATTR,
|
||||
if (mars_nwe_setxattr(path, NWATALK_AD_EA_PRODOS_XATTR,
|
||||
prodos_info, NWATALK_PRODOS_INFO_LEN, 0)) {
|
||||
int err = errno;
|
||||
XDPRINTF((3,0,"AFP ProDOSInfo xattr write failed for %s errno=%d", path, err));
|
||||
@@ -200,37 +371,16 @@ int nwatalk_set_prodos_info(const char *path, const uint8 *prodos_info,
|
||||
|
||||
int nwatalk_get_afp_attributes(const char *path, uint16 *attributes)
|
||||
{
|
||||
#if XATTR_SUPPORT
|
||||
MARS_NWE_AFP_ATTRIBUTES_XATTR_DATA d;
|
||||
ssize_t len;
|
||||
#endif
|
||||
(void)path;
|
||||
|
||||
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);
|
||||
return(0);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
@@ -239,46 +389,24 @@ int nwatalk_set_afp_attributes(const char *path, uint16 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;
|
||||
uint8 data[NWATALK_AD_DATASZ_EA];
|
||||
|
||||
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 (nwatalk_read_ad_metadata(path, data, 1) < 0)
|
||||
return(-0x9c);
|
||||
|
||||
if (mars_nwe_setxattr(path, MARS_NWE_AFP_ENTRY_ID_XATTR,
|
||||
&d, sizeof(d), 0)) {
|
||||
nwatalk_set_file_identity(path, data, entry_id);
|
||||
|
||||
if (nwatalk_write_ad_metadata(path, data)) {
|
||||
int err = errno;
|
||||
XDPRINTF((5,0,"AFP entry-id xattr write ignored for %s entry=0x%08x errno=%d",
|
||||
path, entry_id, err));
|
||||
@@ -295,9 +423,24 @@ int nwatalk_set_entry_id(const char *path, uint32 entry_id)
|
||||
|
||||
int nwatalk_get_resource_fork_size(const char *path, uint32 *resource_size)
|
||||
{
|
||||
(void)path;
|
||||
#if XATTR_SUPPORT
|
||||
ssize_t len;
|
||||
#endif
|
||||
|
||||
if (!resource_size) return(-0x9c);
|
||||
*resource_size = 0;
|
||||
|
||||
#if XATTR_SUPPORT
|
||||
if (!path || !*path) return(-0x9c);
|
||||
len = mars_nwe_getxattr(path, NWATALK_AD_EA_RESO_XATTR, NULL, 0);
|
||||
if (len > 0) {
|
||||
if (len > 0xffffffffL) len = 0xffffffffL;
|
||||
*resource_size = (uint32)len;
|
||||
}
|
||||
#else
|
||||
(void)path;
|
||||
#endif
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
@@ -307,5 +450,5 @@ int nwatalk_get_entry_id(const char *path, uint32 *entry_id)
|
||||
*entry_id = 0;
|
||||
if (!path || !*path) return(-0x9c);
|
||||
|
||||
return(nwatalk_get_mars_entry_id_xattr(path, entry_id));
|
||||
return(nwatalk_get_netatalk_entry_id_xattr(path, entry_id));
|
||||
}
|
||||
|
||||
+7
-7
@@ -940,8 +940,8 @@ static uint32 afp_namespace_entry_id(int volume, const struct stat *stb)
|
||||
static uint32 afp_fallback_entry_id(int volume, const struct stat *stb)
|
||||
/*
|
||||
* Build a stable local AFP entry id from Unix identity data when the NetWare
|
||||
* namespace handle cannot represent the object and mars_nwe AFP xattr has no stored
|
||||
* CNID/AppleDouble id yet. This is only a legacy compatibility fallback.
|
||||
* namespace handle cannot represent the object and Netatalk metadata has no
|
||||
* stored CNID/AppleDouble id yet. This is only a legacy compatibility fallback.
|
||||
*/
|
||||
{
|
||||
uint32 hash = 2166136261U;
|
||||
@@ -971,8 +971,8 @@ static uint32 afp_get_or_create_entry_id(const char *unixname, int volume,
|
||||
int *fallback_out)
|
||||
/*
|
||||
* Return the mars_nwe namespace basehandle as AFP entry id whenever it can be
|
||||
* represented. mars_nwe AFP xattr metadata remains a cache/legacy fallback for
|
||||
* entries that cannot be mapped by the NetWare namespace table.
|
||||
* represented. Netatalk metadata remains a cache/legacy fallback for entries
|
||||
* that cannot be mapped by the NetWare namespace table.
|
||||
*/
|
||||
{
|
||||
uint32 entry_id = 0;
|
||||
@@ -1893,7 +1893,7 @@ static int afp_dos_path_join(int volume, char *dst, int dst_len,
|
||||
*
|
||||
* AFP 0x12 returns a DOSPathString, not the real Unix directory entry name.
|
||||
* The reverse lookup still walks the Unix volume tree because current AFP entry
|
||||
* IDs are mars_nwe AFP xattr metadata IDs, but the path returned to the client
|
||||
* IDs are nwatalk metadata IDs, but the path returned to the client
|
||||
* must be the DOS namespace alias that mars_nwe already uses elsewhere.
|
||||
*/
|
||||
{
|
||||
@@ -1915,11 +1915,11 @@ static int afp_find_dos_name_from_entry_id_rec(int volume,
|
||||
const char *rel_dir,
|
||||
AFP_DOS_NAME_SEARCH *search)
|
||||
/*
|
||||
* Reverse-map the mars_nwe AFP entry-id xattr cache back to a DOS/NetWare path.
|
||||
* Reverse-map the nwatalk entry-id metadata back to a DOS/NetWare path.
|
||||
*
|
||||
* NetWare's documented AFP 0x12 call is an entry-id-only lookup. mars_nwe's
|
||||
* current AFP ids are not the namespace base handles used by namspace.c; they
|
||||
* are mars_nwe AFP xattr metadata ids. Reuse the existing volume table for
|
||||
* are nwatalk metadata ids. Reuse the existing volume table for
|
||||
* the search root and the nwatalk entry-id helper for the per-entry identity,
|
||||
* but do not create fallback ids while scanning. The first conservative smoke
|
||||
* target is therefore an entry that was already cached by Get Entry ID/Get File
|
||||
|
||||
+7
-7
@@ -18,9 +18,10 @@ AFP handlers must keep NetWare semantics on mars_nwe core paths:
|
||||
- rights checks use mars_nwe trustee/effective-rights logic;
|
||||
- Hidden, System, Archive, timestamps, creator/modifier, backup/archive, and
|
||||
related metadata use mars_nwe attribute/archive/fileinfo paths;
|
||||
- AFP-only xattrs are limited to `user.org.mars-nwe.afp.entry-id`,
|
||||
`user.org.mars-nwe.afp.finder-info`, `user.org.mars-nwe.afp.prodos-info`, and
|
||||
future AFP-only bits in `user.org.mars-nwe.afp.attributes`.
|
||||
- AFP metadata uses Netatalk-family xattrs: `user.org.netatalk.Metadata`
|
||||
for AppleDouble `adouble:ea` FinderInfo and CNID/entry-id metadata, plus
|
||||
`user.org.netatalk.ProDOS` for the AFP 2.0 ProDOSInfo bytes that Netatalk's
|
||||
402-byte EA header does not carry.
|
||||
|
||||
Resource forks remain unsupported. AFP resource-fork requests should return
|
||||
the documented completion code instead of inventing a parallel storage backend.
|
||||
@@ -38,6 +39,7 @@ NSS_VOLUME
|
||||
|
||||
OTHERFS_XATTR
|
||||
Finder/Mac metadata: Netatalk adouble:ea xattr org.netatalk.Metadata
|
||||
AFP 2.0 ProDOSInfo: Netatalk-family xattr org.netatalk.ProDOS
|
||||
resource fork: Netatalk adouble:ea xattr org.netatalk.ResourceFork
|
||||
```
|
||||
|
||||
@@ -168,10 +170,8 @@ DOS name lookup, and AFP `0x13` deleted-file metadata. It also checks the AFP
|
||||
xattrs on the tested Unix file:
|
||||
|
||||
```text
|
||||
user.org.mars-nwe.afp.finder-info
|
||||
user.org.mars-nwe.afp.prodos-info
|
||||
user.org.mars-nwe.afp.attributes
|
||||
user.org.mars-nwe.afp.entry-id
|
||||
user.org.netatalk.Metadata
|
||||
user.org.netatalk.ProDOS
|
||||
```
|
||||
|
||||
Use `--no-log` when the server log is unavailable or collected separately. Use
|
||||
|
||||
@@ -61,15 +61,15 @@ HANDLER_CANDIDATES_BY_CALL: Dict[int, Tuple[str, ...]] = {
|
||||
# implementation shape and backend families, not final compatibility status.
|
||||
INLINE_ENDPOINTS: Dict[int, Tuple[str, str, Tuple[str, ...]]] = {
|
||||
0x01: ("inline AFP create directory case", "implemented", ("mars_nwe path/namespace", "mars_nwe object lifecycle")),
|
||||
0x02: ("inline AFP create file case", "implemented", ("mars_nwe path/namespace", "mars_nwe object lifecycle", "AFP-only xattrs via nwatalk")),
|
||||
0x02: ("inline AFP create file case", "implemented", ("mars_nwe path/namespace", "mars_nwe object lifecycle", "Netatalk-family xattrs via nwatalk")),
|
||||
0x03: ("inline AFP delete case", "implemented", ("mars_nwe path/namespace", "mars_nwe object lifecycle")),
|
||||
0x07: ("inline AFP rename case", "implemented", ("mars_nwe path/namespace", "mars_nwe object lifecycle", "AFP-only xattrs via nwatalk")),
|
||||
0x07: ("inline AFP rename case", "implemented", ("mars_nwe path/namespace", "mars_nwe object lifecycle", "Netatalk-family xattrs via nwatalk")),
|
||||
0x08: ("inline AFP open file fork case", "implemented", ("mars_nwe path/namespace", "mars_nwe file handles/I/O")),
|
||||
0x09: ("inline AFP set file information case", "implemented", ("mars_nwe path/namespace", "mars_nwe attributes/archive/fileinfo", "mars_nwe trustee/rights", "AFP-only xattrs via nwatalk")),
|
||||
0x09: ("inline AFP set file information case", "implemented", ("mars_nwe path/namespace", "mars_nwe attributes/archive/fileinfo", "mars_nwe trustee/rights", "Netatalk-family xattrs via nwatalk")),
|
||||
0x0B: ("inline AFP alloc temporary dir handle case", "implemented", ("mars_nwe path/namespace", "mars_nwe directory handles")),
|
||||
0x0D: ("inline AFP 2.0 create directory case", "implemented", ("mars_nwe path/namespace", "mars_nwe object lifecycle")),
|
||||
0x0E: ("inline AFP 2.0 create file case", "implemented", ("mars_nwe path/namespace", "mars_nwe object lifecycle", "AFP-only xattrs via nwatalk")),
|
||||
0x10: ("inline AFP 2.0 set file information case", "implemented", ("mars_nwe path/namespace", "mars_nwe attributes/archive/fileinfo", "mars_nwe trustee/rights", "AFP-only xattrs via nwatalk")),
|
||||
0x0E: ("inline AFP 2.0 create file case", "implemented", ("mars_nwe path/namespace", "mars_nwe object lifecycle", "Netatalk-family xattrs via nwatalk")),
|
||||
0x10: ("inline AFP 2.0 set file information case", "implemented", ("mars_nwe path/namespace", "mars_nwe attributes/archive/fileinfo", "mars_nwe trustee/rights", "Netatalk-family xattrs via nwatalk")),
|
||||
0x13: ("inline AFP deleted-info case", "implemented", ("mars_nwe salvage/deleted-entry backend", "AFP FinderInfo snapshot")),
|
||||
}
|
||||
|
||||
@@ -130,7 +130,7 @@ BACKEND_RULES: Tuple[Tuple[str, Tuple[str, ...]], ...] = (
|
||||
"unlink",
|
||||
"rmdir",
|
||||
)),
|
||||
("AFP-only xattrs via nwatalk", (
|
||||
("Netatalk-family xattrs via nwatalk", (
|
||||
"nwatalk_get_entry_id",
|
||||
"nwatalk_set_entry_id",
|
||||
"nwatalk_get_finder_info",
|
||||
|
||||
@@ -61,7 +61,7 @@ Options:
|
||||
|
||||
The script expects the compiled smoke helpers in the same directory as this
|
||||
script. It prints commands with the password masked, writes an AFP-only log
|
||||
snippet, and runs getfattr checks for mars_nwe AFP xattrs.
|
||||
snippet, and runs getfattr checks for Netatalk-family AFP xattrs.
|
||||
USAGE
|
||||
}
|
||||
|
||||
@@ -885,20 +885,14 @@ fi
|
||||
|
||||
if command -v getfattr >/dev/null 2>&1; then
|
||||
run_cmd \
|
||||
"Linux xattr: AFP FinderInfo" \
|
||||
"getfattr -n user.org.mars-nwe.afp.finder-info -e hex '$UNIX_PATH'" \
|
||||
getfattr -n user.org.mars-nwe.afp.finder-info -e hex "$UNIX_PATH"
|
||||
"Linux xattr: Netatalk AFP metadata" \
|
||||
"getfattr -n user.org.netatalk.Metadata -e hex '$UNIX_PATH'" \
|
||||
getfattr -n user.org.netatalk.Metadata -e hex "$UNIX_PATH"
|
||||
|
||||
run_cmd \
|
||||
"Linux xattr: AFP ProDOSInfo" \
|
||||
"getfattr -n user.org.mars-nwe.afp.prodos-info -e hex '$UNIX_PATH'" \
|
||||
getfattr -n user.org.mars-nwe.afp.prodos-info -e hex "$UNIX_PATH"
|
||||
|
||||
run_optional_cmd \
|
||||
"Linux xattr: AFP Attributes (optional AFP-only bits)" \
|
||||
"getfattr -n user.org.mars-nwe.afp.attributes -e hex '$UNIX_PATH'" \
|
||||
getfattr -n user.org.mars-nwe.afp.attributes -e hex "$UNIX_PATH" || \
|
||||
emit "AFP-only attributes xattr is absent; this is expected when the tested Hidden/System/Archive bits are stored through the NetWare attribute path."
|
||||
"getfattr -n user.org.netatalk.ProDOS -e hex '$UNIX_PATH'" \
|
||||
getfattr -n user.org.netatalk.ProDOS -e hex "$UNIX_PATH"
|
||||
|
||||
run_cmd \
|
||||
"Linux xattr: NetWare FileInfo metadata" \
|
||||
@@ -912,8 +906,8 @@ if command -v getfattr >/dev/null 2>&1; then
|
||||
|
||||
run_cmd \
|
||||
"Linux xattr: AFP Entry ID" \
|
||||
"getfattr -n user.org.mars-nwe.afp.entry-id -e hex '$UNIX_PATH'" \
|
||||
getfattr -n user.org.mars-nwe.afp.entry-id -e hex "$UNIX_PATH"
|
||||
"getfattr -n user.org.netatalk.Metadata -e hex '$UNIX_PATH'" \
|
||||
getfattr -n user.org.netatalk.Metadata -e hex "$UNIX_PATH"
|
||||
else
|
||||
section "Linux xattr checks"
|
||||
emit "getfattr not found; install the attr package to collect xattr output."
|
||||
|
||||
Reference in New Issue
Block a user