diff --git a/include/ntfs-3g/Makefile.am b/include/ntfs-3g/Makefile.am index f4f72d69..6067346e 100644 --- a/include/ntfs-3g/Makefile.am +++ b/include/ntfs-3g/Makefile.am @@ -35,7 +35,8 @@ headers = \ support.h \ types.h \ unistr.h \ - volume.h + volume.h \ + xattrs.h if INSTALL_LIBRARY ntfs3ginclude_HEADERS = $(headers) diff --git a/include/ntfs-3g/xattrs.h b/include/ntfs-3g/xattrs.h new file mode 100644 index 00000000..f94b33b5 --- /dev/null +++ b/include/ntfs-3g/xattrs.h @@ -0,0 +1,58 @@ +/* + * xattrs.h : definitions related to system extended attributes + * + * Copyright (c) 2010 Jean-Pierre Andre + * + * This program/include file is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program/include file is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (in the main directory of the NTFS-3G + * distribution in the file COPYING); if not, write to the Free Software + * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _NTFS_XATTR_H_ +#define _NTFS_XATTR_H_ + +/* + * Identification of data mapped to the system name space + */ + +enum SYSTEMXATTRS { + XATTR_UNMAPPED, + XATTR_NTFS_ACL, + XATTR_NTFS_ATTRIB, + XATTR_NTFS_EFSINFO, + XATTR_NTFS_REPARSE_DATA, + XATTR_NTFS_OBJECT_ID, + XATTR_NTFS_DOS_NAME, + XATTR_NTFS_TIMES, + XATTR_POSIX_ACC, + XATTR_POSIX_DEF +} ; + +enum SYSTEMXATTRS ntfs_xattr_system_type(const char *name); + +int ntfs_xattr_listxattr(ntfs_inode *ni, ntfs_attr_search_ctx *actx, + char *list, size_t size, BOOL prefixing); +int ntfs_xattr_system_getxattr(struct SECURITY_CONTEXT *scx, + enum SYSTEMXATTRS attr, + ntfs_inode *ni, ntfs_inode *dir_ni, + char *value, size_t size); +int ntfs_xattr_system_setxattr(struct SECURITY_CONTEXT *scx, + enum SYSTEMXATTRS attr, + ntfs_inode *ni, ntfs_inode *dir_ni, + const char *value, size_t size, int flags); +int ntfs_xattr_system_removexattr(struct SECURITY_CONTEXT *scx, + enum SYSTEMXATTRS attr, + ntfs_inode *ni, ntfs_inode *dir_ni); + +#endif /* _NTFS_XATTR_H_ */ diff --git a/libntfs-3g/Makefile.am b/libntfs-3g/Makefile.am index fe2fb9da..b74709ad 100644 --- a/libntfs-3g/Makefile.am +++ b/libntfs-3g/Makefile.am @@ -44,7 +44,8 @@ libntfs_3g_la_SOURCES = \ runlist.c \ security.c \ unistr.c \ - volume.c + volume.c \ + xattrs.c if NTFS_DEVICE_DEFAULT_IO_OPS if WINDOWS diff --git a/libntfs-3g/xattrs.c b/libntfs-3g/xattrs.c new file mode 100644 index 00000000..84d6c8e8 --- /dev/null +++ b/libntfs-3g/xattrs.c @@ -0,0 +1,359 @@ +/** + * xattrs.c : common functions to deal with system extended attributes + * + * Copyright (c) 2010 Jean-Pierre Andre + * + * This program/include file is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program/include file is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (in the main directory of the NTFS-3G + * distribution in the file COPYING); if not, write to the Free Software + * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_SETXATTR /* extended attributes support required */ + +#ifdef HAVE_STDIO_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_FCNTL_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef HAVE_ERRNO_H +#include +#endif + +#include "types.h" +#include "param.h" +#include "layout.h" +#include "attrib.h" +#include "index.h" +#include "dir.h" +#include "security.h" +#include "acls.h" +#include "efs.h" +#include "reparse.h" +#include "object_id.h" +#include "misc.h" +#include "logging.h" +#include "xattrs.h" + +static const char xattr_ntfs_3g[] = "ntfs-3g."; +static const char nf_ns_user_prefix[] = "user."; +static const int nf_ns_user_prefix_len = sizeof(nf_ns_user_prefix) - 1; + +static const char nf_ns_xattr_ntfs_acl[] = "system.ntfs_acl"; +static const char nf_ns_xattr_attrib[] = "system.ntfs_attrib"; +static const char nf_ns_xattr_efsinfo[] = "user.ntfs.efsinfo"; +static const char nf_ns_xattr_reparse[] = "system.ntfs_reparse_data"; +static const char nf_ns_xattr_object_id[] = "system.ntfs_object_id"; +static const char nf_ns_xattr_dos_name[] = "system.ntfs_dos_name"; +static const char nf_ns_xattr_times[] = "system.ntfs_times"; +static const char nf_ns_xattr_posix_access[] = "system.posix_acl_access"; +static const char nf_ns_xattr_posix_default[] = "system.posix_acl_default"; + +static const char nf_ns_alt_xattr_efsinfo[] = "user.ntfs.efsinfo"; + +struct XATTRNAME { + enum SYSTEMXATTRS xattr; + const char *name; +} ; + +static struct XATTRNAME nf_ns_xattr_names[] = { + { XATTR_NTFS_ACL, nf_ns_xattr_ntfs_acl }, + { XATTR_NTFS_ATTRIB, nf_ns_xattr_attrib }, + { XATTR_NTFS_EFSINFO, nf_ns_xattr_efsinfo }, + { XATTR_NTFS_REPARSE_DATA, nf_ns_xattr_reparse }, + { XATTR_NTFS_OBJECT_ID, nf_ns_xattr_object_id }, + { XATTR_NTFS_DOS_NAME, nf_ns_xattr_dos_name }, + { XATTR_NTFS_TIMES, nf_ns_xattr_times }, + { XATTR_POSIX_ACC, nf_ns_xattr_posix_access }, + { XATTR_POSIX_DEF, nf_ns_xattr_posix_default }, + { XATTR_UNMAPPED, (char*)NULL } /* terminator */ +}; + +/* + * Determine whether an extended attribute is mapped to + * internal data (original name in system namespace, or renamed) + */ + +enum SYSTEMXATTRS ntfs_xattr_system_type(const char *name) +{ + struct XATTRNAME *p; + + p = nf_ns_xattr_names; + while (p->name && strcmp(p->name,name)) + p++; + return (p->xattr); +} + +int ntfs_xattr_listxattr(ntfs_inode *ni, ntfs_attr_search_ctx *actx, + char *list, size_t size, BOOL prefixing) +{ + int ret = 0; + char *to = list; + + /* first list the regular user attributes (ADS) */ + while (!ntfs_attr_lookup(AT_DATA, NULL, 0, CASE_SENSITIVE, + 0, NULL, 0, actx)) { + char *tmp_name = NULL; + int tmp_name_len; + + if (!actx->attr->name_length) + continue; + tmp_name_len = ntfs_ucstombs( + (ntfschar *)((u8*)actx->attr + + le16_to_cpu(actx->attr->name_offset)), + actx->attr->name_length, &tmp_name, 0); + if (tmp_name_len < 0) { + ret = -errno; + goto exit; + } + /* + * When using name spaces, do not return + * security, trusted or system attributes + * (filtered elsewhere anyway) + * otherwise insert "user." prefix + */ + if (prefixing) { + if ((strlen(tmp_name) > sizeof(xattr_ntfs_3g)) + && !strncmp(tmp_name,xattr_ntfs_3g, + sizeof(xattr_ntfs_3g)-1)) + tmp_name_len = 0; + else + ret += tmp_name_len + + nf_ns_user_prefix_len + 1; + } else + ret += tmp_name_len + 1; + if (size && tmp_name_len) { + if ((size_t)ret <= size) { + if (prefixing) { + strcpy(to, nf_ns_user_prefix); + to += nf_ns_user_prefix_len; + } + strncpy(to, tmp_name, tmp_name_len); + to += tmp_name_len; + *to = 0; + to++; + } else { + free(tmp_name); + ret = -ERANGE; + goto exit; + } + } + free(tmp_name); + } + /* List efs info xattr for encrypted files */ + if (ni->vol->efs_raw && (ni->flags & FILE_ATTR_ENCRYPTED)) { + ret += sizeof(nf_ns_xattr_efsinfo); + if ((size_t)ret <= size) { + memcpy(to, nf_ns_xattr_efsinfo, + sizeof(nf_ns_xattr_efsinfo)); + to += sizeof(nf_ns_xattr_efsinfo); + } + } +exit : + return (ret); +} + + +int ntfs_xattr_system_getxattr(struct SECURITY_CONTEXT *scx, + enum SYSTEMXATTRS attr, + ntfs_inode *ni, ntfs_inode *dir_ni, + char *value, size_t size) +{ + int res; + + /* + * the returned value is the needed + * size. If it is too small, no copy + * is done, and the caller has to + * issue a new call with correct size. + */ + switch (attr) { + case XATTR_NTFS_ACL : + res = ntfs_get_ntfs_acl(scx, ni, value, size); + break; +#if POSIXACLS + case XATTR_POSIX_ACC : + res = ntfs_get_posix_acl(scx, ni, nf_ns_xattr_posix_access, + value, size); + break; + case XATTR_POSIX_DEF : + res = ntfs_get_posix_acl(scx, ni, nf_ns_xattr_posix_default, + value, size); + break; +#endif + case XATTR_NTFS_ATTRIB : + res = ntfs_get_ntfs_attrib(ni, value, size); + break; + case XATTR_NTFS_EFSINFO : + if (ni->vol->efs_raw) + res = ntfs_get_efs_info(ni, value, size); + else + res = -EPERM; + break; + case XATTR_NTFS_REPARSE_DATA : + res = ntfs_get_ntfs_reparse_data(ni, value, size); + break; + case XATTR_NTFS_OBJECT_ID : + res = ntfs_get_ntfs_object_id(ni, value, size); + break; + case XATTR_NTFS_DOS_NAME: + if (dir_ni) + res = ntfs_get_ntfs_dos_name(ni, dir_ni, value, size); + else + res = -errno; + break; + case XATTR_NTFS_TIMES: + res = ntfs_inode_get_times(ni, value, size); + break; + default : + errno = EOPNOTSUPP; + res = -errno; + break; + } + return (res); +} + +int ntfs_xattr_system_setxattr(struct SECURITY_CONTEXT *scx, + enum SYSTEMXATTRS attr, + ntfs_inode *ni, ntfs_inode *dir_ni, + const char *value, size_t size, int flags) +{ + int res; + + switch (attr) { + case XATTR_NTFS_ACL : + res = ntfs_set_ntfs_acl(scx, ni, value, size, flags); + break; +#if POSIXACLS + case XATTR_POSIX_ACC : + res = ntfs_set_posix_acl(scx ,ni , nf_ns_xattr_posix_access, + value, size, flags); + break; + case XATTR_POSIX_DEF : + res = ntfs_set_posix_acl(scx, ni, nf_ns_xattr_posix_default, + value, size, flags); + break; +#endif + case XATTR_NTFS_ATTRIB : + res = ntfs_set_ntfs_attrib(ni, value, size, flags); + break; + case XATTR_NTFS_EFSINFO : + if (ni->vol->efs_raw) + res = ntfs_set_efs_info(ni, value, size, flags); + else + res = -EPERM; + break; + case XATTR_NTFS_REPARSE_DATA : + res = ntfs_set_ntfs_reparse_data(ni, value, size, flags); + break; + case XATTR_NTFS_OBJECT_ID : + res = ntfs_set_ntfs_object_id(ni, value, size, flags); + break; + case XATTR_NTFS_DOS_NAME: + if (dir_ni) + /* warning : this closes both inodes */ + res = ntfs_set_ntfs_dos_name(ni, dir_ni, value, + size, flags); + else + res = -errno; + break; + case XATTR_NTFS_TIMES: + res = ntfs_inode_set_times(ni, value, size, flags); + break; + default : + errno = EOPNOTSUPP; + res = -errno; + break; + } + return (res); +} + +int ntfs_xattr_system_removexattr(struct SECURITY_CONTEXT *scx, + enum SYSTEMXATTRS attr, + ntfs_inode *ni, ntfs_inode *dir_ni) +{ + int res; + + res = 0; + switch (attr) { + /* + * Removal of NTFS ACL, ATTRIB, EFSINFO or TIMES + * is never allowed + */ + case XATTR_NTFS_ACL : + case XATTR_NTFS_ATTRIB : + case XATTR_NTFS_EFSINFO : + case XATTR_NTFS_TIMES : + res = -EPERM; + break; +#if POSIXACLS + case XATTR_POSIX_ACC : + case XATTR_POSIX_DEF : + if (ni) { + if (!ntfs_allowed_as_owner(scx, ni) + || ntfs_remove_posix_acl(scx, ni, + (attr == XATTR_POSIX_ACC ? + nf_ns_xattr_posix_access : + nf_ns_xattr_posix_default))) + res = -errno; + } else + res = -errno; + break; +#endif + case XATTR_NTFS_REPARSE_DATA : + if (ni) { + if (!ntfs_allowed_as_owner(scx, ni) + || ntfs_remove_ntfs_reparse_data(ni)) + res = -errno; + } else + res = -errno; + break; + case XATTR_NTFS_OBJECT_ID : + if (ni) { + if (!ntfs_allowed_as_owner(scx, ni) + || ntfs_remove_ntfs_object_id(ni)) + res = -errno; + } else + res = -errno; + break; + case XATTR_NTFS_DOS_NAME: + if (ni && dir_ni) { + if (ntfs_remove_ntfs_dos_name(ni,dir_ni)) + res = -errno; + /* ni and dir_ni have been closed */ + } else + res = -errno; + break; + default : + errno = EOPNOTSUPP; + res = -errno; + break; + } + return (res); +} + +#endif /* HAVE_SETXATTR */ diff --git a/src/lowntfs-3g.c b/src/lowntfs-3g.c index cfbf845f..17105c73 100644 --- a/src/lowntfs-3g.c +++ b/src/lowntfs-3g.c @@ -102,6 +102,7 @@ #include "object_id.h" #include "efs.h" #include "logging.h" +#include "xattrs.h" #include "misc.h" /* @@ -2568,12 +2569,14 @@ done : * Name space identifications and prefixes */ -enum { XATTRNS_NONE, +enum { + XATTRNS_NONE, XATTRNS_USER, XATTRNS_SYSTEM, XATTRNS_SECURITY, XATTRNS_TRUSTED, - XATTRNS_OPEN } ; + XATTRNS_OPEN +} ; static const char nf_ns_user_prefix[] = "user."; static const int nf_ns_user_prefix_len = sizeof(nf_ns_user_prefix) - 1; @@ -2586,49 +2589,6 @@ static const int nf_ns_trusted_prefix_len = sizeof(nf_ns_trusted_prefix) - 1; static const char xattr_ntfs_3g[] = "ntfs-3g."; -/* - * Identification of data mapped to the system name space - */ - -enum { XATTR_UNMAPPED, - XATTR_NTFS_ACL, - XATTR_NTFS_ATTRIB, - XATTR_NTFS_EFSINFO, - XATTR_NTFS_REPARSE_DATA, - XATTR_NTFS_OBJECT_ID, - XATTR_NTFS_DOS_NAME, - XATTR_NTFS_TIMES, - XATTR_POSIX_ACC, - XATTR_POSIX_DEF } ; - -static const char nf_ns_xattr_ntfs_acl[] = "system.ntfs_acl"; -static const char nf_ns_xattr_attrib[] = "system.ntfs_attrib"; -static const char nf_ns_xattr_efsinfo[] = "user.ntfs.efsinfo"; -static const char nf_ns_xattr_reparse[] = "system.ntfs_reparse_data"; -static const char nf_ns_xattr_object_id[] = "system.ntfs_object_id"; -static const char nf_ns_xattr_dos_name[] = "system.ntfs_dos_name"; -static const char nf_ns_xattr_times[] = "system.ntfs_times"; -static const char nf_ns_xattr_posix_access[] = "system.posix_acl_access"; -static const char nf_ns_xattr_posix_default[] = "system.posix_acl_default"; - -struct XATTRNAME { - int xattr; - const char *name; -} ; - -static struct XATTRNAME nf_ns_xattr_names[] = { - { XATTR_NTFS_ACL, nf_ns_xattr_ntfs_acl }, - { XATTR_NTFS_ATTRIB, nf_ns_xattr_attrib }, - { XATTR_NTFS_EFSINFO, nf_ns_xattr_efsinfo }, - { XATTR_NTFS_REPARSE_DATA, nf_ns_xattr_reparse }, - { XATTR_NTFS_OBJECT_ID, nf_ns_xattr_object_id }, - { XATTR_NTFS_DOS_NAME, nf_ns_xattr_dos_name }, - { XATTR_NTFS_TIMES, nf_ns_xattr_times }, - { XATTR_POSIX_ACC, nf_ns_xattr_posix_access }, - { XATTR_POSIX_DEF, nf_ns_xattr_posix_default }, - { XATTR_UNMAPPED, (char*)NULL } /* terminator */ -}; - /* * Check whether access to internal data as an extended * attribute in system name space is allowed @@ -2700,21 +2660,6 @@ static ntfs_inode *ntfs_check_access_xattr(fuse_req_t req, return (ni); } -/* - * Determine whether an extended attribute is in the system - * name space and mapped to internal data - */ - -static int mapped_xattr_system(const char *name) -{ - struct XATTRNAME *p; - - p = nf_ns_xattr_names; - while (p->name && strcmp(p->name,name)) - p++; - return (p->xattr); -} - /* * Determine the name space of an extended attribute */ @@ -2796,7 +2741,6 @@ static void ntfs_fuse_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size) { ntfs_attr_search_ctx *actx = NULL; ntfs_inode *ni; - char *to; char *list = (char*)NULL; int ret = 0; #if !KERNELPERMS | (POSIXACLS & !KERNELACLS) @@ -2831,72 +2775,14 @@ static void ntfs_fuse_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size) goto exit; } } - to = list; if ((ctx->streams == NF_STREAMS_INTERFACE_XATTR) || (ctx->streams == NF_STREAMS_INTERFACE_OPENXATTR)) { - while (!ntfs_attr_lookup(AT_DATA, NULL, 0, CASE_SENSITIVE, - 0, NULL, 0, actx)) { - char *tmp_name = NULL; - int tmp_name_len; - - if (!actx->attr->name_length) - continue; - tmp_name_len = ntfs_ucstombs( - (ntfschar *)((u8*)actx->attr + - le16_to_cpu(actx->attr->name_offset)), - actx->attr->name_length, &tmp_name, 0); - if (tmp_name_len < 0) { - ret = -errno; - goto exit; - } - /* - * When using name spaces, do not return - * security, trusted nor system attributes - * (filtered elsewhere anyway) - * otherwise insert "user." prefix - */ - if (ctx->streams == NF_STREAMS_INTERFACE_XATTR) { - if ((strlen(tmp_name) > sizeof(xattr_ntfs_3g)) - && !strncmp(tmp_name,xattr_ntfs_3g, - sizeof(xattr_ntfs_3g)-1)) - tmp_name_len = 0; - else - ret += tmp_name_len - + nf_ns_user_prefix_len + 1; - } else - ret += tmp_name_len + 1; - if (size && tmp_name_len) { - if ((size_t)ret <= size) { - if (ctx->streams - == NF_STREAMS_INTERFACE_XATTR) { - strcpy(to, nf_ns_user_prefix); - to += nf_ns_user_prefix_len; - } - strncpy(to, tmp_name, tmp_name_len); - to += tmp_name_len; - *to = 0; - to++; - } else { - free(tmp_name); - ret = -ERANGE; - goto exit; - } - } - free(tmp_name); - } + ret = ntfs_xattr_listxattr(ni, actx, list, size, + ctx->streams == NF_STREAMS_INTERFACE_XATTR); + if (ret < 0) + goto exit; } - - /* List efs info xattr for encrypted files */ - if (ctx->efs_raw && (ni->flags & FILE_ATTR_ENCRYPTED)) { - ret += sizeof(nf_ns_xattr_efsinfo); - if ((size_t)ret <= size) { - memcpy(to, nf_ns_xattr_efsinfo, - sizeof(nf_ns_xattr_efsinfo)); - to += sizeof(nf_ns_xattr_efsinfo); - } - } - if (errno != ENOENT) ret = -errno; exit: @@ -2915,82 +2801,22 @@ out : free(list); } -static __inline__ int ntfs_system_getxattr(struct SECURITY_CONTEXT *scx, - int attr, ntfs_inode *ni, char *value, size_t size) -{ - int res; - ntfs_inode *dir_ni; - - /* - * the returned value is the needed - * size. If it is too small, no copy - * is done, and the caller has to - * issue a new call with correct size. - */ - switch (attr) { - case XATTR_NTFS_ACL : - res = ntfs_get_ntfs_acl(scx, ni, value, size); - break; -#if POSIXACLS - case XATTR_POSIX_ACC : - res = ntfs_get_posix_acl(scx, ni, nf_ns_xattr_posix_access, - value, size); - break; - case XATTR_POSIX_DEF : - res = ntfs_get_posix_acl(scx, ni, nf_ns_xattr_posix_default, - value, size); - break; -#endif - case XATTR_NTFS_ATTRIB : - res = ntfs_get_ntfs_attrib(ni, value, size); - break; - case XATTR_NTFS_EFSINFO : - if (ctx->efs_raw) - res = ntfs_get_efs_info(ni, value, size); - else - res = -EPERM; - break; - case XATTR_NTFS_REPARSE_DATA : - res = ntfs_get_ntfs_reparse_data(ni, value, size); - break; - case XATTR_NTFS_OBJECT_ID : - res = ntfs_get_ntfs_object_id(ni, value, size); - break; - case XATTR_NTFS_DOS_NAME: - dir_ni = ntfs_dir_parent_inode(ni); - if (dir_ni) { - res = ntfs_get_ntfs_dos_name(ni, dir_ni, value, size); - if (ntfs_inode_close(dir_ni)) - set_fuse_error(&res); - } else - res = -errno; - break; - case XATTR_NTFS_TIMES: - res = ntfs_inode_get_times(ni, value, size); - break; - default : - errno = EOPNOTSUPP; - res = -errno; - break; - } - return (res); -} - static void ntfs_fuse_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name, size_t size) { ntfs_inode *ni; + ntfs_inode *dir_ni; ntfs_attr *na = NULL; char *value = (char*)NULL; ntfschar *lename = (ntfschar*)NULL; int lename_len; int res; s64 rsize; - int attr; + enum SYSTEMXATTRS attr; int namespace; struct SECURITY_CONTEXT security; - attr = mapped_xattr_system(name); + attr = ntfs_xattr_system_type(name); if (attr != XATTR_UNMAPPED) { /* * hijack internal data and ACL retrieval, whatever @@ -3004,10 +2830,16 @@ static void ntfs_fuse_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name, ni = ntfs_check_access_xattr(req, &security, ino, attr, FALSE); if (ni) { - if (ntfs_allowed_access(&security,ni,S_IREAD)) - res = ntfs_system_getxattr(&security, - attr, ni, value, size); - else + if (ntfs_allowed_access(&security,ni,S_IREAD)) { + if (attr == XATTR_NTFS_DOS_NAME) + dir_ni = ntfs_dir_parent_inode(ni); + else + dir_ni = (ntfs_inode*)NULL; + res = ntfs_xattr_system_getxattr(&security, + attr, ni, dir_ni, value, size); + if (dir_ni && ntfs_inode_close(dir_ni)) + set_fuse_error(&res); + } else res = -errno; if (ntfs_inode_close(ni)) set_fuse_error(&res); @@ -3023,8 +2855,14 @@ static void ntfs_fuse_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name, if (ni) { /* user mapping not mandatory */ ntfs_fuse_fill_security_context(req, &security); - res = ntfs_system_getxattr(&security, - attr, ni, value, size); + if (attr == XATTR_NTFS_DOS_NAME) + dir_ni = ntfs_dir_parent_inode(ni); + else + dir_ni = (ntfs_inode*)NULL; + res = ntfs_xattr_system_getxattr(&security, + attr, ni, dir_ni, value, size); + if (dir_ni && ntfs_inode_close(dir_ni)) + set_fuse_error(&res); if (ntfs_inode_close(ni)) set_fuse_error(&res); } else @@ -3118,76 +2956,21 @@ out : free(value); } -static __inline__ int ntfs_system_setxattr(struct SECURITY_CONTEXT *scx, - int attr, ntfs_inode *ni, const char *value, - size_t size, int flags) -{ - int res; - ntfs_inode *dir_ni; - - switch (attr) { - case XATTR_NTFS_ACL : - res = ntfs_set_ntfs_acl(scx, ni, value, size, flags); - break; -#if POSIXACLS - case XATTR_POSIX_ACC : - res = ntfs_set_posix_acl(scx ,ni , nf_ns_xattr_posix_access, - value, size, flags); - break; - case XATTR_POSIX_DEF : - res = ntfs_set_posix_acl(scx, ni, nf_ns_xattr_posix_default, - value, size, flags); - break; -#endif - case XATTR_NTFS_ATTRIB : - res = ntfs_set_ntfs_attrib(ni, value, size, flags); - break; - case XATTR_NTFS_EFSINFO : - if (ctx->efs_raw) - res = ntfs_set_efs_info(ni, value, size, flags); - else - res = -EPERM; - break; - case XATTR_NTFS_REPARSE_DATA : - res = ntfs_set_ntfs_reparse_data(ni, value, size, flags); - break; - case XATTR_NTFS_OBJECT_ID : - res = ntfs_set_ntfs_object_id(ni, value, size, flags); - break; - case XATTR_NTFS_DOS_NAME: - dir_ni = ntfs_dir_parent_inode(ni); - if (dir_ni) - /* warning : this closes both inodes */ - res = ntfs_set_ntfs_dos_name(ni, dir_ni, value, - size, flags); - else - res = -errno; - break; - case XATTR_NTFS_TIMES: - res = ntfs_inode_set_times(ni, value, size, flags); - break; - default : - errno = EOPNOTSUPP; - res = -errno; - break; - } - return (res); -} - static void ntfs_fuse_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name, const char *value, size_t size, int flags) { ntfs_inode *ni; + ntfs_inode *dir_ni; ntfs_attr *na = NULL; ntfschar *lename = NULL; int res, lename_len; size_t total; s64 part; - int attr; + enum SYSTEMXATTRS attr; int namespace; struct SECURITY_CONTEXT security; - attr = mapped_xattr_system(name); + attr = ntfs_xattr_system_type(name); if (attr != XATTR_UNMAPPED) { /* * hijack internal data and ACL setting, whatever @@ -3199,8 +2982,13 @@ static void ntfs_fuse_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name, ni = ntfs_check_access_xattr(req,&security,ino,attr,TRUE); if (ni) { if (ntfs_allowed_as_owner(&security, ni)) { - res = ntfs_system_setxattr(&security, - attr, ni, value, size, flags); + if (attr == XATTR_NTFS_DOS_NAME) + dir_ni = ntfs_dir_parent_inode(ni); + else + dir_ni = (ntfs_inode*)NULL; + res = ntfs_xattr_system_setxattr(&security, + attr, ni, dir_ni, value, size, flags); + /* never have to close dir_ni */ if (res) res = -errno; } else @@ -3224,8 +3012,13 @@ static void ntfs_fuse_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name, */ if (!ntfs_fuse_fill_security_context(req, &security) || ntfs_allowed_as_owner(&security, ni)) { - res = ntfs_system_setxattr(&security, - attr, ni, value, size, flags); + if (attr == XATTR_NTFS_DOS_NAME) + dir_ni = ntfs_dir_parent_inode(ni); + else + dir_ni = (ntfs_inode*)NULL; + res = ntfs_xattr_system_setxattr(&security, + attr, ni, dir_ni, value, size, flags); + /* never have to close dir_ni */ if (res) res = -errno; } else @@ -3363,103 +3156,84 @@ out : fuse_reply_err(req, 0); } -static __inline__ int ntfs_system_removexattr(fuse_req_t req, fuse_ino_t ino, - int attr) -{ - int res; - ntfs_inode *dir_ni; - ntfs_inode *ni; - struct SECURITY_CONTEXT security; - - res = 0; - switch (attr) { - /* - * Removal of NTFS ACL, ATTRIB, EFSINFO or TIMES - * is never allowed - */ - case XATTR_NTFS_ACL : - case XATTR_NTFS_ATTRIB : - case XATTR_NTFS_EFSINFO : - case XATTR_NTFS_TIMES : - res = -EPERM; - break; -#if POSIXACLS - case XATTR_POSIX_ACC : - case XATTR_POSIX_DEF : - ni = ntfs_check_access_xattr(req,&security,ino,attr,TRUE); - if (ni) { - if (!ntfs_allowed_as_owner(&security, ni) - || ntfs_remove_posix_acl(&security, ni, - (attr == XATTR_POSIX_ACC ? - nf_ns_xattr_posix_access : - nf_ns_xattr_posix_default))) - res = -errno; - if (ntfs_inode_close(ni)) - set_fuse_error(&res); - } else - res = -errno; - break; -#endif - case XATTR_NTFS_REPARSE_DATA : - ni = ntfs_check_access_xattr(req, &security, ino, attr, TRUE); - if (ni) { - if (!ntfs_allowed_as_owner(&security, ni) - || ntfs_remove_ntfs_reparse_data(ni)) - res = -errno; - if (ntfs_inode_close(ni)) - set_fuse_error(&res); - } else - res = -errno; - break; - case XATTR_NTFS_OBJECT_ID : - ni = ntfs_check_access_xattr(req, &security, ino, attr, TRUE); - if (ni) { - if (!ntfs_allowed_as_owner(&security, ni) - || ntfs_remove_ntfs_object_id(ni)) - res = -errno; - if (ntfs_inode_close(ni)) - set_fuse_error(&res); - } else - res = -errno; - break; - case XATTR_NTFS_DOS_NAME: - ni = ntfs_check_access_xattr(req,&security,ino,attr,TRUE); - if (ni) { - dir_ni = ntfs_dir_parent_inode(ni); - if (!dir_ni - || ntfs_remove_ntfs_dos_name(ni,dir_ni)) - res = -errno; - } else - res = -errno; - break; - default : - errno = EOPNOTSUPP; - res = -errno; - break; - } - return (res); -} - static void ntfs_fuse_removexattr(fuse_req_t req, fuse_ino_t ino, const char *name) { ntfs_inode *ni; + ntfs_inode *dir_ni; ntfschar *lename = NULL; int res = 0, lename_len; - int attr; + enum SYSTEMXATTRS attr; int namespace; -#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) struct SECURITY_CONTEXT security; -#endif - attr = mapped_xattr_system(name); + attr = ntfs_xattr_system_type(name); if (attr != XATTR_UNMAPPED) { - /* - * hijack internal data and ACL removal, whatever - * mode was selected for xattr (from the user's - * point of view, ACLs are not xattr) - * Note : updating an ACL does not set ctime - */ - res = ntfs_system_removexattr(req, ino, attr); + switch (attr) { + /* + * Removal of NTFS ACL, ATTRIB, EFSINFO or TIMES + * is never allowed + */ + case XATTR_NTFS_ACL : + case XATTR_NTFS_ATTRIB : + case XATTR_NTFS_EFSINFO : + case XATTR_NTFS_TIMES : + res = -EPERM; + break; + default : +#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) + ni = ntfs_check_access_xattr(req, &security, ino, + attr,TRUE); + if (ni) { + if (ntfs_allowed_as_owner(&security, ni)) { + if (attr == XATTR_NTFS_DOS_NAME) + dir_ni = ntfs_dir_parent_inode(ni); + else + dir_ni = (ntfs_inode*)NULL; + res = ntfs_xattr_system_removexattr(&security, + attr, ni, dir_ni); + if (res) + res = -errno; + /* never have to close dir_ni */ + } else + res = -errno; + if ((attr != XATTR_NTFS_DOS_NAME) + && ntfs_inode_close(ni)) + set_fuse_error(&res); + } else + res = -errno; +#else + /* creation of a new name is not controlled by fuse */ + if (attr == XATTR_NTFS_DOS_NAME) + ni = ntfs_check_access_xattr(req, &security, + ino, attr, TRUE); + else + ni = ntfs_inode_open(ctx->vol, INODE(ino)); + if (ni) { + /* + * user mapping is not mandatory + * if defined, only owner is allowed + */ + if (!ntfs_fuse_fill_security_context(req, &security) + || ntfs_allowed_as_owner(&security, ni)) { + if (attr == XATTR_NTFS_DOS_NAME) + dir_ni = ntfs_dir_parent_inode(ni); + else + dir_ni = (ntfs_inode*)NULL; + res = ntfs_xattr_system_removexattr(&security, + attr, ni, dir_ni); + /* never have to close dir_ni */ + if (res) + res = -errno; + } else + res = -errno; + if ((attr != XATTR_NTFS_DOS_NAME) + && ntfs_inode_close(ni)) + set_fuse_error(&res); + } else + res = -errno; +#endif + break; + } if (res < 0) fuse_reply_err(req, -res); else diff --git a/src/ntfs-3g.c b/src/ntfs-3g.c index cecdce77..1c1ff389 100644 --- a/src/ntfs-3g.c +++ b/src/ntfs-3g.c @@ -101,6 +101,7 @@ #include "object_id.h" #include "efs.h" #include "logging.h" +#include "xattrs.h" #include "misc.h" /* @@ -454,6 +455,28 @@ static int ntfs_allowed_real_dir_access(struct SECURITY_CONTEXT *scx, return (allowed); } +static ntfs_inode *get_parent_dir(const char *path) +{ + ntfs_inode *dir_ni; + char *dirpath; + char *p; + + dirpath = strdup(path); + dir_ni = (ntfs_inode*)NULL; + if (dirpath) { + p = strrchr(dirpath,'/'); + if (p) { /* always present, be safe */ + *p = 0; + dir_ni = ntfs_pathname_to_inode(ctx->vol, + NULL, dirpath); + } + free(dirpath); + } else + errno = ENOMEM; + return (dir_ni); +} + + #endif /* HAVE_SETXATTR */ /** @@ -2436,12 +2459,14 @@ close_inode: * Name space identifications and prefixes */ -enum { XATTRNS_NONE, +enum { + XATTRNS_NONE, XATTRNS_USER, XATTRNS_SYSTEM, XATTRNS_SECURITY, XATTRNS_TRUSTED, - XATTRNS_OPEN } ; + XATTRNS_OPEN +} ; static const char nf_ns_user_prefix[] = "user."; static const int nf_ns_user_prefix_len = sizeof(nf_ns_user_prefix) - 1; @@ -2454,49 +2479,6 @@ static const int nf_ns_trusted_prefix_len = sizeof(nf_ns_trusted_prefix) - 1; static const char xattr_ntfs_3g[] = "ntfs-3g."; -/* - * Identification of data mapped to the system name space - */ - -enum { XATTR_UNMAPPED, - XATTR_NTFS_ACL, - XATTR_NTFS_ATTRIB, - XATTR_NTFS_EFSINFO, - XATTR_NTFS_REPARSE_DATA, - XATTR_NTFS_OBJECT_ID, - XATTR_NTFS_DOS_NAME, - XATTR_NTFS_TIMES, - XATTR_POSIX_ACC, - XATTR_POSIX_DEF } ; - -static const char nf_ns_xattr_ntfs_acl[] = "system.ntfs_acl"; -static const char nf_ns_xattr_attrib[] = "system.ntfs_attrib"; -static const char nf_ns_xattr_efsinfo[] = "user.ntfs.efsinfo"; -static const char nf_ns_xattr_reparse[] = "system.ntfs_reparse_data"; -static const char nf_ns_xattr_object_id[] = "system.ntfs_object_id"; -static const char nf_ns_xattr_dos_name[] = "system.ntfs_dos_name"; -static const char nf_ns_xattr_times[] = "system.ntfs_times"; -static const char nf_ns_xattr_posix_access[] = "system.posix_acl_access"; -static const char nf_ns_xattr_posix_default[] = "system.posix_acl_default"; - -struct XATTRNAME { - int xattr; - const char *name; -} ; - -static struct XATTRNAME nf_ns_xattr_names[] = { - { XATTR_NTFS_ACL, nf_ns_xattr_ntfs_acl }, - { XATTR_NTFS_ATTRIB, nf_ns_xattr_attrib }, - { XATTR_NTFS_EFSINFO, nf_ns_xattr_efsinfo }, - { XATTR_NTFS_REPARSE_DATA, nf_ns_xattr_reparse }, - { XATTR_NTFS_OBJECT_ID, nf_ns_xattr_object_id }, - { XATTR_NTFS_DOS_NAME, nf_ns_xattr_dos_name }, - { XATTR_NTFS_TIMES, nf_ns_xattr_times }, - { XATTR_POSIX_ACC, nf_ns_xattr_posix_access }, - { XATTR_POSIX_DEF, nf_ns_xattr_posix_default }, - { XATTR_UNMAPPED, (char*)NULL } /* terminator */ -}; - /* * Check whether access to internal data as an extended * attribute in system name space is allowed @@ -2552,21 +2534,6 @@ static ntfs_inode *ntfs_check_access_xattr(struct SECURITY_CONTEXT *security, return (ni); } -/* - * Determine whether an extended attribute is in the system - * name space and mapped to internal data - */ - -static int mapped_xattr_system(const char *name) -{ - struct XATTRNAME *p; - - p = nf_ns_xattr_names; - while (p->name && strcmp(p->name,name)) - p++; - return (p->xattr); -} - /* * Determine the name space of an extended attribute */ @@ -2648,7 +2615,6 @@ static int ntfs_fuse_listxattr(const char *path, char *list, size_t size) { ntfs_attr_search_ctx *actx = NULL; ntfs_inode *ni; - char *to = list; int ret = 0; #if !KERNELPERMS | (POSIXACLS & !KERNELACLS) struct SECURITY_CONTEXT security; @@ -2679,68 +2645,11 @@ static int ntfs_fuse_listxattr(const char *path, char *list, size_t size) if ((ctx->streams == NF_STREAMS_INTERFACE_XATTR) || (ctx->streams == NF_STREAMS_INTERFACE_OPENXATTR)) { - while (!ntfs_attr_lookup(AT_DATA, NULL, 0, CASE_SENSITIVE, - 0, NULL, 0, actx)) { - char *tmp_name = NULL; - int tmp_name_len; - - if (!actx->attr->name_length) - continue; - tmp_name_len = ntfs_ucstombs( - (ntfschar *)((u8*)actx->attr + - le16_to_cpu(actx->attr->name_offset)), - actx->attr->name_length, &tmp_name, 0); - if (tmp_name_len < 0) { - ret = -errno; - goto exit; - } - /* - * When using name spaces, do not return - * security, trusted nor system attributes - * (filtered elsewhere anyway) - * otherwise insert "user." prefix - */ - if (ctx->streams == NF_STREAMS_INTERFACE_XATTR) { - if ((strlen(tmp_name) > sizeof(xattr_ntfs_3g)) - && !strncmp(tmp_name,xattr_ntfs_3g, - sizeof(xattr_ntfs_3g)-1)) - tmp_name_len = 0; - else - ret += tmp_name_len - + nf_ns_user_prefix_len + 1; - } else - ret += tmp_name_len + 1; - if (size && tmp_name_len) { - if ((size_t)ret <= size) { - if (ctx->streams - == NF_STREAMS_INTERFACE_XATTR) { - strcpy(to, nf_ns_user_prefix); - to += nf_ns_user_prefix_len; - } - strncpy(to, tmp_name, tmp_name_len); - to += tmp_name_len; - *to = 0; - to++; - } else { - free(tmp_name); - ret = -ERANGE; - goto exit; - } - } - free(tmp_name); - } + ret = ntfs_xattr_listxattr(ni, actx, list, size, + ctx->streams == NF_STREAMS_INTERFACE_XATTR); + if (ret < 0) + goto exit; } - - /* List efs info xattr for encrypted files */ - if (ctx->efs_raw && (ni->flags & FILE_ATTR_ENCRYPTED)) { - ret += sizeof(nf_ns_xattr_efsinfo); - if ((size_t)ret <= size) { - memcpy(to, nf_ns_xattr_efsinfo, - sizeof(nf_ns_xattr_efsinfo)); - to += sizeof(nf_ns_xattr_efsinfo); - } - } - if (errno != ENOENT) ret = -errno; exit: @@ -2830,99 +2739,20 @@ exit: return ret; } -static __inline__ int ntfs_system_getxattr(struct SECURITY_CONTEXT *scx, - const char *path, int attr, ntfs_inode *ni, - char *value, size_t size) -{ - int res; - ntfs_inode *dir_ni; - char *dirpath; - char *p; - /* - * the returned value is the needed - * size. If it is too small, no copy - * is done, and the caller has to - * issue a new call with correct size. - */ - switch (attr) { - case XATTR_NTFS_ACL : - res = ntfs_get_ntfs_acl(scx, ni, value, size); - break; -#if POSIXACLS - case XATTR_POSIX_ACC : - res = ntfs_get_posix_acl(scx, ni, nf_ns_xattr_posix_access, - value, size); - break; - case XATTR_POSIX_DEF : - res = ntfs_get_posix_acl(scx, ni, nf_ns_xattr_posix_default, - value, size); - break; -#endif - case XATTR_NTFS_ATTRIB : - res = ntfs_get_ntfs_attrib(ni, value, size); - break; - case XATTR_NTFS_EFSINFO : - if (ctx->efs_raw) - res = ntfs_get_efs_info(ni, value, size); - else - res = -EPERM; - break; - case XATTR_NTFS_REPARSE_DATA : - res = ntfs_get_ntfs_reparse_data(ni, value, size); - break; - case XATTR_NTFS_OBJECT_ID : - res = ntfs_get_ntfs_object_id(ni, value, size); - break; - case XATTR_NTFS_DOS_NAME: - res = 0; - dirpath = strdup(path); - if (dirpath) { - p = strrchr(dirpath,'/'); /* always present */ - *p = 0; - dir_ni = ntfs_pathname_to_inode(ni->vol, - NULL, dirpath); - if (dir_ni) { - res = ntfs_get_ntfs_dos_name(ni, - dir_ni, value, size); - if (ntfs_inode_close(dir_ni)) - set_fuse_error(&res); - } else - res = -errno; - free(dirpath); - } else - res = -ENOMEM; - if (res < 0) - errno = -res; - break; - case XATTR_NTFS_TIMES: - res = ntfs_inode_get_times(ni, value, size); - break; - default : - /* - * make sure applications do not see - * Posix ACL not consistent with mode - */ - errno = EOPNOTSUPP; - res = -errno; - break; - } - return (res); -} - - static int ntfs_fuse_getxattr(const char *path, const char *name, char *value, size_t size) { ntfs_inode *ni; + ntfs_inode *dir_ni; ntfs_attr *na = NULL; ntfschar *lename = NULL; int res, lename_len; s64 rsize; - int attr; + enum SYSTEMXATTRS attr; int namespace; struct SECURITY_CONTEXT security; - attr = mapped_xattr_system(name); + attr = ntfs_xattr_system_type(name); if (attr != XATTR_UNMAPPED) { #if !KERNELPERMS | (POSIXACLS & !KERNELACLS) /* @@ -2933,8 +2763,14 @@ static int ntfs_fuse_getxattr(const char *path, const char *name, ni = ntfs_check_access_xattr(&security, path, attr, FALSE); if (ni) { if (ntfs_allowed_access(&security,ni,S_IREAD)) { - res = ntfs_system_getxattr(&security, - path, attr, ni, value, size); + if (attr == XATTR_NTFS_DOS_NAME) + dir_ni = get_parent_dir(path); + else + dir_ni = (ntfs_inode*)NULL; + res = ntfs_xattr_system_getxattr(&security, + attr, ni, dir_ni, value, size); + if (dir_ni && ntfs_inode_close(dir_ni)) + set_fuse_error(&res); } else { res = -errno; } @@ -2955,8 +2791,14 @@ static int ntfs_fuse_getxattr(const char *path, const char *name, if (ni) { /* user mapping not mandatory */ ntfs_fuse_fill_security_context(&security); - res = ntfs_system_getxattr(&security, - path, attr, ni, value, size); + if (attr == XATTR_NTFS_DOS_NAME) + dir_ni = get_parent_dir(path); + else + dir_ni = (ntfs_inode*)NULL; + res = ntfs_xattr_system_getxattr(&security, + attr, ni, dir_ni, value, size); + if (dir_ni && ntfs_inode_close(dir_ni)) + set_fuse_error(&res); if (ntfs_inode_close(ni)) set_fuse_error(&res); } else @@ -3028,94 +2870,21 @@ exit: return res; } -static __inline__ int ntfs_system_setxattr(struct SECURITY_CONTEXT *scx, - const char *path, int attr, ntfs_inode *ni, - const char *value, size_t size, int flags) -{ - int res; - char *dirpath; - char *p; - ntfs_inode *dir_ni; - - switch (attr) { - case XATTR_NTFS_ACL : - res = ntfs_set_ntfs_acl(scx, ni, value, size, flags); - break; -#if POSIXACLS - case XATTR_POSIX_ACC : - res = ntfs_set_posix_acl(scx,ni, nf_ns_xattr_posix_access, - value, size, flags); - break; - case XATTR_POSIX_DEF : - res = ntfs_set_posix_acl(scx, ni, nf_ns_xattr_posix_default, - value, size, flags); - break; -#endif - case XATTR_NTFS_ATTRIB : - res = ntfs_set_ntfs_attrib(ni, value, size, flags); - break; - case XATTR_NTFS_EFSINFO : - if (ctx->efs_raw) - res = ntfs_set_efs_info(ni, value, size, flags); - else - res = -EPERM; - break; - case XATTR_NTFS_REPARSE_DATA : - res = ntfs_set_ntfs_reparse_data(ni, value, size, flags); - break; - case XATTR_NTFS_OBJECT_ID : - res = ntfs_set_ntfs_object_id(ni, value, size, flags); - break; - case XATTR_NTFS_DOS_NAME: - res = 0; - dirpath = strdup(path); - if (dirpath) { - p = strrchr(dirpath,'/'); /* always present */ - *p = 0; - dir_ni = ntfs_pathname_to_inode(ni->vol, - NULL, dirpath); - if (dir_ni) - /* warning : this closes both inodes */ - res = ntfs_set_ntfs_dos_name(ni, dir_ni, - value,size,flags); - else - res = -errno; - free(dirpath); - } else - res = -ENOMEM; - if (res < 0) - errno = -res; - break; - case XATTR_NTFS_TIMES: - res = ntfs_inode_set_times(ni, value, size, flags); - break; - default : - /* - * make sure applications do not see - * Posix ACL not consistent with mode - */ - errno = EOPNOTSUPP; - res = -errno; - break; - } - return (res); -} - - static int ntfs_fuse_setxattr(const char *path, const char *name, const char *value, size_t size, int flags) { ntfs_inode *ni; + ntfs_inode *dir_ni; ntfs_attr *na = NULL; ntfschar *lename = NULL; int res, lename_len; size_t total; s64 part; - int attr; + enum SYSTEMXATTRS attr; int namespace; struct SECURITY_CONTEXT security; - attr = mapped_xattr_system(name); + attr = ntfs_xattr_system_type(name); if (attr != XATTR_UNMAPPED) { #if !KERNELPERMS | (POSIXACLS & !KERNELACLS) /* @@ -3127,8 +2896,13 @@ static int ntfs_fuse_setxattr(const char *path, const char *name, ni = ntfs_check_access_xattr(&security,path,attr,TRUE); if (ni) { if (ntfs_allowed_as_owner(&security,ni)) { - res = ntfs_system_setxattr(&security, - path, attr, ni, value, size, flags); + if (attr == XATTR_NTFS_DOS_NAME) + dir_ni = get_parent_dir(path); + else + dir_ni = (ntfs_inode*)NULL; + res = ntfs_xattr_system_setxattr(&security, + attr, ni, dir_ni, value, size, flags); + /* never have to close dir_ni */ if (res) res = -errno; } else @@ -3159,9 +2933,14 @@ static int ntfs_fuse_setxattr(const char *path, const char *name, */ if (!ntfs_fuse_fill_security_context(&security) || ntfs_allowed_as_owner(&security,ni)) { - res = ntfs_system_setxattr(&security, - path, attr, ni, value, + if (attr == XATTR_NTFS_DOS_NAME) + dir_ni = get_parent_dir(path); + else + dir_ni = (ntfs_inode*)NULL; + res = ntfs_xattr_system_setxattr(&security, + attr, ni, dir_ni, value, size, flags); + /* never have to close dir_ni */ if (res) res = -errno; } else @@ -3289,134 +3068,100 @@ exit: return res; } -static __inline__ int ntfs_system_removexattr(const char *path, - int attr) +static int ntfs_fuse_removexattr(const char *path, const char *name) { - int res; - ntfs_inode *dir_ni; ntfs_inode *ni; - char *dirpath; - char *p; + ntfs_inode *dir_ni; + ntfschar *lename = NULL; + int res = 0, lename_len; + enum SYSTEMXATTRS attr; + int namespace; struct SECURITY_CONTEXT security; - res = 0; - switch (attr) { + attr = ntfs_xattr_system_type(name); + if (attr != XATTR_UNMAPPED) { + switch (attr) { /* * Removal of NTFS ACL, ATTRIB, EFSINFO or TIMES * is never allowed */ - case XATTR_NTFS_ACL : - case XATTR_NTFS_ATTRIB : - case XATTR_NTFS_EFSINFO : - case XATTR_NTFS_TIMES : - res = -EPERM; - break; -#if POSIXACLS - case XATTR_POSIX_ACC : - case XATTR_POSIX_DEF : - ni = ntfs_check_access_xattr(&security, path, attr, TRUE); - if (ni) { - if (!ntfs_allowed_as_owner(&security,ni) - || ntfs_remove_posix_acl(&security,ni, - (attr == XATTR_POSIX_ACC ? - nf_ns_xattr_posix_access : - nf_ns_xattr_posix_default))) - res = -errno; - if (ntfs_inode_close(ni)) - set_fuse_error(&res); - } else - res = -errno; - break; -#endif - case XATTR_NTFS_REPARSE_DATA : - ni = ntfs_check_access_xattr(&security, path, attr, TRUE); - if (ni) { - if (!ntfs_allowed_as_owner(&security,ni) - || ntfs_remove_ntfs_reparse_data(ni)) - res = -errno; - if (ntfs_inode_close(ni)) - set_fuse_error(&res); - } else - res = -errno; - break; - case XATTR_NTFS_OBJECT_ID : - ni = ntfs_check_access_xattr(&security,path,attr,TRUE); - if (ni) { - if (!ntfs_allowed_as_owner(&security,ni) - || ntfs_remove_ntfs_object_id(ni)) - res = -errno; - if (ntfs_inode_close(ni)) - set_fuse_error(&res); - } else - res = -errno; - break; - case XATTR_NTFS_DOS_NAME: - res = 0; - ni = ntfs_check_access_xattr(&security,path,attr,TRUE); - if (ni) { - dirpath = strdup(path); - if (dirpath) { - p = strrchr(dirpath,'/'); /* always present */ - *p = 0; - dir_ni = ntfs_pathname_to_inode(ni->vol, - NULL, dirpath); - if (!dir_ni - || ntfs_remove_ntfs_dos_name(ni, dir_ni)) - res = -errno; - free(dirpath); - } else - res = -ENOMEM; - if (res < 0) - errno = -res; - } else - res = -errno; - break; - default : - /* - * make sure applications do not see - * Posix ACL not consistent with mode - */ - errno = EOPNOTSUPP; - res = -errno; - break; - } - return (res); -} - -static int ntfs_fuse_removexattr(const char *path, const char *name) -{ - ntfs_inode *ni; - ntfschar *lename = NULL; - int res = 0, lename_len; - int attr; - int namespace; + case XATTR_NTFS_ACL : + case XATTR_NTFS_ATTRIB : + case XATTR_NTFS_EFSINFO : + case XATTR_NTFS_TIMES : + res = -EPERM; + break; + default : #if !KERNELPERMS | (POSIXACLS & !KERNELACLS) - struct SECURITY_CONTEXT security; -#endif - - attr = mapped_xattr_system(name); - if (attr != XATTR_UNMAPPED) { -#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) - /* * hijack internal data and ACL removal, whatever * mode was selected for xattr (from the user's * point of view, ACLs are not xattr) * Note : updating an ACL does not set ctime */ - res = ntfs_system_removexattr(path, attr); + ni = ntfs_check_access_xattr(&security,path,attr,TRUE); + if (ni) { + if (ntfs_allowed_as_owner(&security,ni)) { + if (attr == XATTR_NTFS_DOS_NAME) + dir_ni = get_parent_dir(path); + else + dir_ni = (ntfs_inode*)NULL; + res = ntfs_xattr_system_removexattr(&security, + attr, ni, dir_ni); + /* never have to close dir_ni */ + if (res) + res = -errno; + } else + res = -errno; + if ((attr != XATTR_NTFS_DOS_NAME) + && ntfs_inode_close(ni)) + set_fuse_error(&res); + } else + res = -errno; #else /* - * Only hijack NTFS ACL and ATTRIB removal if POSIX ACLS + * Only hijack NTFS ACL setting if POSIX ACLS * option is not selected * Access control is partially done by fuse */ - if (ntfs_fuse_is_named_data_stream(path)) - res = -EINVAL; /* n/a for named data streams. */ - else { - res = ntfs_system_removexattr(path, attr); - } + /* creation of a new name is not controlled by fuse */ + if (attr == XATTR_NTFS_DOS_NAME) + ni = ntfs_check_access_xattr(&security, + path, attr, TRUE); + else { + if (ntfs_fuse_is_named_data_stream(path)) { + ni = (ntfs_inode*)NULL; + errno = EINVAL; /* n/a for named data streams. */ + } else + ni = ntfs_pathname_to_inode(ctx->vol, + NULL, path); + } + if (ni) { + /* + * user mapping is not mandatory + * if defined, only owner is allowed + */ + if (!ntfs_fuse_fill_security_context(&security) + || ntfs_allowed_as_owner(&security,ni)) { + if (attr == XATTR_NTFS_DOS_NAME) + dir_ni = get_parent_dir(path); + else + dir_ni = (ntfs_inode*)NULL; + res = ntfs_xattr_system_removexattr(&security, + attr, ni, dir_ni); + /* never have to close dir_ni */ + if (res) + res = -errno; + } else + res = -errno; + if ((attr != XATTR_NTFS_DOS_NAME) + && ntfs_inode_close(ni)) + set_fuse_error(&res); + } else + res = -errno; #endif + break; + } return (res); } if ((ctx->streams != NF_STREAMS_INTERFACE_XATTR)