Grouped system extended attributes functions into a dedicated module

PERMISSION_HANDLING_BRANCH
Jean-Pierre André 2010-10-26 08:59:51 +02:00
parent 1afaf16912
commit e1ef554dd2
6 changed files with 677 additions and 739 deletions

View File

@ -35,7 +35,8 @@ headers = \
support.h \
types.h \
unistr.h \
volume.h
volume.h \
xattrs.h
if INSTALL_LIBRARY
ntfs3ginclude_HEADERS = $(headers)

View File

@ -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_ */

View File

@ -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

359
libntfs-3g/xattrs.c 100644
View File

@ -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 <stdio.h>
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_ERRNO_H
#include <errno.h>
#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 */

View File

@ -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

View File

@ -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)