diff --git a/src/lowntfs-3g.c b/src/lowntfs-3g.c index 1e7098ef..f78cb9c8 100644 --- a/src/lowntfs-3g.c +++ b/src/lowntfs-3g.c @@ -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)); diff --git a/src/ntfs-3g.c b/src/ntfs-3g.c index d3537660..2eb197a8 100644 --- a/src/ntfs-3g.c +++ b/src/ntfs-3g.c @@ -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));