Add support for 'position' argument in macOS xattr functions.

The 'position' argument is only used for the legacy resource fork and is
disallowed for other extended attributes. The name check is placed first
in the functions as this is how macOS behaves (EINVAL is returned if the
attribute is not the resource fork attribute and the position is non-0
even when the attribute does not exist).
This commit is contained in:
Erik Larsson 2020-08-25 11:26:29 +03:00
parent 4ecc13c0ac
commit 1511a5ca51
2 changed files with 101 additions and 6 deletions

View File

@ -3373,9 +3373,18 @@ out :
free(list);
}
#if defined(__APPLE__) || defined(__DARWIN__)
static void ntfs_fuse_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
size_t size, uint32_t position)
#else
static void ntfs_fuse_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
size_t size)
#endif
{
#if !(defined(__APPLE__) || defined(__DARWIN__))
static const unsigned int position = 0U;
#endif
ntfs_inode *ni;
ntfs_inode *dir_ni;
ntfs_attr *na = NULL;
@ -3388,6 +3397,16 @@ static void ntfs_fuse_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
int namespace;
struct SECURITY_CONTEXT security;
#if defined(__APPLE__) || defined(__DARWIN__)
/* If the attribute is not a resource fork attribute and the position
* parameter is non-zero, we return with EINVAL as requesting position
* is not permitted for non-resource fork attributes. */
if (position && strcmp(name, XATTR_RESOURCEFORK_NAME)) {
fuse_reply_err(req, EINVAL);
return;
}
#endif
attr = ntfs_xattr_system_type(name,ctx->vol);
if (attr != XATTR_UNMAPPED) {
/*
@ -3502,11 +3521,13 @@ static void ntfs_fuse_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
&& (na->data_flags & ATTR_IS_ENCRYPTED)
&& NAttrNonResident(na))
rsize = ((na->data_size + 511) & ~511) + 2;
rsize -= position;
if (size) {
if (size >= (size_t)rsize) {
value = (char*)ntfs_malloc(rsize);
if (value)
res = ntfs_attr_pread(na, 0, rsize, value);
res = ntfs_attr_pread(na, position, rsize,
value);
if (!value || (res != rsize))
res = -errno;
} else
@ -3531,9 +3552,21 @@ out :
free(value);
}
#if defined(__APPLE__) || defined(__DARWIN__)
static void ntfs_fuse_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
const char *value, size_t size, int flags,
uint32_t position)
#else
static void ntfs_fuse_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
const char *value, size_t size, int flags)
#endif
{
#if !(defined(__APPLE__) || defined(__DARWIN__))
static const unsigned int position = 0U;
#else
BOOL is_resource_fork;
#endif
ntfs_inode *ni;
ntfs_inode *dir_ni;
ntfs_attr *na = NULL;
@ -3545,6 +3578,17 @@ static void ntfs_fuse_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
int namespace;
struct SECURITY_CONTEXT security;
#if defined(__APPLE__) || defined(__DARWIN__)
/* If the attribute is not a resource fork attribute and the position
* parameter is non-zero, we return with EINVAL as requesting position
* is not permitted for non-resource fork attributes. */
is_resource_fork = strcmp(name, XATTR_RESOURCEFORK_NAME) ? FALSE : TRUE;
if (position && !is_resource_fork) {
fuse_reply_err(req, EINVAL);
return;
}
#endif
attr = ntfs_xattr_system_type(name,ctx->vol);
if (attr != XATTR_UNMAPPED) {
/*
@ -3720,6 +3764,11 @@ static void ntfs_fuse_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
res = -errno;
goto exit;
}
#if defined(__APPLE__) || defined(__DARWIN__)
} else if (is_resource_fork) {
/* In macOS, the resource fork is a special case. It doesn't
* ever shrink (it would have to be removed and re-added). */
#endif
} else {
/* currently compressed streams can only be wiped out */
if (ntfs_attr_truncate(na, (s64)0 /* size */)) {
@ -3731,8 +3780,8 @@ static void ntfs_fuse_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
res = 0;
if (size) {
do {
part = ntfs_attr_pwrite(na, total, size - total,
&value[total]);
part = ntfs_attr_pwrite(na, position + total,
size - total, &value[total]);
if (part > 0)
total += part;
} while ((part > 0) && (total < size));

View File

@ -3151,9 +3151,18 @@ exit:
return ret;
}
#if defined(__APPLE__) || defined(__DARWIN__)
static int ntfs_fuse_getxattr(const char *path, const char *name,
char *value, size_t size, uint32_t position)
#else
static int ntfs_fuse_getxattr(const char *path, const char *name,
char *value, size_t size)
#endif
{
#if !(defined(__APPLE__) || defined(__DARWIN__))
static const unsigned int position = 0U;
#endif
ntfs_inode *ni;
ntfs_inode *dir_ni;
ntfs_attr *na = NULL;
@ -3164,6 +3173,15 @@ static int ntfs_fuse_getxattr(const char *path, const char *name,
int namespace;
struct SECURITY_CONTEXT security;
#if defined(__APPLE__) || defined(__DARWIN__)
/* If the attribute is not a resource fork attribute and the position
* parameter is non-zero, we return with EINVAL as requesting position
* is not permitted for non-resource fork attributes. */
if (position && strcmp(name, XATTR_RESOURCEFORK_NAME)) {
return -EINVAL;
}
#endif
attr = ntfs_xattr_system_type(name,ctx->vol);
if (attr != XATTR_UNMAPPED) {
#if !KERNELPERMS | (POSIXACLS & !KERNELACLS)
@ -3269,9 +3287,10 @@ static int ntfs_fuse_getxattr(const char *path, const char *name,
&& (na->data_flags & ATTR_IS_ENCRYPTED)
&& NAttrNonResident(na))
rsize = ((na->data_size + 511) & ~511) + 2;
rsize -= position;
if (size) {
if (size >= (size_t)rsize) {
res = ntfs_attr_pread(na, 0, rsize, value);
res = ntfs_attr_pread(na, position, rsize, value);
if (res != rsize)
res = -errno;
} else
@ -3287,9 +3306,21 @@ exit:
return res;
}
#if defined(__APPLE__) || defined(__DARWIN__)
static int ntfs_fuse_setxattr(const char *path, const char *name,
const char *value, size_t size, int flags,
uint32_t position)
#else
static int ntfs_fuse_setxattr(const char *path, const char *name,
const char *value, size_t size, int flags)
#endif
{
#if !(defined(__APPLE__) || defined(__DARWIN__))
static const unsigned int position = 0U;
#else
BOOL is_resource_fork;
#endif
ntfs_inode *ni;
ntfs_inode *dir_ni;
ntfs_attr *na = NULL;
@ -3301,6 +3332,16 @@ static int ntfs_fuse_setxattr(const char *path, const char *name,
int namespace;
struct SECURITY_CONTEXT security;
#if defined(__APPLE__) || defined(__DARWIN__)
/* If the attribute is not a resource fork attribute and the position
* parameter is non-zero, we return with EINVAL as requesting position
* is not permitted for non-resource fork attributes. */
is_resource_fork = strcmp(name, XATTR_RESOURCEFORK_NAME) ? FALSE : TRUE;
if (position && !is_resource_fork) {
return -EINVAL;
}
#endif
attr = ntfs_xattr_system_type(name,ctx->vol);
if (attr != XATTR_UNMAPPED) {
#if !KERNELPERMS | (POSIXACLS & !KERNELACLS)
@ -3466,6 +3507,11 @@ static int ntfs_fuse_setxattr(const char *path, const char *name,
res = -errno;
goto exit;
}
#if defined(__APPLE__) || defined(__DARWIN__)
} else if (is_resource_fork) {
/* In macOS, the resource fork is a special case. It doesn't
* ever shrink (it would have to be removed and re-added). */
#endif
} else {
/* currently compressed streams can only be wiped out */
if (ntfs_attr_truncate(na, (s64)0 /* size */)) {
@ -3477,8 +3523,8 @@ static int ntfs_fuse_setxattr(const char *path, const char *name,
res = 0;
if (size) {
do {
part = ntfs_attr_pwrite(na, total, size - total,
&value[total]);
part = ntfs_attr_pwrite(na, position + total,
size - total, &value[total]);
if (part > 0)
total += part;
} while ((part > 0) && (total < size));