From d990f7996cf9b2993af6e2ebba8ed4587060b37b Mon Sep 17 00:00:00 2001 From: jpandre Date: Thu, 17 Dec 2009 08:24:13 +0000 Subject: [PATCH] Changed the interfaces to use extended attributes --- include/ntfs-3g/dir.h | 11 +- include/ntfs-3g/efs.h | 9 +- include/ntfs-3g/inode.h | 8 +- include/ntfs-3g/reparse.h | 10 +- libntfs-3g/dir.c | 234 +++++++++-------- libntfs-3g/efs.c | 25 +- libntfs-3g/inode.c | 8 +- libntfs-3g/reparse.c | 11 +- src/ntfs-3g.c | 512 ++++++++++++++++++-------------------- 9 files changed, 408 insertions(+), 420 deletions(-) diff --git a/include/ntfs-3g/dir.h b/include/ntfs-3g/dir.h index 796e61ff..494763dc 100644 --- a/include/ntfs-3g/dir.h +++ b/include/ntfs-3g/dir.h @@ -106,12 +106,11 @@ extern int ntfs_readdir(ntfs_inode *dir_ni, s64 *pos, ntfs_inode *ntfs_dir_parent_inode(ntfs_inode *ni); -int ntfs_get_ntfs_dos_name(const char *path, - char *value, size_t size, ntfs_inode *ni); -int ntfs_set_ntfs_dos_name(const char *path, - const char *value, size_t size, int flags, - ntfs_inode *ni); -int ntfs_remove_ntfs_dos_name(const char *path, ntfs_inode *ni); +int ntfs_get_ntfs_dos_name(ntfs_inode *ni, ntfs_inode *dir_ni, + char *value, size_t size); +int ntfs_set_ntfs_dos_name(ntfs_inode *ni, ntfs_inode *dir_ni, + const char *value, size_t size, int flags); +int ntfs_remove_ntfs_dos_name(ntfs_inode *ni, ntfs_inode *dir_ni); #endif /* defined _NTFS_DIR_H */ diff --git a/include/ntfs-3g/efs.h b/include/ntfs-3g/efs.h index bb28e3c7..6eada067 100644 --- a/include/ntfs-3g/efs.h +++ b/include/ntfs-3g/efs.h @@ -21,11 +21,10 @@ #ifndef EFS_H #define EFS_H -int ntfs_get_efs_info(const char *path, - char *value, size_t size, ntfs_inode *ni); -int ntfs_set_efs_info(const char *path, - const char *value, size_t size, int flags, - ntfs_inode *ni); +int ntfs_get_efs_info(ntfs_inode *ni, char *value, size_t size); + +int ntfs_set_efs_info(ntfs_inode *ni, + const char *value, size_t size, int flags); int ntfs_efs_fixup_attribute(ntfs_attr_search_ctx *ctx, ntfs_attr *na); #endif /* EFS_H */ diff --git a/include/ntfs-3g/inode.h b/include/ntfs-3g/inode.h index 9e26f833..f0f62797 100644 --- a/include/ntfs-3g/inode.h +++ b/include/ntfs-3g/inode.h @@ -196,9 +196,9 @@ extern int ntfs_inode_free_space(ntfs_inode *ni, int size); extern int ntfs_inode_badclus_bad(u64 mft_no, ATTR_RECORD *a); -extern int ntfs_inode_get_times(const char *path, char *value, - size_t size, ntfs_inode *ni); -extern int ntfs_inode_set_times(const char *path, const char *value, - size_t size, int flags, ntfs_inode *ni); +extern int ntfs_inode_get_times(ntfs_inode *ni, char *value, size_t size); + +extern int ntfs_inode_set_times(ntfs_inode *ni, const char *value, + size_t size, int flags); #endif /* defined _NTFS_INODE_H */ diff --git a/include/ntfs-3g/reparse.h b/include/ntfs-3g/reparse.h index 730d9fdb..35f4aa45 100644 --- a/include/ntfs-3g/reparse.h +++ b/include/ntfs-3g/reparse.h @@ -28,11 +28,11 @@ char *ntfs_make_symlink(ntfs_inode *ni, const char *mnt_point, int *pattr_size); BOOL ntfs_possible_symlink(ntfs_inode *ni); -int ntfs_get_ntfs_reparse_data(const char *path, - char *value, size_t size, ntfs_inode *ni); -int ntfs_set_ntfs_reparse_data(const char *path, const char *value, - size_t size, int flags, ntfs_inode *ni); -int ntfs_remove_ntfs_reparse_data(const char *path, ntfs_inode *ni); +int ntfs_get_ntfs_reparse_data(ntfs_inode *ni, char *value, size_t size); + +int ntfs_set_ntfs_reparse_data(ntfs_inode *ni, const char *value, + size_t size, int flags); +int ntfs_remove_ntfs_reparse_data(ntfs_inode *ni); int ntfs_delete_reparse_index(ntfs_inode *ni); diff --git a/libntfs-3g/dir.c b/libntfs-3g/dir.c index dde14fce..8a2b5d21 100644 --- a/libntfs-3g/dir.c +++ b/libntfs-3g/dir.c @@ -1899,65 +1899,107 @@ static int get_dos_name(ntfs_inode *ni, u64 dnum, ntfschar *dosname) } +/* + * Get a long name for a file in designated directory + * + * Returns size if found + * 0 if not found + * -1 if there was an error (described by errno) + */ + +static int get_long_name(ntfs_inode *ni, u64 dnum, ntfschar *longname) +{ + size_t outsize = 0; + FILE_NAME_ATTR *fn; + ntfs_attr_search_ctx *ctx; + + /* find the name in the attributes */ + ctx = ntfs_attr_get_search_ctx(ni, NULL); + if (!ctx) + return -1; + + /* first search for WIN32 or DOS+WIN32 names */ + while (!ntfs_attr_lookup(AT_FILE_NAME, AT_UNNAMED, 0, CASE_SENSITIVE, + 0, NULL, 0, ctx)) { + /* We know this will always be resident. */ + fn = (FILE_NAME_ATTR*)((u8*)ctx->attr + + le16_to_cpu(ctx->attr->value_offset)); + + if ((fn->file_name_type & FILE_NAME_WIN32) + && (MREF_LE(fn->parent_directory) == dnum)) { + /* + * Found a WIN32 or WIN32+DOS name for the entry + * copy name + */ + outsize = fn->file_name_length; + memcpy(longname,fn->file_name,outsize*sizeof(ntfschar)); + } + } + /* if not found search for POSIX names */ + if (!outsize) { + ntfs_attr_reinit_search_ctx(ctx); + while (!ntfs_attr_lookup(AT_FILE_NAME, AT_UNNAMED, 0, CASE_SENSITIVE, + 0, NULL, 0, ctx)) { + /* We know this will always be resident. */ + fn = (FILE_NAME_ATTR*)((u8*)ctx->attr + + le16_to_cpu(ctx->attr->value_offset)); + + if ((fn->file_name_type == FILE_NAME_POSIX) + && (MREF_LE(fn->parent_directory) == dnum)) { + /* + * Found a POSIX name for the entry + * copy name + */ + outsize = fn->file_name_length; + memcpy(longname,fn->file_name,outsize*sizeof(ntfschar)); + } + } + } + ntfs_attr_put_search_ctx(ctx); + return (outsize); +} + + /* * Get the ntfs DOS name into an extended attribute */ -int ntfs_get_ntfs_dos_name(const char *path, - char *value, size_t size, ntfs_inode *ni) +int ntfs_get_ntfs_dos_name(ntfs_inode *ni, ntfs_inode *dir_ni, + char *value, size_t size) { int outsize = 0; char *outname = (char*)NULL; - ntfs_inode *dir_ni = NULL; u64 dnum; - char *dirname; - const char *rdirname; - char *p; int doslen; ntfschar dosname[MAX_DOS_NAME_LENGTH]; - /* get the parent directory */ - dirname = strdup(path); - if (dirname) { - p = strrchr(dirname,'/'); - if (p) { - *p++ = 0; - rdirname = (dirname[0] ? dirname : "/"); - dir_ni = ntfs_pathname_to_inode(ni->vol, NULL, rdirname); - dnum = dir_ni->mft_no; - free(dirname); - } - } - if (dir_ni) { - doslen = get_dos_name(ni, dnum, dosname); - if (doslen > 0) { - /* - * Found a DOS name for the entry, make - * uppercase and encode into the buffer - * if there is enough space - */ - ntfs_name_upcase(dosname, doslen, - ni->vol->upcase, ni->vol->upcase_len); - if (ntfs_ucstombs(dosname, doslen, &outname, size) < 0) { - ntfs_log_error("Cannot represent dosname in current locale.\n"); - outsize = -errno; - } else { - outsize = strlen(outname); - if (value && (outsize <= (int)size)) - memcpy(value, outname, outsize); - else - if (size && (outsize > (int)size)) - outsize = -ERANGE; - free(outname); - } - } else { - if (doslen == 0) - errno = ENODATA; + dnum = dir_ni->mft_no; + doslen = get_dos_name(ni, dnum, dosname); + if (doslen > 0) { + /* + * Found a DOS name for the entry, make + * uppercase and encode into the buffer + * if there is enough space + */ + ntfs_name_upcase(dosname, doslen, + ni->vol->upcase, ni->vol->upcase_len); + if (ntfs_ucstombs(dosname, doslen, &outname, size) < 0) { + ntfs_log_error("Cannot represent dosname in current locale.\n"); outsize = -errno; + } else { + outsize = strlen(outname); + if (value && (outsize <= (int)size)) + memcpy(value, outname, outsize); + else + if (size && (outsize > (int)size)) + outsize = -ERANGE; + free(outname); } - ntfs_inode_close(dir_ni); - } else + } else { + if (doslen == 0) + errno = ENODATA; outsize = -errno; + } return (outsize); } @@ -2043,7 +2085,6 @@ static int set_namespace(ntfs_inode *ni, ntfs_inode *dir_ni, */ static int set_dos_name(ntfs_inode *ni, ntfs_inode *dir_ni, - const char *fullpath, ntfschar *shortname, int shortlen, ntfschar *longname, int longlen, ntfschar *deletename, int deletelen, BOOL existed) @@ -2091,19 +2132,22 @@ static int set_dos_name(ntfs_inode *ni, ntfs_inode *dir_ni, longname, longlen, FILE_NAME_WIN32_AND_DOS) >= 0)) res = 0; + ntfs_inode_update_times(ni, NTFS_UPDATE_CTIME); + ntfs_inode_update_times(dir_ni, NTFS_UPDATE_MCTIME); if (ntfs_inode_close_in_dir(ni,dir_ni) && !res) res = -1; if (ntfs_inode_close(dir_ni) && !res) res = -1; } - } else + } else { if (!ntfs_link_i(ni, dir_ni, shortname, shortlen, FILE_NAME_DOS) /* make sure a new link was recorded */ && (le16_to_cpu(ni->mrec->link_count) > linkcount)) { /* delete the existing long name or short name */ - if (!ntfs_delete(vol, fullpath, ni, dir_ni, - deletename, deletelen)) { +// is it ok to not provide the path ? + if (!ntfs_delete(vol, (char*)NULL, ni, dir_ni, + deletename, deletelen)) { /* delete closes the inodes, so have to open again */ dir_ni = ntfs_inode_open(vol, dnum); if (dir_ni) { @@ -2126,6 +2170,7 @@ static int set_dos_name(ntfs_inode *ni, ntfs_inode *dir_ni, ntfs_inode_close_in_dir(ni,dir_ni); ntfs_inode_close(dir_ni); } + } return (res); } @@ -2140,8 +2185,8 @@ static int set_dos_name(ntfs_inode *ni, ntfs_inode *dir_ni, * The inode of the file is always closed */ -int ntfs_set_ntfs_dos_name(const char *path, const char *value, size_t size, - int flags, ntfs_inode *ni) +int ntfs_set_ntfs_dos_name(ntfs_inode *ni, ntfs_inode *dir_ni, + const char *value, size_t size, int flags) { int res = 0; int longlen = 0; @@ -2154,11 +2199,7 @@ int ntfs_set_ntfs_dos_name(const char *path, const char *value, size_t size, u64 dnum; BOOL closed = FALSE; ntfschar *shortname = NULL; - ntfschar *longname = NULL; - ntfs_inode *dir_ni = NULL; - char *dirname = (char*)NULL; - const char *rdirname; - char *p; + ntfschar longname[NTFS_MAX_NAME_LEN]; vol = ni->vol; fnum = ni->mft_no; @@ -2170,28 +2211,17 @@ int ntfs_set_ntfs_dos_name(const char *path, const char *value, size_t size, shortlen = ntfs_mbstoucs(newname, &shortname); /* make sure the short name has valid chars */ if ((shortlen < 0) || ntfs_forbidden_chars(shortname,shortlen)) { - ntfs_inode_close(ni); + ntfs_inode_close_in_dir(ni,dir_ni); + ntfs_inode_close(dir_ni); res = -errno; return res; } - /* get the parent directory */ - dirname = strdup(path); - if (dirname) { - p = strrchr(dirname,'/'); - if (p) { - *p++ = 0; - longlen = ntfs_mbstoucs(p, &longname); - /* make sure the long name had valid chars */ - if (!ntfs_forbidden_chars(longname,longlen)) { - rdirname = (dirname[0] ? dirname : "/"); - dir_ni = ntfs_pathname_to_inode(vol, NULL, rdirname); - } - } - } - if (dir_ni) { - dnum = dir_ni->mft_no; + dnum = dir_ni->mft_no; + longlen = get_long_name(ni, dnum, longname); + if (longlen > 0) { oldlen = get_dos_name(ni, dnum, oldname); - if (oldlen >= 0) { + if ((oldlen >= 0) + && !ntfs_forbidden_chars(longname, longlen)) { if (oldlen > 0) { if (flags & XATTR_CREATE) { res = -1; @@ -2204,7 +2234,6 @@ int ntfs_set_ntfs_dos_name(const char *path, const char *value, size_t size, res = 0; else { res = set_dos_name(ni, dir_ni, - path, shortname, shortlen, longname, longlen, oldname, oldlen, TRUE); @@ -2215,7 +2244,7 @@ int ntfs_set_ntfs_dos_name(const char *path, const char *value, size_t size, res = -1; errno = ENODATA; } else { - res = set_dos_name(ni, dir_ni, path, + res = set_dos_name(ni, dir_ni, shortname, shortlen, longname, longlen, longname, longlen, FALSE); @@ -2224,17 +2253,15 @@ int ntfs_set_ntfs_dos_name(const char *path, const char *value, size_t size, } } else res = -1; - if (!closed) - ntfs_inode_close(dir_ni); } else { res = -1; - errno = EINVAL; + errno = ENOENT; } - free(dirname); - free(longname); free(shortname); - if (!closed) - ntfs_inode_close(ni); + if (!closed) { + ntfs_inode_close_in_dir(ni,dir_ni); + ntfs_inode_close(dir_ni); + } return (res ? -1 : 0); } @@ -2242,7 +2269,7 @@ int ntfs_set_ntfs_dos_name(const char *path, const char *value, size_t size, * Delete the ntfs DOS name */ -int ntfs_remove_ntfs_dos_name(const char *path, ntfs_inode *ni) +int ntfs_remove_ntfs_dos_name(ntfs_inode *ni, ntfs_inode *dir_ni) { int res; int oldnametype; @@ -2252,27 +2279,13 @@ int ntfs_remove_ntfs_dos_name(const char *path, ntfs_inode *ni) ntfs_volume *vol; BOOL deleted = FALSE; ntfschar shortname[MAX_DOS_NAME_LENGTH]; - ntfschar *longname = NULL; - ntfs_inode *dir_ni = NULL; - char *dirname = (char*)NULL; - const char *rdirname; - char *p; + ntfschar longname[NTFS_MAX_NAME_LEN]; res = -1; vol = ni->vol; - /* get the parent directory */ - dirname = strdup(path); - if (dirname) { - p = strrchr(dirname,'/'); - if (p) { - *p++ = 0; - longlen = ntfs_mbstoucs(p, &longname); - rdirname = (dirname[0] ? dirname : "/"); - dir_ni = ntfs_pathname_to_inode(vol, NULL, rdirname); - } - } - if (dir_ni) { - dnum = dir_ni->mft_no; + dnum = dir_ni->mft_no; + longlen = get_long_name(ni, dnum, longname); + if (longlen > 0) { shortlen = get_dos_name(ni, dnum, shortname); if (shortlen >= 0) { /* migrate the long name as Posix */ @@ -2307,8 +2320,8 @@ int ntfs_remove_ntfs_dos_name(const char *path, ntfs_inode *ni) */ errno = EIO; ntfs_log_error("Could not change" - " DOS name of %s to Posix\n", - path); + " DOS name of inode %lld to Posix\n", + (long long)ni->mft_no); } break; default : @@ -2317,13 +2330,14 @@ int ntfs_remove_ntfs_dos_name(const char *path, ntfs_inode *ni) break; } } - if (!deleted) - ntfs_inode_close(dir_ni); + } else { + errno = ENOENT; + res = -1; + } + if (!deleted) { + ntfs_inode_close_in_dir(ni,dir_ni); + ntfs_inode_close(dir_ni); } - if (!deleted) - ntfs_inode_close(ni); - free(longname); - free(dirname); return (res); } diff --git a/libntfs-3g/efs.c b/libntfs-3g/efs.c index 4464a5f9..4155e85e 100644 --- a/libntfs-3g/efs.c +++ b/libntfs-3g/efs.c @@ -71,8 +71,7 @@ static ntfschar logged_utility_stream_name[] = { * Get the ntfs EFS info into an extended attribute */ -int ntfs_get_efs_info(const char *path, - char *value, size_t size, ntfs_inode *ni) +int ntfs_get_efs_info(ntfs_inode *ni, char *value, size_t size) { EFS_ATTR_HEADER *efs_info; s64 attr_size = 0; @@ -100,17 +99,20 @@ int ntfs_get_efs_info(const char *path, } else { if (efs_info) { free(efs_info); - ntfs_log_error("Bad efs_info for file %s\n",path); + ntfs_log_error("Bad efs_info for inode %lld\n", + (long long)ni->mft_no); } else { ntfs_log_error("Could not get efsinfo" - " for file %s\n", path); + " for inode %lld\n", + (long long)ni->mft_no); } errno = EIO; attr_size = 0; } } else { errno = ENODATA; - ntfs_log_trace("File %s is not encrypted\n",path); + ntfs_log_trace("Inode %lld is not encrypted\n", + (long long)ni->mft_no); } } return (attr_size ? (int)attr_size : -errno); @@ -122,9 +124,9 @@ int ntfs_get_efs_info(const char *path, * Returns 0, or -1 if there is a problem */ -int ntfs_set_efs_info(const char *path __attribute__((unused)), - const char *value, size_t size, int flags, - ntfs_inode *ni) +int ntfs_set_efs_info(ntfs_inode *ni, const char *value, size_t size, + int flags) + { int res; int written; @@ -136,7 +138,8 @@ int ntfs_set_efs_info(const char *path __attribute__((unused)), if (ni && value && size) { if (ni->flags & (FILE_ATTR_ENCRYPTED | FILE_ATTR_COMPRESSED)) { if (ni->flags & FILE_ATTR_ENCRYPTED) { - ntfs_log_trace("File %s already encrypted\n",path); + ntfs_log_trace("Inode %lld already encrypted\n", + (long long)ni->mft_no); errno = EEXIST; } else { /* @@ -145,8 +148,8 @@ int ntfs_set_efs_info(const char *path __attribute__((unused)), * restored as compressed. * TODO : decompress first. */ - ntfs_log_error("File %s cannot be encrypted and compressed\n", - path); + ntfs_log_error("Inode %lld cannot be encrypted and compressed\n", + (long long)ni->mft_no); errno = EIO; } return -1; diff --git a/libntfs-3g/inode.c b/libntfs-3g/inode.c index 0de59d55..dc988c45 100644 --- a/libntfs-3g/inode.c +++ b/libntfs-3g/inode.c @@ -1239,8 +1239,7 @@ int ntfs_inode_badclus_bad(u64 mft_no, ATTR_RECORD *attr) * -errno if failed */ -int ntfs_inode_get_times(const char *path __attribute__((unused)), - char *value, size_t size, ntfs_inode *ni) +int ntfs_inode_get_times(ntfs_inode *ni, char *value, size_t size) { ntfs_attr_search_ctx *ctx; STANDARD_INFORMATION *std_info; @@ -1298,9 +1297,8 @@ int ntfs_inode_get_times(const char *path __attribute__((unused)), * -1 if there were an error (described by errno) */ -int ntfs_inode_set_times(const char *path __attribute__((unused)), - const char *value, size_t size, - int flags, ntfs_inode *ni) +int ntfs_inode_set_times(ntfs_inode *ni, const char *value, size_t size, + int flags) { ntfs_attr_search_ctx *ctx; STANDARD_INFORMATION *std_info; diff --git a/libntfs-3g/reparse.c b/libntfs-3g/reparse.c index 7364021d..4633e583 100644 --- a/libntfs-3g/reparse.c +++ b/libntfs-3g/reparse.c @@ -1028,8 +1028,7 @@ int ntfs_delete_reparse_index(ntfs_inode *ni) * and the buffer is updated if it is long enough */ -int ntfs_get_ntfs_reparse_data(const char *path __attribute__((unused)), - char *value, size_t size, ntfs_inode *ni) +int ntfs_get_ntfs_reparse_data(ntfs_inode *ni, char *value, size_t size) { REPARSE_POINT *reparse_attr; s64 attr_size; @@ -1063,9 +1062,8 @@ int ntfs_get_ntfs_reparse_data(const char *path __attribute__((unused)), * Returns 0, or -1 if there is a problem */ -int ntfs_set_ntfs_reparse_data(const char *path __attribute__((unused)), - const char *value, size_t size, int flags, - ntfs_inode *ni) +int ntfs_set_ntfs_reparse_data(ntfs_inode *ni, + const char *value, size_t size, int flags) { int res; u8 dummy; @@ -1134,8 +1132,7 @@ int ntfs_set_ntfs_reparse_data(const char *path __attribute__((unused)), * Returns 0, or -1 if there is a problem */ -int ntfs_remove_ntfs_reparse_data(const char *path __attribute__((unused)), - ntfs_inode *ni) +int ntfs_remove_ntfs_reparse_data(ntfs_inode *ni) { int res; int olderrno; diff --git a/src/ntfs-3g.c b/src/ntfs-3g.c index 8d1015b7..655b3635 100644 --- a/src/ntfs-3g.c +++ b/src/ntfs-3g.c @@ -2653,6 +2653,83 @@ 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_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) { @@ -2676,54 +2753,8 @@ 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)) { - /* - * 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(&security, ni, - value, size); - break; - case XATTR_POSIX_ACC : - case XATTR_POSIX_DEF : - res = ntfs_get_posix_acl(&security, ni, - name, value, size); - break; - 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(path, - value,size,ni); - else - res = -EPERM; - break; - case XATTR_NTFS_REPARSE_DATA : - res = ntfs_get_ntfs_reparse_data(path, - value,size,ni); - break; - case XATTR_NTFS_DOS_NAME: - res = ntfs_get_ntfs_dos_name(path, - value,size,ni); - break; - case XATTR_NTFS_TIMES: - res = ntfs_inode_get_times(path, - value,size,ni); - break; - default : - /* - * make sure applications do not see - * Posix ACL not consistent with mode - */ - errno = EOPNOTSUPP; - res = -errno; - break; - } + res = ntfs_system_getxattr(&security, + path, attr, ni, value, size); } else { res = -errno; } @@ -2744,49 +2775,8 @@ static int ntfs_fuse_getxattr(const char *path, const char *name, if (ni) { /* user mapping not mandatory */ ntfs_fuse_fill_security_context(&security); - /* - * 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(&security, ni, - value, size); - break; - 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(path, - value,size,ni); - else - res = -EPERM; - break; - case XATTR_NTFS_REPARSE_DATA : - res = ntfs_get_ntfs_reparse_data(path, - value,size,ni); - break; - case XATTR_NTFS_DOS_NAME: - res = ntfs_get_ntfs_dos_name(path, - value,size,ni); - break; - case XATTR_NTFS_TIMES: - res = ntfs_inode_get_times(path, - value,size,ni); - break; - default : - /* - * make sure applications do not see - * Posix ACL not consistent with mode - */ - errno = EOPNOTSUPP; - res = -errno; - break; - } + res = ntfs_system_getxattr(&security, + path, attr, ni, value, size); if (ntfs_inode_close(ni)) set_fuse_error(&res); } else @@ -2857,6 +2847,77 @@ 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_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) { @@ -2881,49 +2942,8 @@ 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)) { - switch (attr) { - case XATTR_NTFS_ACL : - res = ntfs_set_ntfs_acl(&security, ni, - value, size, flags); - break; - case XATTR_POSIX_ACC : - case XATTR_POSIX_DEF : - res = ntfs_set_posix_acl(&security, ni, - name, value, size, flags); - break; - 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(path, - value,size,flags,ni); - else - res = -EPERM; - break; - case XATTR_NTFS_REPARSE_DATA : - res = ntfs_set_ntfs_reparse_data(path, - value,size,flags,ni); - break; - case XATTR_NTFS_DOS_NAME: - /* warning : this closes the inode */ - res = ntfs_set_ntfs_dos_name(path, - value,size,flags,ni); - break; - case XATTR_NTFS_TIMES: - res = ntfs_inode_set_times(path, - value,size,flags,ni); - break; - default : - /* - * make sure applications do not see - * Posix ACL not consistent with mode - */ - errno = EOPNOTSUPP; - res = -errno; - break; - } + res = ntfs_system_setxattr(&security, + path, attr, ni, value, size, flags); if (res) res = -errno; } else @@ -2953,45 +2973,10 @@ static int ntfs_fuse_setxattr(const char *path, const char *name, * if defined, only owner is allowed */ if (!ntfs_fuse_fill_security_context(&security) - || ntfs_allowed_as_owner(&security, ni)) { - switch (attr) { - case XATTR_NTFS_ACL : - res = ntfs_set_ntfs_acl(&security, ni, - value, size, flags); - break; - 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(path, - value,size,flags,ni); - else - res = -EPERM; - break; - case XATTR_NTFS_REPARSE_DATA : - res = ntfs_set_ntfs_reparse_data(path, - value,size,flags,ni); - break; - case XATTR_NTFS_DOS_NAME: - /* warning : this closes the inode */ - res = ntfs_set_ntfs_dos_name(path, - value,size,flags,ni); - break; - case XATTR_NTFS_TIMES: - res = ntfs_inode_set_times(path, - value,size,flags,ni); - break; - default : - /* - * make sure applications do not see - * Posix ACL not consistent with mode - */ - errno = EOPNOTSUPP; - res = -errno; - break; - } + || ntfs_allowed_as_owner(&security,ni)) { + res = ntfs_system_setxattr(&security, + path, attr, ni, value, + size, flags); if (res) res = -errno; } else @@ -3111,6 +3096,89 @@ exit: return res; } +static __inline__ int ntfs_system_removexattr(const char *path, + int attr) +{ + int res; + ntfs_inode *dir_ni; + ntfs_inode *ni; + char *dirpath; + char *p; + 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(&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_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; @@ -3118,7 +3186,9 @@ static int ntfs_fuse_removexattr(const char *path, const char *name) int res = 0, lename_len; int attr; int namespace; +#if POSIXACLS struct SECURITY_CONTEXT security; +#endif attr = mapped_xattr_system(name); if (attr != XATTR_UNMAPPED) { @@ -3130,56 +3200,7 @@ static int ntfs_fuse_removexattr(const char *path, const char *name) * point of view, ACLs are not xattr) * Note : updating an ACL does not set ctime */ - 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; - 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, - name)) - res = -errno; - if (ntfs_inode_close(ni)) - set_fuse_error(&res); - } else - res = -errno; - break; - 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(path,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(&security,path,attr,TRUE); - if (ni) { - if (ntfs_remove_ntfs_dos_name(path,ni)) - res = -errno; - } else - res = -errno; - break; - default : - errno = EOPNOTSUPP; - res = -errno; - break; - break; - } + res = ntfs_system_removexattr(path, attr); #else /* * Only hijack NTFS ACL and ATTRIB removal if POSIX ACLS @@ -3189,50 +3210,7 @@ static int ntfs_fuse_removexattr(const char *path, const char *name) if (ntfs_fuse_is_named_data_stream(path)) res = -EINVAL; /* n/a for named data streams. */ else { - 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; - case XATTR_NTFS_REPARSE_DATA : - 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)) - || ntfs_remove_ntfs_reparse_data(path,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(&security,path,attr,TRUE); - if (ni) { - if (ntfs_remove_ntfs_dos_name(path,ni)) - res = -errno; - } else - res = -errno; - break; - default : - /* - * make sure applications do not see - * Posix ACL not consistent with mode - */ - errno = EOPNOTSUPP; - res = -errno; - break; - } + res = ntfs_system_removexattr(path, attr); } #endif return (res);