diff --git a/include/ntfs-3g/dir.h b/include/ntfs-3g/dir.h index 68e47b3c..805c4f27 100644 --- a/include/ntfs-3g/dir.h +++ b/include/ntfs-3g/dir.h @@ -104,5 +104,11 @@ typedef int (*ntfs_filldir_t)(void *dirent, const ntfschar *name, extern int ntfs_readdir(ntfs_inode *dir_ni, s64 *pos, void *dirent, ntfs_filldir_t filldir); +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); + #endif /* defined _NTFS_DIR_H */ diff --git a/include/ntfs-3g/unistr.h b/include/ntfs-3g/unistr.h index 189384cd..a6deccdc 100644 --- a/include/ntfs-3g/unistr.h +++ b/include/ntfs-3g/unistr.h @@ -65,6 +65,11 @@ extern ntfschar *ntfs_str2ucs(const char *s, int *len); extern void ntfs_ucsfree(ntfschar *ucs); +extern BOOL ntfs_forbidden_chars(const ntfschar *name, int len); +extern BOOL ntfs_collapsible_chars(ntfs_volume *vol, + const ntfschar *shortname, int shortlen, + const ntfschar *longname, int longlen); + extern int ntfs_set_char_encoding(const char *locale); #endif /* defined _NTFS_UNISTR_H */ diff --git a/libntfs-3g/dir.c b/libntfs-3g/dir.c index 5f5ab6a4..bec4d939 100644 --- a/libntfs-3g/dir.c +++ b/libntfs-3g/dir.c @@ -5,7 +5,7 @@ * Copyright (c) 2004-2005 Richard Russon * Copyright (c) 2004-2008 Szabolcs Szakacsits * Copyright (c) 2005-2007 Yura Pakhuchiy - * Copyright (c) 2008 Jean-Pierre Andre + * Copyright (c) 2008-2009 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 @@ -59,6 +59,10 @@ #include "security.h" #include "reparse.h" +#ifdef HAVE_SETXATTR +#include +#endif + /* * The little endian Unicode strings "$I30", "$SII", "$SDH", "$O" * and "$Q" as global constants. @@ -97,6 +101,8 @@ static int inode_cache_compare(const struct CACHED_GENERIC *cached, * * A partial path is compared in order to invalidate all paths * related to a renamed directory + * inode numbers are also checked, as deleting a long name may + * imply deleting a short name and conversely */ static int inode_cache_inv_compare(const struct CACHED_GENERIC *cached, @@ -106,10 +112,12 @@ static int inode_cache_inv_compare(const struct CACHED_GENERIC *cached, len = strlen(wanted->variable); return (!cached->variable - || strncmp((const char*)cached->variable, + || ((((const struct CACHED_INODE*)wanted)->inum + != MREF(((const struct CACHED_INODE*)cached)->inum)) + && (strncmp((const char*)cached->variable, (const char*)wanted->variable,len) || ((((const char*)cached->variable)[len] != '\0') - && (((const char*)cached->variable)[len] != '/'))); + && (((const char*)cached->variable)[len] != '/'))))); } #endif @@ -1516,6 +1524,7 @@ int ntfs_delete(ntfs_volume *vol, const char *pathname, #if CACHE_INODE_SIZE struct CACHED_INODE item; const char *p; + u64 inum = (u64)-1; int count; #endif @@ -1631,6 +1640,9 @@ search: * case there are no reference to this inode left, so we should free all * non-resident attributes and mark all MFT record as not in use. */ +#if CACHE_INODE_SIZE + inum = ni->mft_no; +#endif if (ni->mrec->link_count) { ntfs_inode_update_times(ni, NTFS_UPDATE_CTIME); goto ok; @@ -1685,19 +1697,22 @@ out: if (ntfs_inode_close(ni) && !err) err = errno; #if CACHE_INODE_SIZE + if (pathname) { /* invalide cache entry, even if there was an error */ - /* Remove leading /'s. */ - p = pathname; - while (*p == PATH_SEP) - p++; - if (p[0] && (p[strlen(p)-1] == PATH_SEP)) - ntfs_log_error("Unnormalized path %s\n",pathname); - item.pathname = p; - count = ntfs_invalidate_cache(vol->xinode_cache, GENERIC(&item), - inode_cache_inv_compare); - if (!count) - ntfs_log_error("Could not delete inode cache entry for %s\n", + /* Remove leading /'s. */ + p = pathname; + while (*p == PATH_SEP) + p++; + if (p[0] && (p[strlen(p)-1] == PATH_SEP)) + ntfs_log_error("Unnormalized path %s\n",pathname); + item.pathname = p; + item.inum = inum; + count = ntfs_invalidate_cache(vol->xinode_cache, GENERIC(&item), + inode_cache_inv_compare); + if (!count) + ntfs_log_error("Could not delete inode cache entry for %s\n", pathname); + } #endif if (err) { errno = err; @@ -1726,7 +1741,8 @@ err_out: * * Return 0 on success or -1 on error with errno set to the error code. */ -int ntfs_link(ntfs_inode *ni, ntfs_inode *dir_ni, ntfschar *name, u8 name_len) +static int ntfs_link_i(ntfs_inode *ni, ntfs_inode *dir_ni, ntfschar *name, + u8 name_len, FILE_NAME_TYPE_FLAGS nametype) { FILE_NAME_ATTR *fn = NULL; int fn_len, err; @@ -1756,7 +1772,7 @@ int ntfs_link(ntfs_inode *ni, ntfs_inode *dir_ni, ntfschar *name, u8 name_len) fn->parent_directory = MK_LE_MREF(dir_ni->mft_no, le16_to_cpu(dir_ni->mrec->sequence_number)); fn->file_name_length = name_len; - fn->file_name_type = FILE_NAME_POSIX; + fn->file_name_type = nametype; fn->file_attributes = ni->flags; if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) fn->file_attributes |= FILE_ATTR_I30_INDEX_PRESENT; @@ -1799,3 +1815,284 @@ err_out: return -1; } +int ntfs_link(ntfs_inode *ni, ntfs_inode *dir_ni, ntfschar *name, u8 name_len) +{ + return (ntfs_link_i(ni, dir_ni, name, name_len, FILE_NAME_POSIX)); +} + +#ifdef HAVE_SETXATTR + +#define MAX_DOS_NAME_LENGTH 12 + +/* + * Get a DOS 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_dos_name(ntfs_inode *ni, u64 dnum, ntfschar *dosname) +{ + 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; + + 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_DOS) + && (MREF_LE(fn->parent_directory) == dnum)) { + /* + * Found a DOS or WIN32+DOS name for the entry + * copy name, after truncation for safety + */ + outsize = fn->file_name_length; +/* TODO : reject if name is too long ? */ + if (outsize > MAX_DOS_NAME_LENGTH) + outsize = MAX_DOS_NAME_LENGTH; + memcpy(dosname,fn->file_name,outsize*sizeof(ntfschar)); + ntfs_name_upcase(dosname, outsize, + ni->vol->upcase, ni->vol->upcase_len); + } + } + 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 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, + * encode it into the buffer if there is + * enough space + */ + 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) + outsize = -errno; + ntfs_inode_close(dir_ni); + } else + outsize = -errno; + return (outsize); +} + +/* + * Set a DOS name to a file and adjust name spaces + * + * This done in three (or four) steps : + * + * - insert the short name (as a DOS name or Posix name if collapsible) + * - delete the old long name or existing short name + * - insert the new long name (as a Win32 or DOS+Win32 name) + * - delete the short name if collapsible + * + * Deleting the old long name will not delete the file + * provided the old name was in the Posix name space, + * because the alternate name has been set before. + * + * Likewise, deleting the existing short name implies + * deleting the long name, but not the file itself + * because the alternate name has been set before. + * + * Note : currently the short name and the long name must be different + */ + +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) +{ + unsigned int linkcount; + ntfs_volume *vol; + BOOL collapsible; + BOOL deleted; + u64 dnum; + u64 fnum; + int res; + + res = -1; + vol = ni->vol; + dnum = dir_ni->mft_no; + fnum = ni->mft_no; + /* save initial link count */ + linkcount = le16_to_cpu(ni->mrec->link_count); + + /* check whether the same name may be used as DOS and WIN32 */ + collapsible = ntfs_collapsible_chars(ni->vol, shortname, shortlen, + longname, longlen); + if (!ntfs_link_i(ni, dir_ni, shortname, shortlen, + (collapsible ? FILE_NAME_POSIX : 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 */ + && !ntfs_delete(vol, fullpath, ni, dir_ni, deletename, deletelen)) { + /* delete closes the inodes, so have to open again */ + dir_ni = ntfs_inode_open(vol, dnum); + deleted = FALSE; + if (dir_ni) { + ni = ntfs_inode_open(vol, fnum); + if (ni) { + if (collapsible) { + if (!ntfs_link_i(ni, dir_ni, longname, + longlen, FILE_NAME_WIN32_AND_DOS)) { + if (!ntfs_delete(vol, (const char*)NULL, ni, + dir_ni, shortname, shortlen)) + res = 0; + deleted = TRUE; + } + } else + if (!ntfs_link_i(ni, dir_ni, longname, + longlen, FILE_NAME_WIN32)) + res = 0; + if (!deleted) + ntfs_inode_close(ni); + } + if (!deleted) + ntfs_inode_close(dir_ni); + } + } + return (res); +} + + +/* + * Set the ntfs DOS name into an extended attribute + * The DOS name will be added as another file name attribute + * using the existing file name information from the original + * name or overwriting the DOS Name if one exists. + */ + +int ntfs_set_ntfs_dos_name(const char *path, const char *value, size_t size, + int flags, ntfs_inode *ni) +{ + int res = 0; + int longlen = 0; + int shortlen = 0; + char newname[MAX_DOS_NAME_LENGTH + 1]; + ntfschar oldname[MAX_DOS_NAME_LENGTH]; + int oldsize; + ntfs_volume *vol; + u64 fnum; + u64 dnum; + ntfschar *shortname = NULL; + ntfschar *longname = NULL; + ntfs_inode *dir_ni = NULL; + char *dirname = (char*)NULL; + const char *rdirname; + char *p; + + vol = ni->vol; + fnum = ni->mft_no; + /* convert the string to the NTFS wide chars */ + if (size > MAX_DOS_NAME_LENGTH) + size = MAX_DOS_NAME_LENGTH; + strncpy(newname, value, size); + newname[size] = 0; + shortlen = ntfs_mbstoucs(newname, &shortname); + /* make sure the short name has valid chars */ + if ((shortlen < 0) || ntfs_forbidden_chars(shortname,shortlen)) { + 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); + dnum = dir_ni->mft_no; + } + } + } + if (dir_ni) { + oldsize = get_dos_name(ni, dnum, oldname); + if (oldsize >= 0) { + if (oldsize > 0) { + if (flags & XATTR_CREATE) { + res = -1; + errno = EEXIST; + } else + res = set_dos_name(ni, dir_ni, path, + shortname, shortlen, + longname, longlen, + oldname, oldsize); + } else { + if (flags & XATTR_REPLACE) { + res = -1; + errno = ENODATA; + } else + res = set_dos_name(ni, dir_ni, path, + shortname, shortlen, + longname, longlen, + longname, longlen); + } + } else + res = -1; + } else { + res = -1; + errno = EINVAL; + } + free(dirname); + free(longname); + free(shortname); + return (res ? -1 : 0); +} + +#endif diff --git a/libntfs-3g/security.c b/libntfs-3g/security.c index 70a3184e..9ae0ce1a 100644 --- a/libntfs-3g/security.c +++ b/libntfs-3g/security.c @@ -2173,6 +2173,110 @@ int ntfs_get_posix_acl(struct SECURITY_CONTEXT *scx, const char *path, return (outsize ? (int)outsize : -errno); } +#else /* POSIXACLS */ + + +/* + * Get permissions to access a file + * Takes into account the relation of user to file (owner, group, ...) + * Do no use as mode of the file + * + * returns -1 if there is a problem + * + * This is only used for checking creation of DOS file names + */ + +static int ntfs_get_perm(struct SECURITY_CONTEXT *scx, + const char *path, ntfs_inode *ni, + mode_t request __attribute__((unused))) +{ + const SECURITY_DESCRIPTOR_RELATIVE *phead; + const struct CACHED_PERMISSIONS *cached; + char *securattr; + const SID *usid; /* owner of file/directory */ + const SID *gsid; /* group of file/directory */ + BOOL isdir; + uid_t uid; + gid_t gid; + int perm; + + if (!scx->mapping[MAPUSERS] || !scx->uid) + perm = 07777; + else { + /* check whether available in cache */ + cached = fetch_cache(scx,ni); + if (cached) { + perm = cached->mode; + uid = cached->uid; + gid = cached->gid; + } else { + perm = 0; /* default to no permission */ + isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) + != const_cpu_to_le16(0); + securattr = getsecurityattr(scx->vol, path, ni); + if (securattr) { + phead = (const SECURITY_DESCRIPTOR_RELATIVE*) + securattr; + gsid = (const SID*)& + securattr[le32_to_cpu(phead->group)]; + gid = ntfs_find_group(scx->mapping[MAPGROUPS],gsid); +#if OWNERFROMACL + usid = ntfs_acl_owner(securattr); + perm = ntfs_build_permissions(securattr, + usid, gsid, isdir); + uid = ntfs_find_user(scx->mapping[MAPUSERS],usid); +#else + usid = (const SID*)& + securattr[le32_to_cpu(phead->owner)]; + perm = ntfs_build_permissions(securattr, + usid, gsid, isdir); + if (!perm && ntfs_same_sid(usid, adminsid)) { + uid = find_tenant(scx, securattr); + if (uid) + perm = 0700; + } else + uid = ntfs_find_user(scx->mapping[MAPUSERS],usid); +#endif + /* + * Create a security id if there were none + * and upgrade option is selected + */ + if (!test_nino_flag(ni, v3_Extensions) + && (perm >= 0) + && (scx->vol->secure_flags + & (1 << SECURITY_ADDSECURIDS))) { + upgrade_secur_desc(scx->vol, path, + securattr, ni); + /* + * fetch owner and group for cacheing + * if there is a securid + */ + } + if (test_nino_flag(ni, v3_Extensions) + && (perm >= 0)) { + enter_cache(scx, ni, uid, + gid, perm); + } + free(securattr); + } else { + perm = -1; + uid = gid = 0; + } + } + if (perm >= 0) { + if (uid == scx->uid) + perm &= 07700; + else + if ((gid == scx->gid) + || groupmember(scx, scx->uid, gid)) + perm &= 07070; + else + perm &= 07007; + } + } + return (perm); +} + #endif /* POSIXACLS */ /* @@ -3154,8 +3258,6 @@ int ntfs_sd_add_everyone(ntfs_inode *ni) return ret; } -#if POSIXACLS - /* * Check whether user can access a file in a specific way * @@ -3164,6 +3266,8 @@ int ntfs_sd_add_everyone(ntfs_inode *ni) * 2 if sticky and accesstype is S_IWRITE + S_IEXEC + S_ISVTX * 0 and sets errno if there is a problem or if access * is not allowed + * + * This is used for Posix ACL and checking creation of DOS file names */ int ntfs_allowed_access(struct SECURITY_CONTEXT *scx, @@ -3175,7 +3279,10 @@ int ntfs_allowed_access(struct SECURITY_CONTEXT *scx, int allow; struct stat stbuf; +#if POSIXACLS + /* shortcut, use only if Posix ACLs in use */ if (scx->vol->secure_flags & (1 << SECURITY_DEFAULT)) return (1); +#endif /* * Always allow for root unless execution is requested. * (was checked by fuse until kernel 2.6.29) @@ -3244,6 +3351,8 @@ int ntfs_allowed_access(struct SECURITY_CONTEXT *scx, * no user mapping defined * * Sets errno if there is a problem or if not allowed + * + * This is used for Posix ACL and checking creation of DOS file names */ BOOL ntfs_allowed_dir_access(struct SECURITY_CONTEXT *scx, @@ -3256,7 +3365,10 @@ BOOL ntfs_allowed_dir_access(struct SECURITY_CONTEXT *scx, ntfs_inode *dir_ni; struct stat stbuf; +#if POSIXACLS + /* shortcut, use only if Posix ACLs in use */ if (scx->vol->secure_flags & (1 << SECURITY_DEFAULT)) return (TRUE); +#endif allow = 0; dirpath = strdup(path); if (dirpath) { @@ -3290,8 +3402,6 @@ BOOL ntfs_allowed_dir_access(struct SECURITY_CONTEXT *scx, return (allow); /* errno is set if not allowed */ } -#endif - /* * Define a new owner/group to a file * diff --git a/libntfs-3g/unistr.c b/libntfs-3g/unistr.c index e78d3e7c..764e297a 100644 --- a/libntfs-3g/unistr.c +++ b/libntfs-3g/unistr.c @@ -1076,6 +1076,68 @@ void ntfs_ucsfree(ntfschar *ucs) free(ucs); } +/* + * Check whether a name contains no chars forbidden + * for DOS or Win32 use + * + * If there is a bad char, errno is set to EINVAL + */ + +BOOL ntfs_forbidden_chars(const ntfschar *name, int len) +{ + BOOL forbidden = FALSE; + int ch; + int i; + u32 mainset = (1L << ('\"' - 0x20)) + | (1L << ('*' - 0x20)) + | (1L << ('/' - 0x20)) + | (1L << (':' - 0x20)) + | (1L << ('<' - 0x20)) + | (1L << ('>' - 0x20)) + | (1L << ('?' - 0x20)); + + for (i=0; i= vol->upcase_len) + || ((shortname[i] != longname[i]) + && (shortname[i] != vol->upcase[ch]))) + collapsible = FALSE; + } + return (collapsible); +} + /* * Define the character encoding to be used. * Use UTF-8 unless specified otherwise. diff --git a/src/ntfs-3g.c b/src/ntfs-3g.c index 10a26257..76ca1dab 100644 --- a/src/ntfs-3g.c +++ b/src/ntfs-3g.c @@ -1995,17 +1995,33 @@ enum { XATTR_UNMAPPED, XATTR_NTFS_ATTRIB, XATTR_NTFS_EFSINFO, XATTR_NTFS_REPARSE_DATA, + XATTR_NTFS_DOS_NAME, XATTR_POSIX_ACC, XATTR_POSIX_DEF } ; -static const char nf_ns_xattr_ntfs[] = "system.ntfs_acl"; +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_dos_name[] = "system.ntfs_dos_name"; static const char nf_ns_xattr_posix_access[] = "system.posix_acl_access"; static const char nf_ns_xattr_posix_default[] = "system.posix_acl_default"; -#if POSIXACLS +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_DOS_NAME, nf_ns_xattr_dos_name }, + { 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 @@ -2016,10 +2032,11 @@ static const char nf_ns_xattr_posix_default[] = "system.posix_acl_default"; */ static ntfs_inode *ntfs_check_access_xattr(struct SECURITY_CONTEXT *security, - const char *path, int attr) + const char *path, int attr, BOOL setting) { ntfs_inode *ni; BOOL foracl; + mode_t acctype; ni = (ntfs_inode*)NULL; if (ntfs_fuse_is_named_data_stream(path)) @@ -2038,8 +2055,15 @@ static ntfs_inode *ntfs_check_access_xattr(struct SECURITY_CONTEXT *security, && foracl) { errno = EOPNOTSUPP; } else { - /* parent directory must be executable */ - if (ntfs_allowed_dir_access(security,path,S_IEXEC)) { + /* + * parent directory must be executable, and + * for setting a DOS name it must be writeable + */ + if (setting && (attr == XATTR_NTFS_DOS_NAME)) + acctype = S_IEXEC | S_IWRITE; + else + acctype = S_IEXEC; + if (ntfs_allowed_dir_access(security,path,acctype)) { ni = ntfs_pathname_to_inode(ctx->vol, NULL, path); } } @@ -2047,8 +2071,6 @@ static ntfs_inode *ntfs_check_access_xattr(struct SECURITY_CONTEXT *security, return (ni); } -#endif - /* * Determine whether an extended attribute is in the system * name space and mapped to internal data @@ -2056,31 +2078,12 @@ static ntfs_inode *ntfs_check_access_xattr(struct SECURITY_CONTEXT *security, static int mapped_xattr_system(const char *name) { - int num; + struct XATTRNAME *p; - - if (!strcmp(name,nf_ns_xattr_ntfs)) - num = XATTR_NTFS_ACL; - else - if (!strcmp(name,nf_ns_xattr_attrib)) - num = XATTR_NTFS_ATTRIB; - else - if (!strcmp(name,nf_ns_xattr_reparse)) - num = XATTR_NTFS_REPARSE_DATA; - else - if (!strcmp(name,nf_ns_xattr_posix_access)) - num = XATTR_POSIX_ACC; - else - if (!strcmp(name,nf_ns_xattr_posix_default)) - num = XATTR_POSIX_DEF; - else - if (ctx->efs_raw - && !strcmp(name, - nf_ns_xattr_efsinfo)) - num = XATTR_NTFS_EFSINFO; - else - num = XATTR_UNMAPPED; - return (num); + p = nf_ns_xattr_names; + while (p->name && strcmp(p->name,name)) + p++; + return (p->xattr); } /* @@ -2362,11 +2365,11 @@ static int ntfs_fuse_getxattr(const char *path, const char *name, if (attr != XATTR_UNMAPPED) { #if POSIXACLS /* - * hijack Posix/NTFS ACL retrieval, whatever mode - * was selected for xattr (from the user's point - * of view, ACLs are not xattr) + * hijack internal data and ACL retrieval, whatever + * mode was selected for xattr (from the user's + * point of view, ACLs are not xattr) */ - ni = ntfs_check_access_xattr(&security,path,attr); + ni = ntfs_check_access_xattr(&security,path,attr,FALSE); if (ni) { if (ntfs_allowed_access(&security,path,ni,S_IREAD)) { /* @@ -2397,6 +2400,10 @@ static int ntfs_fuse_getxattr(const char *path, const char *name, 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; default : /* not possible */ break; } @@ -2443,6 +2450,10 @@ static int ntfs_fuse_getxattr(const char *path, const char *name, 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; default : /* * make sure applications do not see @@ -2537,12 +2548,12 @@ static int ntfs_fuse_setxattr(const char *path, const char *name, if (attr != XATTR_UNMAPPED) { #if POSIXACLS /* - * hijack Posix/NTFS ACL retrieval, whatever mode - * was selected for xattr (from the user's point - * of view, ACLs are not xattr) + * hijack internal data and ACL setting, 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 */ - ni = ntfs_check_access_xattr(&security,path,attr); + ni = ntfs_check_access_xattr(&security,path,attr,TRUE); if (ni) { if (ntfs_allowed_as_owner(&security,path,ni)) { switch (attr) { @@ -2567,6 +2578,11 @@ static int ntfs_fuse_setxattr(const char *path, const char *name, 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; default : /* not possible */ break; } @@ -2574,7 +2590,8 @@ static int ntfs_fuse_setxattr(const char *path, const char *name, res = -errno; } else res = -errno; - if (ntfs_inode_close(ni)) + if ((attr != XATTR_NTFS_DOS_NAME) + && ntfs_inode_close(ni)) set_fuse_error(&res); } else res = -errno; @@ -2587,7 +2604,11 @@ static int ntfs_fuse_setxattr(const char *path, const char *name, if (ntfs_fuse_is_named_data_stream(path)) res = -EINVAL; /* n/a for named data streams. */ else { - ni = ntfs_pathname_to_inode(ctx->vol, NULL, path); + /* 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 + ni = ntfs_pathname_to_inode(ctx->vol, NULL, path); if (ni) { /* * user mapping is not mandatory @@ -2612,6 +2633,11 @@ static int ntfs_fuse_setxattr(const char *path, const char *name, 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; default : /* * make sure applications do not see @@ -2625,7 +2651,8 @@ static int ntfs_fuse_setxattr(const char *path, const char *name, res = -errno; } else res = -errno; - if (ntfs_inode_close(ni)) + if ((attr != XATTR_NTFS_DOS_NAME) + && ntfs_inode_close(ni)) set_fuse_error(&res); } else res = -errno; @@ -2752,9 +2779,9 @@ static int ntfs_fuse_removexattr(const char *path, const char *name) #if POSIXACLS /* - * hijack Posix/NTFS ACL retrieval, whatever mode - * was selected for xattr (from the user's point - * of view, ACLs are not xattr) + * 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 = 0; @@ -2769,7 +2796,7 @@ static int ntfs_fuse_removexattr(const char *path, const char *name) break; case XATTR_POSIX_ACC : case XATTR_POSIX_DEF : - ni = ntfs_check_access_xattr(&security,path,attr); + ni = ntfs_check_access_xattr(&security,path,attr,TRUE); if (ni) { if (!ntfs_allowed_as_owner(&security,path,ni) || ntfs_remove_posix_acl(&security,path, @@ -2781,7 +2808,7 @@ static int ntfs_fuse_removexattr(const char *path, const char *name) res = -errno; break; case XATTR_NTFS_REPARSE_DATA : - ni = ntfs_check_access_xattr(&security,path,attr); + ni = ntfs_check_access_xattr(&security,path,attr,TRUE); if (ni) { if (!ntfs_allowed_as_owner(&security,path,ni) || ntfs_remove_ntfs_reparse_data(path,ni)) @@ -2791,7 +2818,11 @@ static int ntfs_fuse_removexattr(const char *path, const char *name) } else res = -errno; break; - default : /* not possible */ + case XATTR_NTFS_DOS_NAME: + default : + errno = EOPNOTSUPP; + res = -errno; + break; break; } #else @@ -2828,7 +2859,8 @@ static int ntfs_fuse_removexattr(const char *path, const char *name) } else res = -errno; break; - default : /* not possible */ + case XATTR_NTFS_DOS_NAME: + default : /* * make sure applications do not see * Posix ACL not consistent with mode