Developped getting and setting DOS names (short 8+3 names)
parent
3ddbce3ea6
commit
9a4672ca65
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
329
libntfs-3g/dir.c
329
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 <sys/xattr.h>
|
||||
#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
|
||||
|
|
|
@ -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
|
||||
*
|
||||
|
|
|
@ -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<len; i++) {
|
||||
ch = le16_to_cpu(name[i]);
|
||||
if ((ch <= 0x20)
|
||||
|| ((ch < 0x40)
|
||||
&& ((1L << (ch - 0x20)) & mainset))
|
||||
|| (ch == '\\')
|
||||
|| (ch == '|'))
|
||||
forbidden = TRUE;
|
||||
}
|
||||
if (forbidden)
|
||||
errno = EINVAL;
|
||||
return (forbidden);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check whether the same name can be used as a DOS and
|
||||
* a Win32 name
|
||||
*
|
||||
* The names must be the same, or the short name the uppercase
|
||||
* variant of the long name
|
||||
*/
|
||||
|
||||
BOOL ntfs_collapsible_chars(ntfs_volume *vol,
|
||||
const ntfschar *shortname, int shortlen,
|
||||
const ntfschar *longname, int longlen)
|
||||
{
|
||||
BOOL collapsible;
|
||||
unsigned int ch;
|
||||
int i;
|
||||
|
||||
collapsible = shortlen == longlen;
|
||||
if (collapsible)
|
||||
for (i=0; i<shortlen; i++) {
|
||||
ch = le16_to_cpu(longname[i]);
|
||||
if ((ch >= 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.
|
||||
|
|
130
src/ntfs-3g.c
130
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
|
||||
|
|
Loading…
Reference in New Issue