Compare commits
30 Commits
edge
...
PERMISSION
Author | SHA1 | Date |
---|---|---|
|
0e875d3039 | |
|
860cddd4db | |
|
e9e3b18711 | |
|
3c30a0e798 | |
|
a165aca342 | |
|
097a681932 | |
|
54e49e77f1 | |
|
29190c9394 | |
|
285668105c | |
|
6c71d84ef8 | |
|
eeabab767f | |
|
3ae68884f7 | |
|
453a8aa501 | |
|
1df8ddc199 | |
|
1192e02fef | |
|
aabda06ffd | |
|
e7daa6c72f | |
|
9efb8b60a4 | |
|
6ebb79f251 | |
|
13641ad4d6 | |
|
53be5fa9b2 | |
|
fc20bbb5b8 | |
|
f5d0ab51c6 | |
|
2e7f889a72 | |
|
4f03663c55 | |
|
c7f958c8ed | |
|
df8d045340 | |
|
17c9f839d5 | |
|
58be44ebc5 | |
|
19bfa135e7 |
24
README
24
README
|
@ -38,14 +38,15 @@ the FUSE kernel module. Then unpack the source tarball and type:
|
|||
make
|
||||
make install # or 'sudo make install' if you aren't root.
|
||||
|
||||
Please note that NTFS-3G doesn't require the FUSE user space package.
|
||||
Please note that NTFS-3G doesn't require the FUSE user space package any
|
||||
more.
|
||||
|
||||
Non-Linux: Please see
|
||||
|
||||
http://www.tuxera.com/community/ntfs-3g-download/
|
||||
|
||||
for OS specific installation and source packages.
|
||||
|
||||
for known OS specific installation and source packages, but generally
|
||||
the same procedures apply.
|
||||
|
||||
USAGE
|
||||
=====
|
||||
|
@ -66,3 +67,20 @@ line at the END(!) of the /etc/fstab file:
|
|||
|
||||
/dev/sda1 /mnt/windows ntfs-3g defaults 0 0
|
||||
|
||||
|
||||
TESTING WITHOUT INSTALLING
|
||||
=========================
|
||||
|
||||
Newer versions of ntfs-3g can be tested without installing anything and
|
||||
without disturbing an existing installation. Just configure and make as
|
||||
shown previously. This will create the scripts ntfs-3g and lowntfs-3g
|
||||
in the src directory, which you may activate for testing :
|
||||
|
||||
./configure
|
||||
make
|
||||
|
||||
then, as root :
|
||||
src/ntfs-3g [-o mount-options] /dev/sda1 /mnt/windows
|
||||
|
||||
And, to end the test, unmount the usual way :
|
||||
umount /dev/sda1
|
||||
|
|
10
configure.ac
10
configure.ac
|
@ -23,7 +23,7 @@
|
|||
|
||||
# Autoconf
|
||||
AC_PREREQ(2.59)
|
||||
AC_INIT([ntfs-3g],[2010.10.2],[ntfs-3g-devel@lists.sf.net])
|
||||
AC_INIT([ntfs-3g],[2011.1.15],[ntfs-3g-devel@lists.sf.net])
|
||||
LIBNTFS_3G_VERSION="80"
|
||||
AC_CONFIG_SRCDIR([src/ntfs-3g.c])
|
||||
|
||||
|
@ -261,10 +261,10 @@ AC_HEADER_STDC
|
|||
AC_CHECK_HEADERS([ctype.h fcntl.h libgen.h libintl.h limits.h locale.h \
|
||||
mntent.h stddef.h stdint.h stdlib.h stdio.h stdarg.h string.h \
|
||||
strings.h errno.h time.h unistd.h utime.h wchar.h getopt.h features.h \
|
||||
endian.h byteswap.h sys/byteorder.h sys/endian.h sys/param.h \
|
||||
sys/ioctl.h sys/mkdev.h sys/mount.h sys/stat.h sys/types.h sys/vfs.h \
|
||||
sys/statvfs.h sys/sysmacros.h linux/major.h linux/fd.h linux/hdreg.h \
|
||||
machine/endian.h windows.h syslog.h])
|
||||
endian.h byteswap.h sys/byteorder.h sys/disk.h sys/endian.h \
|
||||
sys/param.h sys/ioctl.h sys/mkdev.h sys/mount.h sys/stat.h sys/types.h \
|
||||
sys/vfs.h sys/statvfs.h sys/sysmacros.h linux/major.h linux/fd.h \
|
||||
linux/hdreg.h machine/endian.h windows.h syslog.h])
|
||||
|
||||
# Checks for typedefs, structures, and compiler characteristics.
|
||||
AC_HEADER_STDBOOL
|
||||
|
|
|
@ -58,6 +58,12 @@ typedef enum {
|
|||
LCN_EIO = -5,
|
||||
} ntfs_lcn_special_values;
|
||||
|
||||
typedef enum { /* ways of processing holes when expanding */
|
||||
HOLES_NO,
|
||||
HOLES_OK,
|
||||
HOLES_DELAY
|
||||
} hole_type;
|
||||
|
||||
/**
|
||||
* struct ntfs_attr_search_ctx - search context used in attribute search functions
|
||||
* @mrec: buffer containing mft record to search
|
||||
|
@ -203,7 +209,6 @@ typedef enum {
|
|||
NA_BeingNonResident, /* 1: Attribute is being made not resident. */
|
||||
NA_FullyMapped, /* 1: Attribute has been fully mapped */
|
||||
NA_DataAppending, /* 1: Attribute is being appended to */
|
||||
NA_DelaySparsing, /* 1: Delay checking attribute being sparse */
|
||||
NA_ComprClosing, /* 1: Compressed attribute is being closed */
|
||||
} ntfs_attr_state_bits;
|
||||
|
||||
|
@ -231,10 +236,6 @@ typedef enum {
|
|||
#define NAttrSetDataAppending(na) set_nattr_flag(na, DataAppending)
|
||||
#define NAttrClearDataAppending(na) clear_nattr_flag(na, DataAppending)
|
||||
|
||||
#define NAttrDelaySparsing(na) test_nattr_flag(na, DelaySparsing)
|
||||
#define NAttrSetDelaySparsing(na) set_nattr_flag(na, DelaySparsing)
|
||||
#define NAttrClearDelaySparsing(na) clear_nattr_flag(na, DelaySparsing)
|
||||
|
||||
#define NAttrComprClosing(na) test_nattr_flag(na, ComprClosing)
|
||||
#define NAttrSetComprClosing(na) set_nattr_flag(na, ComprClosing)
|
||||
#define NAttrClearComprClosing(na) clear_nattr_flag(na, ComprClosing)
|
||||
|
@ -343,6 +344,7 @@ extern int ntfs_attr_record_move_away(ntfs_attr_search_ctx *ctx, int extra);
|
|||
extern int ntfs_attr_update_mapping_pairs(ntfs_attr *na, VCN from_vcn);
|
||||
|
||||
extern int ntfs_attr_truncate(ntfs_attr *na, const s64 newsize);
|
||||
extern int ntfs_attr_truncate_solid(ntfs_attr *na, const s64 newsize);
|
||||
|
||||
/**
|
||||
* get_attribute_value_length - return the length of the value of an attribute
|
||||
|
|
|
@ -311,6 +311,7 @@ typedef enum {
|
|||
#define MFT_REF_MASK_LE const_cpu_to_le64(MFT_REF_MASK_CPU)
|
||||
|
||||
typedef u64 MFT_REF;
|
||||
typedef le64 leMFT_REF; /* a little-endian MFT_MREF */
|
||||
|
||||
#define MK_MREF(m, s) ((MFT_REF)(((MFT_REF)(s) << 48) | \
|
||||
((MFT_REF)(m) & MFT_REF_MASK_CPU)))
|
||||
|
|
|
@ -137,6 +137,7 @@ struct PERMISSIONS_CACHE {
|
|||
enum {
|
||||
SECURITY_DEFAULT, /* rely on fuse for permissions checking */
|
||||
SECURITY_RAW, /* force same ownership/permissions on files */
|
||||
SECURITY_ACL, /* enable Posix ACLs (when compiled in) */
|
||||
SECURITY_ADDSECURIDS, /* upgrade old security descriptors */
|
||||
SECURITY_STATICGRPS, /* use static groups for access control */
|
||||
SECURITY_WANTED /* a security related option was present */
|
||||
|
@ -349,7 +350,7 @@ INDEX_ENTRY *ntfs_read_sii(struct SECURITY_API *scapi,
|
|||
INDEX_ENTRY *ntfs_read_sdh(struct SECURITY_API *scapi,
|
||||
INDEX_ENTRY *entry);
|
||||
struct SECURITY_API *ntfs_initialize_file_security(const char *device,
|
||||
int flags);
|
||||
unsigned long flags);
|
||||
BOOL ntfs_leave_file_security(struct SECURITY_API *scx);
|
||||
|
||||
int ntfs_get_usid(struct SECURITY_API *scapi, uid_t uid, char *buf);
|
||||
|
|
|
@ -61,6 +61,7 @@ extern char *ntfs_uppercase_mbs(const char *low,
|
|||
const ntfschar *upcase, u32 upcase_len);
|
||||
|
||||
extern void ntfs_upcase_table_build(ntfschar *uc, u32 uc_len);
|
||||
extern u32 ntfs_upcase_build_default(ntfschar **upcase);
|
||||
extern ntfschar *ntfs_locase_table_build(const ntfschar *uc, u32 uc_cnt);
|
||||
|
||||
extern ntfschar *ntfs_str2ucs(const char *s, int *len);
|
||||
|
|
|
@ -58,6 +58,7 @@
|
|||
#endif
|
||||
|
||||
#define MS_IGNORE_HIBERFILE 0x20000000
|
||||
#define MS_FORENSIC 0x04000000 /* No modification during mount */
|
||||
|
||||
/* Forward declaration */
|
||||
typedef struct _ntfs_volume ntfs_volume;
|
||||
|
|
|
@ -59,8 +59,6 @@ void ntfs_xattr_free_mapping(struct XATTRMAPPING*);
|
|||
|
||||
enum SYSTEMXATTRS ntfs_xattr_system_type(const char *name,
|
||||
ntfs_volume *vol);
|
||||
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,
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* Copyright (c) 2002-2005 Richard Russon
|
||||
* Copyright (c) 2002-2008 Szabolcs Szakacsits
|
||||
* Copyright (c) 2004-2007 Yura Pakhuchiy
|
||||
* Copyright (c) 2007-2010 Jean-Pierre Andre
|
||||
* Copyright (c) 2007-2011 Jean-Pierre Andre
|
||||
* Copyright (c) 2010 Erik Larsson
|
||||
*
|
||||
* This program/include file is free software; you can redistribute it and/or
|
||||
|
@ -603,6 +603,7 @@ static int ntfs_attr_map_partial_runlist(ntfs_attr *na, VCN vcn)
|
|||
VCN last_vcn;
|
||||
VCN highest_vcn;
|
||||
VCN needed;
|
||||
VCN existing_vcn;
|
||||
runlist_element *rl;
|
||||
ATTR_RECORD *a;
|
||||
BOOL startseen;
|
||||
|
@ -612,6 +613,8 @@ static int ntfs_attr_map_partial_runlist(ntfs_attr *na, VCN vcn)
|
|||
if (lcn >= 0 || lcn == LCN_HOLE || lcn == LCN_ENOENT)
|
||||
return 0;
|
||||
|
||||
existing_vcn = (na->rl ? na->rl->vcn : -1);
|
||||
|
||||
ctx = ntfs_attr_get_search_ctx(na->ni, NULL);
|
||||
if (!ctx)
|
||||
return -1;
|
||||
|
@ -643,6 +646,11 @@ static int ntfs_attr_map_partial_runlist(ntfs_attr *na, VCN vcn)
|
|||
needed = highest_vcn + 1;
|
||||
if (!a->lowest_vcn)
|
||||
startseen = TRUE;
|
||||
/* reaching a previously allocated part ? */
|
||||
if ((existing_vcn >= 0)
|
||||
&& (needed >= existing_vcn)) {
|
||||
needed = last_vcn;
|
||||
}
|
||||
}
|
||||
} else
|
||||
rl = (runlist_element*)NULL;
|
||||
|
@ -1182,12 +1190,27 @@ static int ntfs_attr_fill_zero(ntfs_attr *na, s64 pos, s64 count)
|
|||
rli++;
|
||||
}
|
||||
size = min(end - pos, NTFS_BUF_SIZE);
|
||||
written = ntfs_rl_pwrite(vol, rli, ofsi, pos, size, buf);
|
||||
if (written <= 0) {
|
||||
ntfs_log_perror("Failed to zero space");
|
||||
goto err_free;
|
||||
/*
|
||||
* If the zeroed block is fully within a hole,
|
||||
* we need not write anything, so advance as far
|
||||
* as possible within the hole.
|
||||
*/
|
||||
if ((rli->lcn == (LCN)LCN_HOLE)
|
||||
&& (ofsi <= pos)
|
||||
&& (ofsi + (rli->length << vol->cluster_size_bits)
|
||||
>= (pos + size))) {
|
||||
size = min(end - pos, ofsi - pos
|
||||
+ (rli->length << vol->cluster_size_bits));
|
||||
pos += size;
|
||||
} else {
|
||||
written = ntfs_rl_pwrite(vol, rli, ofsi, pos,
|
||||
size, buf);
|
||||
if (written <= 0) {
|
||||
ntfs_log_perror("Failed to zero space");
|
||||
goto err_free;
|
||||
}
|
||||
pos += written;
|
||||
}
|
||||
pos += written;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
@ -1711,6 +1734,9 @@ static int borrow_from_hole(ntfs_attr *na, runlist_element **prl,
|
|||
return (compressed_part);
|
||||
}
|
||||
|
||||
static int ntfs_attr_truncate_i(ntfs_attr *na, const s64 newsize,
|
||||
hole_type holes);
|
||||
|
||||
/**
|
||||
* ntfs_attr_pwrite - positioned write to an ntfs attribute
|
||||
* @na: ntfs attribute to write to
|
||||
|
@ -1815,20 +1841,20 @@ s64 ntfs_attr_pwrite(ntfs_attr *na, const s64 pos, s64 count, const void *b)
|
|||
* attribute to be made temporarily sparse, which
|
||||
* implies reformating the inode and reorganizing the
|
||||
* full runlist. To avoid unnecessary reorganization,
|
||||
* we delay sparse testing until the data is filled in.
|
||||
*
|
||||
* Note : should add a specific argument to truncate()
|
||||
* instead of the hackish test of a flag...
|
||||
* we avoid sparse testing until the data is filled in.
|
||||
*/
|
||||
if (NAttrDataAppending(na))
|
||||
NAttrSetDelaySparsing(na);
|
||||
#endif
|
||||
if (ntfs_attr_truncate(na, pos + count)) {
|
||||
NAttrClearDelaySparsing(na);
|
||||
if (ntfs_attr_truncate_i(na, pos + count,
|
||||
(NAttrDataAppending(na) ?
|
||||
HOLES_DELAY : HOLES_OK))) {
|
||||
ntfs_log_perror("Failed to enlarge attribute");
|
||||
goto errno_set;
|
||||
}
|
||||
NAttrClearDelaySparsing(na);
|
||||
#else
|
||||
if (ntfs_attr_truncate(na, pos + count)) {
|
||||
ntfs_log_perror("Failed to enlarge attribute");
|
||||
goto errno_set;
|
||||
}
|
||||
#endif
|
||||
/* resizing may change the compression mode */
|
||||
compressed = (na->data_flags & ATTR_COMPRESSION_MASK)
|
||||
!= const_cpu_to_le16(0);
|
||||
|
@ -5011,6 +5037,15 @@ static int ntfs_resident_attr_resize_i(ntfs_attr *na, const s64 newsize,
|
|||
ntfs_attr_close(tna);
|
||||
continue;
|
||||
}
|
||||
if ((tna->type == AT_DATA) && !tna->name_len) {
|
||||
/*
|
||||
* If we had to make the unnamed data attribute
|
||||
* non-resident, propagate its new allocated size
|
||||
* to all name attributes and directory indexes
|
||||
*/
|
||||
tna->ni->allocated_size = tna->allocated_size;
|
||||
NInoFileNameSetDirty(tna->ni);
|
||||
}
|
||||
if (((tna->data_flags & ATTR_COMPRESSION_MASK)
|
||||
== ATTR_IS_COMPRESSED)
|
||||
&& ntfs_attr_pclose(tna)) {
|
||||
|
@ -5339,7 +5374,7 @@ static int ntfs_attr_make_resident(ntfs_attr *na, ntfs_attr_search_ctx *ctx)
|
|||
* update allocated and compressed size.
|
||||
*/
|
||||
static int ntfs_attr_update_meta(ATTR_RECORD *a, ntfs_attr *na, MFT_RECORD *m,
|
||||
ntfs_attr_search_ctx *ctx)
|
||||
hole_type holes, ntfs_attr_search_ctx *ctx)
|
||||
{
|
||||
int sparse, ret = 0;
|
||||
|
||||
|
@ -5352,7 +5387,7 @@ static int ntfs_attr_update_meta(ATTR_RECORD *a, ntfs_attr *na, MFT_RECORD *m,
|
|||
a->allocated_size = cpu_to_sle64(na->allocated_size);
|
||||
|
||||
/* Update sparse bit, unless this is an intermediate state */
|
||||
if (NAttrDelaySparsing(na))
|
||||
if (holes == HOLES_DELAY)
|
||||
sparse = (a->flags & ATTR_IS_SPARSE) != const_cpu_to_le16(0);
|
||||
else {
|
||||
sparse = ntfs_rl_sparse(na->rl);
|
||||
|
@ -5363,7 +5398,7 @@ static int ntfs_attr_update_meta(ATTR_RECORD *a, ntfs_attr *na, MFT_RECORD *m,
|
|||
}
|
||||
|
||||
/* Check whether attribute becomes sparse, unless check is delayed. */
|
||||
if (!NAttrDelaySparsing(na)
|
||||
if ((holes != HOLES_DELAY)
|
||||
&& sparse
|
||||
&& !(a->flags & (ATTR_IS_SPARSE | ATTR_IS_COMPRESSED))) {
|
||||
/*
|
||||
|
@ -5465,7 +5500,8 @@ error: ret = -3; goto out;
|
|||
/**
|
||||
* ntfs_attr_update_mapping_pairs_i - see ntfs_attr_update_mapping_pairs
|
||||
*/
|
||||
static int ntfs_attr_update_mapping_pairs_i(ntfs_attr *na, VCN from_vcn)
|
||||
static int ntfs_attr_update_mapping_pairs_i(ntfs_attr *na, VCN from_vcn,
|
||||
hole_type holes)
|
||||
{
|
||||
ntfs_attr_search_ctx *ctx;
|
||||
ntfs_inode *ni, *base_ni;
|
||||
|
@ -5501,7 +5537,7 @@ retry:
|
|||
* Same if the file was sparse and is not any more.
|
||||
* Note : not needed if the full runlist is to be processed
|
||||
*/
|
||||
if (!NAttrDelaySparsing(na)
|
||||
if ((holes != HOLES_DELAY)
|
||||
&& (!NAttrFullyMapped(na) || from_vcn)
|
||||
&& !(na->data_flags & ATTR_IS_COMPRESSED)) {
|
||||
BOOL changed;
|
||||
|
@ -5607,7 +5643,7 @@ retry:
|
|||
continue;
|
||||
}
|
||||
|
||||
switch (ntfs_attr_update_meta(a, na, m, ctx)) {
|
||||
switch (ntfs_attr_update_meta(a, na, m, holes, ctx)) {
|
||||
case -1: return -1;
|
||||
case -2: goto retry;
|
||||
case -3: goto put_err_out;
|
||||
|
@ -5742,34 +5778,6 @@ retry:
|
|||
goto put_err_out;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* If the base extent was skipped in the above process,
|
||||
* we still may have to update the sizes.
|
||||
*/
|
||||
if (!first_updated) {
|
||||
le16 spcomp;
|
||||
|
||||
ntfs_attr_reinit_search_ctx(ctx);
|
||||
if (!ntfs_attr_lookup(na->type, na->name, na->name_len,
|
||||
CASE_SENSITIVE, 0, NULL, 0, ctx)) {
|
||||
a = ctx->attr;
|
||||
a->allocated_size = cpu_to_sle64(na->allocated_size);
|
||||
spcomp = na->data_flags
|
||||
& (ATTR_IS_COMPRESSED | ATTR_IS_SPARSE);
|
||||
if (spcomp)
|
||||
a->compressed_size = cpu_to_sle64(na->compressed_size);
|
||||
if ((na->type == AT_DATA) && (na->name == AT_UNNAMED)) {
|
||||
na->ni->allocated_size
|
||||
= (spcomp
|
||||
? na->compressed_size
|
||||
: na->allocated_size);
|
||||
NInoFileNameSetDirty(na->ni);
|
||||
}
|
||||
} else {
|
||||
ntfs_log_error("Failed to update sizes in base extent\n");
|
||||
goto put_err_out;
|
||||
}
|
||||
}
|
||||
|
||||
/* Deallocate not used attribute extents and return with success. */
|
||||
if (finished_build) {
|
||||
|
@ -5903,7 +5911,7 @@ int ntfs_attr_update_mapping_pairs(ntfs_attr *na, VCN from_vcn)
|
|||
int ret;
|
||||
|
||||
ntfs_log_enter("Entering\n");
|
||||
ret = ntfs_attr_update_mapping_pairs_i(na, from_vcn);
|
||||
ret = ntfs_attr_update_mapping_pairs_i(na, from_vcn, HOLES_OK);
|
||||
ntfs_log_leave("\n");
|
||||
return ret;
|
||||
}
|
||||
|
@ -6073,7 +6081,8 @@ put_err_out:
|
|||
* ERANGE - @newsize is not valid for the attribute type of @na.
|
||||
* ENOSPC - There is no enough space in base mft to resize $ATTRIBUTE_LIST.
|
||||
*/
|
||||
static int ntfs_non_resident_attr_expand_i(ntfs_attr *na, const s64 newsize)
|
||||
static int ntfs_non_resident_attr_expand_i(ntfs_attr *na, const s64 newsize,
|
||||
hole_type holes)
|
||||
{
|
||||
LCN lcn_seek_from;
|
||||
VCN first_free_vcn;
|
||||
|
@ -6137,7 +6146,8 @@ static int ntfs_non_resident_attr_expand_i(ntfs_attr *na, const s64 newsize)
|
|||
* If we extend $DATA attribute on NTFS 3+ volume, we can add
|
||||
* sparse runs instead of real allocation of clusters.
|
||||
*/
|
||||
if (na->type == AT_DATA && vol->major_ver >= 3) {
|
||||
if ((na->type == AT_DATA) && (vol->major_ver >= 3)
|
||||
&& (holes != HOLES_NO)) {
|
||||
rl = ntfs_malloc(0x1000);
|
||||
if (!rl)
|
||||
return -1;
|
||||
|
@ -6208,7 +6218,7 @@ static int ntfs_non_resident_attr_expand_i(ntfs_attr *na, const s64 newsize)
|
|||
na->allocated_size = first_free_vcn << vol->cluster_size_bits;
|
||||
/* Write mapping pairs for new runlist. */
|
||||
#if PARTIAL_RUNLIST_UPDATING
|
||||
if (ntfs_attr_update_mapping_pairs(na, start_update)) {
|
||||
if (ntfs_attr_update_mapping_pairs_i(na, start_update, holes)) {
|
||||
#else
|
||||
if (ntfs_attr_update_mapping_pairs(na, 0)) {
|
||||
#endif
|
||||
|
@ -6297,12 +6307,13 @@ put_err_out:
|
|||
}
|
||||
|
||||
|
||||
static int ntfs_non_resident_attr_expand(ntfs_attr *na, const s64 newsize)
|
||||
static int ntfs_non_resident_attr_expand(ntfs_attr *na, const s64 newsize,
|
||||
hole_type holes)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ntfs_log_enter("Entering\n");
|
||||
ret = ntfs_non_resident_attr_expand_i(na, newsize);
|
||||
ret = ntfs_non_resident_attr_expand_i(na, newsize, holes);
|
||||
ntfs_log_leave("\n");
|
||||
return ret;
|
||||
}
|
||||
|
@ -6311,6 +6322,7 @@ static int ntfs_non_resident_attr_expand(ntfs_attr *na, const s64 newsize)
|
|||
* ntfs_attr_truncate - resize an ntfs attribute
|
||||
* @na: open ntfs attribute to resize
|
||||
* @newsize: new size (in bytes) to which to resize the attribute
|
||||
* @holes: how to create a hole if expanding
|
||||
*
|
||||
* Change the size of an open ntfs attribute @na to @newsize bytes. If the
|
||||
* attribute is made bigger and the attribute is resident the newly
|
||||
|
@ -6327,7 +6339,8 @@ static int ntfs_non_resident_attr_expand(ntfs_attr *na, const s64 newsize)
|
|||
* EOPNOTSUPP - The desired resize is not implemented yet.
|
||||
* EACCES - Encrypted attribute.
|
||||
*/
|
||||
int ntfs_attr_truncate(ntfs_attr *na, const s64 newsize)
|
||||
static int ntfs_attr_truncate_i(ntfs_attr *na, const s64 newsize,
|
||||
hole_type holes)
|
||||
{
|
||||
int ret = STATUS_ERROR;
|
||||
s64 fullsize;
|
||||
|
@ -6392,7 +6405,8 @@ int ntfs_attr_truncate(ntfs_attr *na, const s64 newsize)
|
|||
else
|
||||
fullsize = newsize;
|
||||
if (fullsize > na->data_size)
|
||||
ret = ntfs_non_resident_attr_expand(na, fullsize);
|
||||
ret = ntfs_non_resident_attr_expand(na, fullsize,
|
||||
holes);
|
||||
else
|
||||
ret = ntfs_non_resident_attr_shrink(na, fullsize);
|
||||
} else
|
||||
|
@ -6401,7 +6415,25 @@ out:
|
|||
ntfs_log_leave("Return status %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Resize an attribute, creating a hole if relevant
|
||||
*/
|
||||
|
||||
int ntfs_attr_truncate(ntfs_attr *na, const s64 newsize)
|
||||
{
|
||||
return (ntfs_attr_truncate_i(na, newsize, HOLES_OK));
|
||||
}
|
||||
|
||||
/*
|
||||
* Resize an attribute, avoiding hole creation
|
||||
*/
|
||||
|
||||
int ntfs_attr_truncate_solid(ntfs_attr *na, const s64 newsize)
|
||||
{
|
||||
return (ntfs_attr_truncate_i(na, newsize, HOLES_NO));
|
||||
}
|
||||
|
||||
/*
|
||||
* Stuff a hole in a compressed file
|
||||
*
|
||||
|
@ -6462,7 +6494,7 @@ static int stuff_hole(ntfs_attr *na, const s64 pos)
|
|||
if (!ret
|
||||
&& ((na->initialized_size + end_size) < pos)
|
||||
&& ntfs_non_resident_attr_expand(na,
|
||||
pos - end_size))
|
||||
pos - end_size, HOLES_OK))
|
||||
ret = -1;
|
||||
else
|
||||
na->initialized_size
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* Copyright (c) 2004-2005 Anton Altaparmakov
|
||||
* Copyright (c) 2004-2006 Szabolcs Szakacsits
|
||||
* Copyright (c) 2005 Yura Pakhuchiy
|
||||
* Copyright (c) 2009-2010 Jean-Pierre Andre
|
||||
* Copyright (c) 2009-2011 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
|
||||
|
@ -1251,6 +1251,7 @@ static int ntfs_compress_overwr_free(ntfs_attr *na, runlist_element *rl,
|
|||
case 1 :
|
||||
/* there is a single hole, may have to merge */
|
||||
freerl->vcn = freevcn;
|
||||
freerl->length = freecnt;
|
||||
if (freerl[1].lcn == LCN_HOLE) {
|
||||
freerl->length += freerl[1].length;
|
||||
erl = freerl;
|
||||
|
|
|
@ -58,6 +58,9 @@
|
|||
#ifdef HAVE_SYS_MOUNT_H
|
||||
#include <sys/mount.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_DISK_H
|
||||
#include <sys/disk.h>
|
||||
#endif
|
||||
#ifdef HAVE_LINUX_FD_H
|
||||
#include <linux/fd.h>
|
||||
#endif
|
||||
|
@ -556,6 +559,36 @@ s64 ntfs_device_size_get(struct ntfs_device *dev, int block_size)
|
|||
return (s64)this_floppy.size * 512 / block_size;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef DIOCGMEDIASIZE
|
||||
{
|
||||
/* FreeBSD */
|
||||
off_t size;
|
||||
|
||||
if (dev->d_ops->ioctl(dev, DIOCGMEDIASIZE, &size) >= 0) {
|
||||
ntfs_log_debug("DIOCGMEDIASIZE nr bytes = %llu (0x%llx)\n",
|
||||
(unsigned long long)size,
|
||||
(unsigned long long)size);
|
||||
return (s64)size / block_size;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef DKIOCGETBLOCKCOUNT
|
||||
{
|
||||
/* Mac OS X */
|
||||
uint64_t blocks;
|
||||
int sector_size;
|
||||
|
||||
sector_size = ntfs_device_sector_size_get(dev);
|
||||
if (sector_size >= 0 && dev->d_ops->ioctl(dev,
|
||||
DKIOCGETBLOCKCOUNT, &blocks) >= 0)
|
||||
{
|
||||
ntfs_log_debug("DKIOCGETBLOCKCOUNT nr blocks = %llu (0x%llx)\n",
|
||||
(unsigned long long) blocks,
|
||||
(unsigned long long) blocks);
|
||||
return blocks * sector_size / block_size;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
* We couldn't figure it out by using a specialized ioctl,
|
||||
|
@ -705,6 +738,28 @@ int ntfs_device_sector_size_get(struct ntfs_device *dev)
|
|||
return sect_size;
|
||||
}
|
||||
}
|
||||
#elif defined(DIOCGSECTORSIZE)
|
||||
{
|
||||
/* FreeBSD */
|
||||
size_t sect_size = 0;
|
||||
|
||||
if (!dev->d_ops->ioctl(dev, DIOCGSECTORSIZE, §_size)) {
|
||||
ntfs_log_debug("DIOCGSECTORSIZE sector size = %d bytes\n",
|
||||
(int) sect_size);
|
||||
return sect_size;
|
||||
}
|
||||
}
|
||||
#elif defined(DKIOCGETBLOCKSIZE)
|
||||
{
|
||||
/* Mac OS X */
|
||||
uint32_t sect_size = 0;
|
||||
|
||||
if (!dev->d_ops->ioctl(dev, DKIOCGETBLOCKSIZE, §_size)) {
|
||||
ntfs_log_debug("DKIOCGETBLOCKSIZE sector size = %d bytes\n",
|
||||
(int) sect_size);
|
||||
return sect_size;
|
||||
}
|
||||
}
|
||||
#else
|
||||
errno = EOPNOTSUPP;
|
||||
#endif
|
||||
|
|
|
@ -1812,7 +1812,7 @@ search:
|
|||
while (!ntfs_attr_lookup(AT_FILE_NAME, AT_UNNAMED, 0, CASE_SENSITIVE,
|
||||
0, NULL, 0, actx)) {
|
||||
char *s;
|
||||
BOOL case_sensitive = IGNORE_CASE;
|
||||
IGNORE_CASE_BOOL case_sensitive = IGNORE_CASE;
|
||||
|
||||
errno = 0;
|
||||
fn = (FILE_NAME_ATTR*)((u8*)actx->attr +
|
||||
|
@ -1844,8 +1844,9 @@ search:
|
|||
(long long unsigned)MREF_LE(fn->parent_directory));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (fn->file_name_type == FILE_NAME_POSIX || case_sensitive_match)
|
||||
if (case_sensitive_match
|
||||
|| ((fn->file_name_type == FILE_NAME_POSIX)
|
||||
&& NVolCaseSensitive(ni->vol)))
|
||||
case_sensitive = CASE_SENSITIVE;
|
||||
|
||||
if (ntfs_names_are_equal(fn->file_name, fn->file_name_length,
|
||||
|
|
|
@ -1121,6 +1121,7 @@ static int ntfs_ir_reparent(ntfs_index_context *icx)
|
|||
INDEX_ENTRY *ie;
|
||||
INDEX_BLOCK *ib = NULL;
|
||||
VCN new_ib_vcn;
|
||||
int ix_root_size;
|
||||
int ret = STATUS_ERROR;
|
||||
|
||||
ntfs_log_trace("Entering\n");
|
||||
|
@ -1150,6 +1151,7 @@ static int ntfs_ir_reparent(ntfs_index_context *icx)
|
|||
if (ntfs_ib_write(icx, ib))
|
||||
goto clear_bmp;
|
||||
|
||||
retry :
|
||||
ir = ntfs_ir_lookup(icx->ni, icx->name, icx->name_len, &ctx);
|
||||
if (!ir)
|
||||
goto clear_bmp;
|
||||
|
@ -1164,12 +1166,32 @@ static int ntfs_ir_reparent(ntfs_index_context *icx)
|
|||
ir->index.index_length = cpu_to_le32(le32_to_cpu(ir->index.entries_offset)
|
||||
+ le16_to_cpu(ie->length));
|
||||
ir->index.allocated_size = ir->index.index_length;
|
||||
|
||||
ix_root_size = sizeof(INDEX_ROOT) - sizeof(INDEX_HEADER)
|
||||
+ le32_to_cpu(ir->index.allocated_size);
|
||||
if (ntfs_resident_attr_value_resize(ctx->mrec, ctx->attr,
|
||||
sizeof(INDEX_ROOT) - sizeof(INDEX_HEADER) +
|
||||
le32_to_cpu(ir->index.allocated_size)))
|
||||
ix_root_size)) {
|
||||
/*
|
||||
* When there is no space to build a non-resident
|
||||
* index, we may have to move the root to an extent
|
||||
*/
|
||||
if ((errno == ENOSPC)
|
||||
&& !ctx->al_entry
|
||||
&& !ntfs_inode_add_attrlist(icx->ni)) {
|
||||
ntfs_attr_put_search_ctx(ctx);
|
||||
ctx = (ntfs_attr_search_ctx*)NULL;
|
||||
ir = ntfs_ir_lookup(icx->ni, icx->name, icx->name_len,
|
||||
&ctx);
|
||||
if (ir
|
||||
&& !ntfs_attr_record_move_away(ctx, ix_root_size
|
||||
- le32_to_cpu(ctx->attr->value_length))) {
|
||||
ntfs_attr_put_search_ctx(ctx);
|
||||
ctx = (ntfs_attr_search_ctx*)NULL;
|
||||
goto retry;
|
||||
}
|
||||
}
|
||||
/* FIXME: revert index root */
|
||||
goto clear_bmp;
|
||||
}
|
||||
/*
|
||||
* FIXME: do it earlier if we have enough space in IR (should always),
|
||||
* so in error case we wouldn't lose the IB.
|
||||
|
|
|
@ -481,6 +481,9 @@ ntfs_inode *ntfs_inode_open(ntfs_volume *vol, const MFT_REF mref)
|
|||
} else {
|
||||
ni = ntfs_inode_real_open(vol, mref);
|
||||
}
|
||||
if (!ni) {
|
||||
debug_double_inode(item.inum, 0);
|
||||
}
|
||||
#else
|
||||
ni = ntfs_inode_real_open(vol, mref);
|
||||
#endif
|
||||
|
@ -842,6 +845,12 @@ static int ntfs_inode_sync_file_name(ntfs_inode *ni, ntfs_inode *dir_ni)
|
|||
else {
|
||||
fnx->allocated_size = cpu_to_sle64(ni->allocated_size);
|
||||
fnx->data_size = cpu_to_sle64(ni->data_size);
|
||||
/*
|
||||
* The file name record has also to be fixed if some
|
||||
* attribute update implied the unnamed data to be
|
||||
* made non-resident
|
||||
*/
|
||||
fn->allocated_size = fnx->allocated_size;
|
||||
}
|
||||
/* update or clear the reparse tag in the index */
|
||||
fnx->reparse_point_tag = reparse_tag;
|
||||
|
|
|
@ -200,8 +200,13 @@ static u64 ntfs_fix_file_name(ntfs_inode *dir_ni, ntfschar *uname,
|
|||
*/
|
||||
lemref = entry->indexed_file;
|
||||
mref = le64_to_cpu(lemref);
|
||||
for (i=0; i<found->file_name_length; i++)
|
||||
uname[i] = found->file_name[i];
|
||||
if (NVolCaseSensitive(vol) || !vol->locase) {
|
||||
for (i=0; i<found->file_name_length; i++)
|
||||
uname[i] = found->file_name[i];
|
||||
} else {
|
||||
for (i=0; i<found->file_name_length; i++)
|
||||
uname[i] = vol->locase[found->file_name[i]];
|
||||
}
|
||||
}
|
||||
}
|
||||
ntfs_index_ctx_put(icx);
|
||||
|
|
|
@ -5030,7 +5030,7 @@ int ntfs_get_group(struct SECURITY_API *scapi, const SID *gsid)
|
|||
*/
|
||||
|
||||
struct SECURITY_API *ntfs_initialize_file_security(const char *device,
|
||||
int flags)
|
||||
unsigned long flags)
|
||||
{
|
||||
ntfs_volume *vol;
|
||||
unsigned long mntflag;
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
*
|
||||
* Copyright (c) 2000-2004 Anton Altaparmakov
|
||||
* Copyright (c) 2002-2009 Szabolcs Szakacsits
|
||||
* Copyright (c) 2008-2010 Jean-Pierre Andre
|
||||
* Copyright (c) 2008-2011 Jean-Pierre Andre
|
||||
* Copyright (c) 2008 Bernhard Kaindl
|
||||
*
|
||||
* This program/include file is free software; you can redistribute it and/or
|
||||
|
@ -1128,6 +1128,69 @@ char *ntfs_uppercase_mbs(const char *low,
|
|||
*/
|
||||
void ntfs_upcase_table_build(ntfschar *uc, u32 uc_len)
|
||||
{
|
||||
#if 1 /* Vista */
|
||||
/*
|
||||
* This is the table as defined by Vista
|
||||
*/
|
||||
/*
|
||||
* "Start" is inclusive and "End" is exclusive, every value has the
|
||||
* value of "Add" added to it.
|
||||
*/
|
||||
static int uc_run_table[][3] = { /* Start, End, Add */
|
||||
{0x0061, 0x007b, -32}, {0x00e0, 0x00f7, -32}, {0x00f8, 0x00ff, -32},
|
||||
{0x0256, 0x0258, -205}, {0x028a, 0x028c, -217}, {0x037b, 0x037e, 130},
|
||||
{0x03ac, 0x03ad, -38}, {0x03ad, 0x03b0, -37}, {0x03b1, 0x03c2, -32},
|
||||
{0x03c2, 0x03c3, -31}, {0x03c3, 0x03cc, -32}, {0x03cc, 0x03cd, -64},
|
||||
{0x03cd, 0x03cf, -63}, {0x0430, 0x0450, -32}, {0x0450, 0x0460, -80},
|
||||
{0x0561, 0x0587, -48}, {0x1f00, 0x1f08, 8}, {0x1f10, 0x1f16, 8},
|
||||
{0x1f20, 0x1f28, 8}, {0x1f30, 0x1f38, 8}, {0x1f40, 0x1f46, 8},
|
||||
{0x1f51, 0x1f52, 8}, {0x1f53, 0x1f54, 8}, {0x1f55, 0x1f56, 8},
|
||||
{0x1f57, 0x1f58, 8}, {0x1f60, 0x1f68, 8}, {0x1f70, 0x1f72, 74},
|
||||
{0x1f72, 0x1f76, 86}, {0x1f76, 0x1f78, 100}, {0x1f78, 0x1f7a, 128},
|
||||
{0x1f7a, 0x1f7c, 112}, {0x1f7c, 0x1f7e, 126}, {0x1f80, 0x1f88, 8},
|
||||
{0x1f90, 0x1f98, 8}, {0x1fa0, 0x1fa8, 8}, {0x1fb0, 0x1fb2, 8},
|
||||
{0x1fb3, 0x1fb4, 9}, {0x1fcc, 0x1fcd, -9}, {0x1fd0, 0x1fd2, 8},
|
||||
{0x1fe0, 0x1fe2, 8}, {0x1fe5, 0x1fe6, 7}, {0x1ffc, 0x1ffd, -9},
|
||||
{0x2170, 0x2180, -16}, {0x24d0, 0x24ea, -26}, {0x2c30, 0x2c5f, -48},
|
||||
{0x2d00, 0x2d26, -7264}, {0xff41, 0xff5b, -32}, {0}
|
||||
};
|
||||
/*
|
||||
* "Start" is exclusive and "End" is inclusive, every second value is
|
||||
* decremented by one.
|
||||
*/
|
||||
static int uc_dup_table[][2] = { /* Start, End */
|
||||
{0x0100, 0x012f}, {0x0132, 0x0137}, {0x0139, 0x0149}, {0x014a, 0x0178},
|
||||
{0x0179, 0x017e}, {0x01a0, 0x01a6}, {0x01b3, 0x01b7}, {0x01cd, 0x01dd},
|
||||
{0x01de, 0x01ef}, {0x01f4, 0x01f5}, {0x01f8, 0x01f9}, {0x01fa, 0x0220},
|
||||
{0x0222, 0x0234}, {0x023b, 0x023c}, {0x0241, 0x0242}, {0x0246, 0x024f},
|
||||
{0x03d8, 0x03ef}, {0x03f7, 0x03f8}, {0x03fa, 0x03fb}, {0x0460, 0x0481},
|
||||
{0x048a, 0x04bf}, {0x04c1, 0x04c4}, {0x04c5, 0x04c8}, {0x04c9, 0x04ce},
|
||||
{0x04ec, 0x04ed}, {0x04d0, 0x04eb}, {0x04ee, 0x04f5}, {0x04f6, 0x0513},
|
||||
{0x1e00, 0x1e95}, {0x1ea0, 0x1ef9}, {0x2183, 0x2184}, {0x2c60, 0x2c61},
|
||||
{0x2c67, 0x2c6c}, {0x2c75, 0x2c76}, {0x2c80, 0x2ce3}, {0}
|
||||
};
|
||||
/*
|
||||
* Set the Unicode character at offset "Offset" to "Value". Note,
|
||||
* "Value" is host endian.
|
||||
*/
|
||||
static int uc_byte_table[][2] = { /* Offset, Value */
|
||||
{0x00ff, 0x0178}, {0x0180, 0x0243}, {0x0183, 0x0182}, {0x0185, 0x0184},
|
||||
{0x0188, 0x0187}, {0x018c, 0x018b}, {0x0192, 0x0191}, {0x0195, 0x01f6},
|
||||
{0x0199, 0x0198}, {0x019a, 0x023d}, {0x019e, 0x0220}, {0x01a8, 0x01a7},
|
||||
{0x01ad, 0x01ac}, {0x01b0, 0x01af}, {0x01b9, 0x01b8}, {0x01bd, 0x01bc},
|
||||
{0x01bf, 0x01f7}, {0x01c6, 0x01c4}, {0x01c9, 0x01c7}, {0x01cc, 0x01ca},
|
||||
{0x01dd, 0x018e}, {0x01f3, 0x01f1}, {0x023a, 0x2c65}, {0x023e, 0x2c66},
|
||||
{0x0253, 0x0181}, {0x0254, 0x0186}, {0x0259, 0x018f}, {0x025b, 0x0190},
|
||||
{0x0260, 0x0193}, {0x0263, 0x0194}, {0x0268, 0x0197}, {0x0269, 0x0196},
|
||||
{0x026b, 0x2c62}, {0x026f, 0x019c}, {0x0272, 0x019d}, {0x0275, 0x019f},
|
||||
{0x027d, 0x2c64}, {0x0280, 0x01a6}, {0x0283, 0x01a9}, {0x0288, 0x01ae},
|
||||
{0x0289, 0x0244}, {0x028c, 0x0245}, {0x0292, 0x01b7}, {0x03f2, 0x03f9},
|
||||
{0x04cf, 0x04c0}, {0x1d7d, 0x2c63}, {0x214e, 0x2132}, {0}
|
||||
};
|
||||
#else /* Vista */
|
||||
/*
|
||||
* This is the table as defined by Windows XP
|
||||
*/
|
||||
static int uc_run_table[][3] = { /* Start, End, Add */
|
||||
{0x0061, 0x007B, -32}, {0x0451, 0x045D, -80}, {0x1F70, 0x1F72, 74},
|
||||
{0x00E0, 0x00F7, -32}, {0x045E, 0x0460, -80}, {0x1F72, 0x1F76, 86},
|
||||
|
@ -1164,6 +1227,7 @@ void ntfs_upcase_table_build(ntfschar *uc, u32 uc_len)
|
|||
{0x01A8, 0x01A7}, {0x01DD, 0x018E}, {0x0268, 0x0197},
|
||||
{0}
|
||||
};
|
||||
#endif /* Vista */
|
||||
int i, r;
|
||||
int k, off;
|
||||
|
||||
|
@ -1187,6 +1251,27 @@ void ntfs_upcase_table_build(ntfschar *uc, u32 uc_len)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate and build the default upcase table
|
||||
*
|
||||
* Returns the number of entries
|
||||
* 0 if failed
|
||||
*/
|
||||
|
||||
#define UPCASE_LEN 65536 /* default number of entries in upcase */
|
||||
|
||||
u32 ntfs_upcase_build_default(ntfschar **upcase)
|
||||
{
|
||||
u32 upcase_len;
|
||||
|
||||
*upcase = (ntfschar*)ntfs_malloc(UPCASE_LEN*2);
|
||||
if (*upcase) {
|
||||
ntfs_upcase_table_build(*upcase, UPCASE_LEN*2);
|
||||
upcase_len = UPCASE_LEN;
|
||||
}
|
||||
return (upcase_len);
|
||||
}
|
||||
|
||||
/*
|
||||
* Build a table for converting to lower case
|
||||
*
|
||||
|
|
|
@ -482,13 +482,10 @@ ntfs_volume *ntfs_volume_startup(struct ntfs_device *dev, unsigned long flags)
|
|||
goto error_exit;
|
||||
|
||||
/* Create the default upcase table. */
|
||||
vol->upcase_len = 65536;
|
||||
vol->upcase = ntfs_malloc(vol->upcase_len * sizeof(ntfschar));
|
||||
if (!vol->upcase)
|
||||
vol->upcase_len = ntfs_upcase_build_default(&vol->upcase);
|
||||
if (!vol->upcase_len || !vol->upcase)
|
||||
goto error_exit;
|
||||
|
||||
ntfs_upcase_table_build(vol->upcase,
|
||||
vol->upcase_len * sizeof(ntfschar));
|
||||
|
||||
/* Default with no locase table and case sensitive file names */
|
||||
vol->locase = (ntfschar*)NULL;
|
||||
NVolSetCaseSensitive(vol);
|
||||
|
@ -1184,7 +1181,7 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, unsigned long flags)
|
|||
* Check for dirty logfile and hibernated Windows.
|
||||
* We care only about read-write mounts.
|
||||
*/
|
||||
if (!(flags & MS_RDONLY)) {
|
||||
if (!(flags & (MS_RDONLY | MS_FORENSIC))) {
|
||||
if (!(flags & MS_IGNORE_HIBERFILE) &&
|
||||
ntfs_volume_check_hiberfile(vol, 1) < 0)
|
||||
goto error_exit;
|
||||
|
@ -1196,10 +1193,10 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, unsigned long flags)
|
|||
if (ntfs_logfile_reset(vol))
|
||||
goto error_exit;
|
||||
}
|
||||
}
|
||||
/* make $TXF_DATA resident if present on the root directory */
|
||||
if (!NVolReadOnly(vol) && fix_txf_data(vol))
|
||||
goto error_exit;
|
||||
if (fix_txf_data(vol))
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
return vol;
|
||||
io_error_exit:
|
||||
|
|
|
@ -473,110 +473,6 @@ void ntfs_xattr_free_mapping(struct XATTRMAPPING *mapping)
|
|||
|
||||
#endif /* XATTR_MAPPINGS */
|
||||
|
||||
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;
|
||||
#ifdef XATTR_MAPPINGS
|
||||
BOOL accepted;
|
||||
const struct XATTRMAPPING *item;
|
||||
#endif /* XATTR_MAPPINGS */
|
||||
|
||||
/* 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);
|
||||
}
|
||||
#ifdef XATTR_MAPPINGS
|
||||
/* now append the system attributes mapped to user space */
|
||||
for (item=ni->vol->xattr_mapping; item; item=item->next) {
|
||||
switch (item->xattr) {
|
||||
case XATTR_NTFS_EFSINFO :
|
||||
accepted = ni->vol->efs_raw
|
||||
&& (ni->flags & FILE_ATTR_ENCRYPTED);
|
||||
break;
|
||||
case XATTR_NTFS_REPARSE_DATA :
|
||||
accepted = (ni->flags & FILE_ATTR_REPARSE_POINT)
|
||||
!= const_cpu_to_le32(0);
|
||||
break;
|
||||
// TODO : we are supposed to only return xattrs which are set
|
||||
// this is more complex for OBJECT_ID and DOS_NAME
|
||||
default : accepted = TRUE;
|
||||
break;
|
||||
}
|
||||
if (accepted) {
|
||||
ret += strlen(item->name) + 1;
|
||||
if (size) {
|
||||
if ((size_t)ret <= size) {
|
||||
strcpy(to, item->name);
|
||||
to += strlen(item->name);
|
||||
*to++ = 0;
|
||||
} else {
|
||||
ret = -ERANGE;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
#else /* XATTR_MAPPINGS */
|
||||
/* List efs info xattr for encrypted files */
|
||||
if (ni->vol->efs_raw && (ni->flags & FILE_ATTR_ENCRYPTED)) {
|
||||
ret += sizeof(nf_ns_alt_xattr_efsinfo);
|
||||
if ((size_t)ret <= size) {
|
||||
memcpy(to, nf_ns_alt_xattr_efsinfo,
|
||||
sizeof(nf_ns_alt_xattr_efsinfo));
|
||||
to += sizeof(nf_ns_alt_xattr_efsinfo);
|
||||
#endif /* XATTR_MAPPINGS */
|
||||
}
|
||||
}
|
||||
exit :
|
||||
return (ret);
|
||||
}
|
||||
|
||||
|
||||
int ntfs_xattr_system_getxattr(struct SECURITY_CONTEXT *scx,
|
||||
enum SYSTEMXATTRS attr,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
|
||||
EXTRA_DIST = secaudit.h
|
||||
EXTRA_DIST = secaudit.h ntfs-3g_common.h
|
||||
|
||||
MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
|
||||
|
||||
|
@ -29,7 +29,7 @@ ntfs_3g_CFLAGS = \
|
|||
-DFUSE_USE_VERSION=26 \
|
||||
$(FUSE_CFLAGS) \
|
||||
-I$(top_srcdir)/include/ntfs-3g
|
||||
ntfs_3g_SOURCES = ntfs-3g.c
|
||||
ntfs_3g_SOURCES = ntfs-3g.c ntfs-3g_common.c
|
||||
|
||||
lowntfs_3g_LDADD = $(FUSE_LIBS) $(top_builddir)/libntfs-3g/libntfs-3g.la
|
||||
if REALLYSTATIC
|
||||
|
@ -40,7 +40,7 @@ lowntfs_3g_CFLAGS = \
|
|||
-DFUSE_USE_VERSION=26 \
|
||||
$(FUSE_CFLAGS) \
|
||||
-I$(top_srcdir)/include/ntfs-3g
|
||||
lowntfs_3g_SOURCES = lowntfs-3g.c
|
||||
lowntfs_3g_SOURCES = lowntfs-3g.c ntfs-3g_common.c
|
||||
|
||||
ntfs_3g_probe_LDADD = $(top_builddir)/libntfs-3g/libntfs-3g.la
|
||||
ntfs_3g_usermap_LDADD = $(top_builddir)/libntfs-3g/libntfs-3g.la
|
||||
|
|
553
src/lowntfs-3g.c
553
src/lowntfs-3g.c
|
@ -4,7 +4,7 @@
|
|||
* Copyright (c) 2005-2007 Yura Pakhuchiy
|
||||
* Copyright (c) 2005 Yuval Fledel
|
||||
* Copyright (c) 2006-2009 Szabolcs Szakacsits
|
||||
* Copyright (c) 2007-2010 Jean-Pierre Andre
|
||||
* Copyright (c) 2007-2011 Jean-Pierre Andre
|
||||
* Copyright (c) 2009 Erik Larsson
|
||||
*
|
||||
* This file is originated from the Linux-NTFS project.
|
||||
|
@ -38,12 +38,6 @@
|
|||
#error "***********************************************************"
|
||||
#endif
|
||||
|
||||
#ifdef FUSE_INTERNAL
|
||||
#define FUSE_TYPE "integrated FUSE low"
|
||||
#else
|
||||
#define FUSE_TYPE "external FUSE low"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STDIO_H
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
@ -69,7 +63,6 @@
|
|||
#ifdef HAVE_LIMITS_H
|
||||
#include <limits.h>
|
||||
#endif
|
||||
#include <getopt.h>
|
||||
#include <syslog.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
|
@ -105,6 +98,8 @@
|
|||
#include "xattrs.h"
|
||||
#include "misc.h"
|
||||
|
||||
#include "ntfs-3g_common.h"
|
||||
|
||||
/*
|
||||
* The following permission checking modes are governed by
|
||||
* the LPERMSCONFIG value in param.h
|
||||
|
@ -157,12 +152,6 @@ typedef enum {
|
|||
FSTYPE_FUSEBLK
|
||||
} fuse_fstype;
|
||||
|
||||
typedef enum {
|
||||
ATIME_ENABLED,
|
||||
ATIME_DISABLED,
|
||||
ATIME_RELATIVE
|
||||
} ntfs_atime_t;
|
||||
|
||||
typedef struct fill_item {
|
||||
struct fill_item *next;
|
||||
size_t bufsize;
|
||||
|
@ -187,66 +176,16 @@ struct open_file {
|
|||
int state;
|
||||
} ;
|
||||
|
||||
typedef enum {
|
||||
NF_STREAMS_INTERFACE_NONE, /* No access to named data streams. */
|
||||
NF_STREAMS_INTERFACE_XATTR, /* Map named data streams to xattrs. */
|
||||
NF_STREAMS_INTERFACE_OPENXATTR, /* Same, not limited to "user." */
|
||||
} ntfs_fuse_streams_interface;
|
||||
|
||||
enum {
|
||||
CLOSE_GHOST = 1,
|
||||
CLOSE_COMPRESSED = 2,
|
||||
CLOSE_ENCRYPTED = 4
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
ntfs_volume *vol;
|
||||
unsigned int uid;
|
||||
unsigned int gid;
|
||||
unsigned int fmask;
|
||||
unsigned int dmask;
|
||||
ntfs_fuse_streams_interface streams;
|
||||
ntfs_atime_t atime;
|
||||
BOOL ro;
|
||||
BOOL show_sys_files;
|
||||
BOOL hide_hid_files;
|
||||
BOOL hide_dot_files;
|
||||
BOOL ignore_case;
|
||||
BOOL windows_names;
|
||||
BOOL compression;
|
||||
BOOL silent;
|
||||
BOOL recover;
|
||||
BOOL hiberfile;
|
||||
BOOL sync;
|
||||
BOOL debug;
|
||||
BOOL no_detach;
|
||||
BOOL blkdev;
|
||||
BOOL mounted;
|
||||
#ifdef HAVE_SETXATTR /* extended attributes interface required */
|
||||
BOOL efs_raw;
|
||||
#ifdef XATTR_MAPPINGS
|
||||
char *xattrmap_path;
|
||||
#endif /* XATTR_MAPPINGS */
|
||||
#endif /* HAVE_SETXATTR */
|
||||
struct fuse_chan *fc;
|
||||
BOOL inherit;
|
||||
unsigned int secure_flags;
|
||||
char *usermap_path;
|
||||
char *abs_mnt_point;
|
||||
struct PERMISSIONS_CACHE *seccache;
|
||||
struct SECURITY_CONTEXT security;
|
||||
struct open_file *open_files;
|
||||
u64 latest_ghost;
|
||||
} ntfs_fuse_context_t;
|
||||
static struct ntfs_options opts;
|
||||
|
||||
static struct options {
|
||||
char *mnt_point; /* Mount point */
|
||||
char *options; /* Mount options */
|
||||
char *device; /* Device to mount */
|
||||
} opts;
|
||||
const char *EXEC_NAME = "lowntfs-3g";
|
||||
|
||||
static const char *EXEC_NAME = "ntfs-3g";
|
||||
static char def_opts[] = "allow_other,nonempty,";
|
||||
static ntfs_fuse_context_t *ctx;
|
||||
static u32 ntfs_sequence;
|
||||
static const char ghostformat[] = ".ghost-ntfs-3g-%020llu";
|
||||
|
@ -268,7 +207,7 @@ static const char *usage_msg =
|
|||
"\n"
|
||||
"Copyright (C) 2005-2007 Yura Pakhuchiy\n"
|
||||
"Copyright (C) 2006-2009 Szabolcs Szakacsits\n"
|
||||
"Copyright (C) 2007-2010 Jean-Pierre Andre\n"
|
||||
"Copyright (C) 2007-2011 Jean-Pierre Andre\n"
|
||||
"Copyright (C) 2009 Erik Larsson\n"
|
||||
"\n"
|
||||
"Usage: %s [-o option[,...]] <device|image_file> <mount_point>\n"
|
||||
|
@ -1272,6 +1211,9 @@ static void ntfs_fuse_open(fuse_req_t req, fuse_ino_t ino,
|
|||
&& (ni->flags & FILE_ATTR_ENCRYPTED))
|
||||
state |= CLOSE_ENCRYPTED;
|
||||
#endif /* HAVE_SETXATTR */
|
||||
/* deny opening metadata files for writing */
|
||||
if (ino < FILE_first_user)
|
||||
res = -EPERM;
|
||||
}
|
||||
ntfs_attr_close(na);
|
||||
} else
|
||||
|
@ -1549,6 +1491,11 @@ static int ntfs_fuse_trunc(struct SECURITY_CONTEXT *scx, fuse_ino_t ino,
|
|||
if (!ni)
|
||||
goto exit;
|
||||
|
||||
/* deny truncating metadata files */
|
||||
if (ino < FILE_first_user) {
|
||||
errno = EPERM;
|
||||
goto exit;
|
||||
}
|
||||
na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0);
|
||||
if (!na)
|
||||
goto exit;
|
||||
|
@ -2156,6 +2103,11 @@ static int ntfs_fuse_rm(fuse_req_t req, fuse_ino_t parent, const char *name)
|
|||
res = -errno;
|
||||
goto exit;
|
||||
}
|
||||
/* deny unlinking metadata files */
|
||||
if (MREF(iref) < FILE_first_user) {
|
||||
res = -EPERM;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
of = ctx->open_files;
|
||||
ino = (fuse_ino_t)MREF(iref);
|
||||
|
@ -2572,17 +2524,6 @@ enum {
|
|||
XATTRNS_OPEN
|
||||
} ;
|
||||
|
||||
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_system_prefix[] = "system.";
|
||||
static const int nf_ns_system_prefix_len = sizeof(nf_ns_system_prefix) - 1;
|
||||
static const char nf_ns_security_prefix[] = "security.";
|
||||
static const int nf_ns_security_prefix_len = sizeof(nf_ns_security_prefix) - 1;
|
||||
static const char nf_ns_trusted_prefix[] = "trusted.";
|
||||
static const int nf_ns_trusted_prefix_len = sizeof(nf_ns_trusted_prefix) - 1;
|
||||
|
||||
static const char xattr_ntfs_3g[] = "ntfs-3g.";
|
||||
|
||||
/*
|
||||
* Check whether access to internal data as an extended
|
||||
* attribute in system name space is allowed
|
||||
|
@ -2771,7 +2712,7 @@ static void ntfs_fuse_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size)
|
|||
|
||||
if ((ctx->streams == NF_STREAMS_INTERFACE_XATTR)
|
||||
|| (ctx->streams == NF_STREAMS_INTERFACE_OPENXATTR)) {
|
||||
ret = ntfs_xattr_listxattr(ni, actx, list, size,
|
||||
ret = ntfs_fuse_listxattr_common(ni, actx, list, size,
|
||||
ctx->streams == NF_STREAMS_INTERFACE_XATTR);
|
||||
if (ret < 0)
|
||||
goto exit;
|
||||
|
@ -3508,350 +3449,6 @@ err_out:
|
|||
|
||||
}
|
||||
|
||||
#define STRAPPEND_MAX_INSIZE 8192
|
||||
#define strappend_is_large(x) ((x) > STRAPPEND_MAX_INSIZE)
|
||||
|
||||
static int strappend(char **dest, const char *append)
|
||||
{
|
||||
char *p;
|
||||
size_t size_append, size_dest = 0;
|
||||
|
||||
if (!dest)
|
||||
return -1;
|
||||
if (!append)
|
||||
return 0;
|
||||
|
||||
size_append = strlen(append);
|
||||
if (*dest)
|
||||
size_dest = strlen(*dest);
|
||||
|
||||
if (strappend_is_large(size_dest) || strappend_is_large(size_append)) {
|
||||
errno = EOVERFLOW;
|
||||
ntfs_log_perror("%s: Too large input buffer", EXEC_NAME);
|
||||
return -1;
|
||||
}
|
||||
|
||||
p = (char*)realloc(*dest, size_dest + size_append + 1);
|
||||
if (!p) {
|
||||
ntfs_log_perror("%s: Memory reallocation failed", EXEC_NAME);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*dest = p;
|
||||
strcpy(*dest + size_dest, append);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bogus_option_value(char *val, const char *s)
|
||||
{
|
||||
if (val) {
|
||||
ntfs_log_error("'%s' option shouldn't have value.\n", s);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int missing_option_value(char *val, const char *s)
|
||||
{
|
||||
if (!val) {
|
||||
ntfs_log_error("'%s' option should have a value.\n", s);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char *parse_mount_options(const char *orig_opts)
|
||||
{
|
||||
char *options, *s, *opt, *val, *ret = NULL;
|
||||
BOOL no_def_opts = FALSE;
|
||||
int default_permissions = 0;
|
||||
int permissions = 0;
|
||||
int want_permissions = 0;
|
||||
|
||||
ctx->secure_flags = 0;
|
||||
#ifdef HAVE_SETXATTR /* extended attributes interface required */
|
||||
ctx->efs_raw = FALSE;
|
||||
#endif /* HAVE_SETXATTR */
|
||||
ctx->compression = DEFAULT_COMPRESSION;
|
||||
options = strdup(orig_opts ? orig_opts : "");
|
||||
if (!options) {
|
||||
ntfs_log_perror("%s: strdup failed", EXEC_NAME);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
s = options;
|
||||
while (s && *s && (val = strsep(&s, ","))) {
|
||||
opt = strsep(&val, "=");
|
||||
if (!strcmp(opt, "ro")) { /* Read-only mount. */
|
||||
if (bogus_option_value(val, "ro"))
|
||||
goto err_exit;
|
||||
ctx->ro = TRUE;
|
||||
if (strappend(&ret, "ro,"))
|
||||
goto err_exit;
|
||||
} else if (!strcmp(opt, "noatime")) {
|
||||
if (bogus_option_value(val, "noatime"))
|
||||
goto err_exit;
|
||||
ctx->atime = ATIME_DISABLED;
|
||||
} else if (!strcmp(opt, "atime")) {
|
||||
if (bogus_option_value(val, "atime"))
|
||||
goto err_exit;
|
||||
ctx->atime = ATIME_ENABLED;
|
||||
} else if (!strcmp(opt, "relatime")) {
|
||||
if (bogus_option_value(val, "relatime"))
|
||||
goto err_exit;
|
||||
ctx->atime = ATIME_RELATIVE;
|
||||
} else if (!strcmp(opt, "fake_rw")) {
|
||||
if (bogus_option_value(val, "fake_rw"))
|
||||
goto err_exit;
|
||||
ctx->ro = TRUE;
|
||||
} else if (!strcmp(opt, "fsname")) { /* Filesystem name. */
|
||||
/*
|
||||
* We need this to be able to check whether filesystem
|
||||
* mounted or not.
|
||||
*/
|
||||
ntfs_log_error("'fsname' is unsupported option.\n");
|
||||
goto err_exit;
|
||||
} else if (!strcmp(opt, "no_def_opts")) {
|
||||
if (bogus_option_value(val, "no_def_opts"))
|
||||
goto err_exit;
|
||||
no_def_opts = TRUE; /* Don't add default options. */
|
||||
ctx->silent = FALSE; /* cancel default silent */
|
||||
} else if (!strcmp(opt, "default_permissions")) {
|
||||
default_permissions = 1;
|
||||
} else if (!strcmp(opt, "permissions")) {
|
||||
permissions = 1;
|
||||
} else if (!strcmp(opt, "umask")) {
|
||||
if (missing_option_value(val, "umask"))
|
||||
goto err_exit;
|
||||
sscanf(val, "%o", &ctx->fmask);
|
||||
ctx->dmask = ctx->fmask;
|
||||
want_permissions = 1;
|
||||
} else if (!strcmp(opt, "fmask")) {
|
||||
if (missing_option_value(val, "fmask"))
|
||||
goto err_exit;
|
||||
sscanf(val, "%o", &ctx->fmask);
|
||||
want_permissions = 1;
|
||||
} else if (!strcmp(opt, "dmask")) {
|
||||
if (missing_option_value(val, "dmask"))
|
||||
goto err_exit;
|
||||
sscanf(val, "%o", &ctx->dmask);
|
||||
want_permissions = 1;
|
||||
} else if (!strcmp(opt, "uid")) {
|
||||
if (missing_option_value(val, "uid"))
|
||||
goto err_exit;
|
||||
sscanf(val, "%i", &ctx->uid);
|
||||
want_permissions = 1;
|
||||
} else if (!strcmp(opt, "gid")) {
|
||||
if (missing_option_value(val, "gid"))
|
||||
goto err_exit;
|
||||
sscanf(val, "%i", &ctx->gid);
|
||||
want_permissions = 1;
|
||||
} else if (!strcmp(opt, "show_sys_files")) {
|
||||
if (bogus_option_value(val, "show_sys_files"))
|
||||
goto err_exit;
|
||||
ctx->show_sys_files = TRUE;
|
||||
} else if (!strcmp(opt, "hide_hid_files")) {
|
||||
if (bogus_option_value(val, "hide_hid_files"))
|
||||
goto err_exit;
|
||||
ctx->hide_hid_files = TRUE;
|
||||
} else if (!strcmp(opt, "hide_dot_files")) {
|
||||
if (bogus_option_value(val, "hide_dot_files"))
|
||||
goto err_exit;
|
||||
ctx->hide_dot_files = TRUE;
|
||||
} else if (!strcmp(opt, "ignore_case")) {
|
||||
if (bogus_option_value(val, "ignore_case"))
|
||||
goto err_exit;
|
||||
ctx->ignore_case = TRUE;
|
||||
} else if (!strcmp(opt, "windows_names")) {
|
||||
if (bogus_option_value(val, "windows_names"))
|
||||
goto err_exit;
|
||||
ctx->windows_names = TRUE;
|
||||
} else if (!strcmp(opt, "compression")) {
|
||||
if (bogus_option_value(val, "compression"))
|
||||
goto err_exit;
|
||||
ctx->compression = TRUE;
|
||||
} else if (!strcmp(opt, "nocompression")) {
|
||||
if (bogus_option_value(val, "nocompression"))
|
||||
goto err_exit;
|
||||
ctx->compression = FALSE;
|
||||
} else if (!strcmp(opt, "silent")) {
|
||||
if (bogus_option_value(val, "silent"))
|
||||
goto err_exit;
|
||||
ctx->silent = TRUE;
|
||||
} else if (!strcmp(opt, "recover")) {
|
||||
if (bogus_option_value(val, "recover"))
|
||||
goto err_exit;
|
||||
ctx->recover = TRUE;
|
||||
} else if (!strcmp(opt, "norecover")) {
|
||||
if (bogus_option_value(val, "norecover"))
|
||||
goto err_exit;
|
||||
ctx->recover = FALSE;
|
||||
} else if (!strcmp(opt, "remove_hiberfile")) {
|
||||
if (bogus_option_value(val, "remove_hiberfile"))
|
||||
goto err_exit;
|
||||
ctx->hiberfile = TRUE;
|
||||
} else if (!strcmp(opt, "sync")) {
|
||||
if (bogus_option_value(val, "sync"))
|
||||
goto err_exit;
|
||||
ctx->sync = TRUE;
|
||||
if (strappend(&ret, "sync,"))
|
||||
goto err_exit;
|
||||
} else if (!strcmp(opt, "locale")) {
|
||||
if (missing_option_value(val, "locale"))
|
||||
goto err_exit;
|
||||
ntfs_set_char_encoding(val);
|
||||
#if defined(__APPLE__) || defined(__DARWIN__)
|
||||
#ifdef ENABLE_NFCONV
|
||||
} else if (!strcmp(opt, "nfconv")) {
|
||||
if (bogus_option_value(val, "nfconv"))
|
||||
goto err_exit;
|
||||
if (ntfs_macosx_normalize_filenames(1)) {
|
||||
ntfs_log_error("ntfs_macosx_normalize_filenames(1) failed!\n");
|
||||
goto err_exit;
|
||||
}
|
||||
} else if (!strcmp(opt, "nonfconv")) {
|
||||
if (bogus_option_value(val, "nonfconv"))
|
||||
goto err_exit;
|
||||
if (ntfs_macosx_normalize_filenames(0)) {
|
||||
ntfs_log_error("ntfs_macosx_normalize_filenames(0) failed!\n");
|
||||
goto err_exit;
|
||||
}
|
||||
#endif /* ENABLE_NFCONV */
|
||||
#endif /* defined(__APPLE__) || defined(__DARWIN__) */
|
||||
} else if (!strcmp(opt, "streams_interface")) {
|
||||
if (missing_option_value(val, "streams_interface"))
|
||||
goto err_exit;
|
||||
if (!strcmp(val, "none"))
|
||||
ctx->streams = NF_STREAMS_INTERFACE_NONE;
|
||||
else if (!strcmp(val, "xattr"))
|
||||
ctx->streams = NF_STREAMS_INTERFACE_XATTR;
|
||||
else if (!strcmp(val, "openxattr"))
|
||||
ctx->streams = NF_STREAMS_INTERFACE_OPENXATTR;
|
||||
else {
|
||||
ntfs_log_error("Invalid named data streams "
|
||||
"access interface.\n");
|
||||
goto err_exit;
|
||||
}
|
||||
} else if (!strcmp(opt, "user_xattr")) {
|
||||
ctx->streams = NF_STREAMS_INTERFACE_XATTR;
|
||||
} else if (!strcmp(opt, "noauto")) {
|
||||
/* Don't pass noauto option to fuse. */
|
||||
} else if (!strcmp(opt, "debug")) {
|
||||
if (bogus_option_value(val, "debug"))
|
||||
goto err_exit;
|
||||
ctx->debug = TRUE;
|
||||
ntfs_log_set_levels(NTFS_LOG_LEVEL_DEBUG);
|
||||
ntfs_log_set_levels(NTFS_LOG_LEVEL_TRACE);
|
||||
} else if (!strcmp(opt, "no_detach")) {
|
||||
if (bogus_option_value(val, "no_detach"))
|
||||
goto err_exit;
|
||||
ctx->no_detach = TRUE;
|
||||
} else if (!strcmp(opt, "remount")) {
|
||||
ntfs_log_error("Remounting is not supported at present."
|
||||
" You have to umount volume and then "
|
||||
"mount it once again.\n");
|
||||
goto err_exit;
|
||||
} else if (!strcmp(opt, "blksize")) {
|
||||
ntfs_log_info("WARNING: blksize option is ignored "
|
||||
"because ntfs-3g must calculate it.\n");
|
||||
} else if (!strcmp(opt, "inherit")) {
|
||||
/*
|
||||
* JPA do not overwrite inherited permissions
|
||||
* in create()
|
||||
*/
|
||||
ctx->inherit = TRUE;
|
||||
} else if (!strcmp(opt, "addsecurids")) {
|
||||
/*
|
||||
* JPA create security ids for files being read
|
||||
* with an individual security attribute
|
||||
*/
|
||||
ctx->secure_flags |= (1 << SECURITY_ADDSECURIDS);
|
||||
} else if (!strcmp(opt, "staticgrps")) {
|
||||
/*
|
||||
* JPA use static definition of groups
|
||||
* for file access control
|
||||
*/
|
||||
ctx->secure_flags |= (1 << SECURITY_STATICGRPS);
|
||||
} else if (!strcmp(opt, "usermapping")) {
|
||||
if (!val) {
|
||||
ntfs_log_error("'usermapping' option should have "
|
||||
"a value.\n");
|
||||
goto err_exit;
|
||||
}
|
||||
ctx->usermap_path = strdup(val);
|
||||
if (!ctx->usermap_path) {
|
||||
ntfs_log_error("no more memory to store "
|
||||
"'usermapping' option.\n");
|
||||
goto err_exit;
|
||||
}
|
||||
#ifdef HAVE_SETXATTR /* extended attributes interface required */
|
||||
#ifdef XATTR_MAPPINGS
|
||||
} else if (!strcmp(opt, "xattrmapping")) {
|
||||
if (!val) {
|
||||
ntfs_log_error("'xattrmapping' option should have "
|
||||
"a value.\n");
|
||||
goto err_exit;
|
||||
}
|
||||
ctx->xattrmap_path = strdup(val);
|
||||
if (!ctx->xattrmap_path) {
|
||||
ntfs_log_error("no more memory to store "
|
||||
"'xattrmapping' option.\n");
|
||||
goto err_exit;
|
||||
}
|
||||
#endif /* XATTR_MAPPINGS */
|
||||
} else if (!strcmp(opt, "efs_raw")) {
|
||||
if (bogus_option_value(val, "efs_raw"))
|
||||
goto err_exit;
|
||||
ctx->efs_raw = TRUE;
|
||||
#endif /* HAVE_SETXATTR */
|
||||
} else { /* Probably FUSE option. */
|
||||
if (strappend(&ret, opt))
|
||||
goto err_exit;
|
||||
if (val) {
|
||||
if (strappend(&ret, "="))
|
||||
goto err_exit;
|
||||
if (strappend(&ret, val))
|
||||
goto err_exit;
|
||||
}
|
||||
if (strappend(&ret, ","))
|
||||
goto err_exit;
|
||||
}
|
||||
}
|
||||
if (!no_def_opts && strappend(&ret, def_opts))
|
||||
goto err_exit;
|
||||
#if KERNELPERMS
|
||||
if ((default_permissions || permissions)
|
||||
&& strappend(&ret, "default_permissions,"))
|
||||
goto err_exit;
|
||||
#endif
|
||||
|
||||
if (ctx->atime == ATIME_RELATIVE && strappend(&ret, "relatime,"))
|
||||
goto err_exit;
|
||||
else if (ctx->atime == ATIME_ENABLED && strappend(&ret, "atime,"))
|
||||
goto err_exit;
|
||||
else if (ctx->atime == ATIME_DISABLED && strappend(&ret, "noatime,"))
|
||||
goto err_exit;
|
||||
|
||||
if (strappend(&ret, "fsname="))
|
||||
goto err_exit;
|
||||
if (strappend(&ret, opts.device))
|
||||
goto err_exit;
|
||||
if (permissions)
|
||||
ctx->secure_flags |= (1 << SECURITY_DEFAULT);
|
||||
if (want_permissions)
|
||||
ctx->secure_flags |= (1 << SECURITY_WANTED);
|
||||
if (ctx->ro)
|
||||
ctx->secure_flags &= ~(1 << SECURITY_ADDSECURIDS);
|
||||
exit:
|
||||
free(options);
|
||||
return ret;
|
||||
err_exit:
|
||||
free(ret);
|
||||
ret = NULL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
ntfs_log_info(usage_msg, EXEC_NAME, VERSION, FUSE_TYPE, fuse_version(),
|
||||
|
@ -3869,97 +3466,6 @@ static char *realpath(const char *path, char *resolved_path)
|
|||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* parse_options - Read and validate the programs command line
|
||||
* Read the command line, verify the syntax and parse the options.
|
||||
*
|
||||
* Return: 0 success, -1 error.
|
||||
*/
|
||||
static int parse_options(int argc, char *argv[])
|
||||
{
|
||||
int c;
|
||||
|
||||
static const char *sopt = "-o:hnvV";
|
||||
static const struct option lopt[] = {
|
||||
{ "options", required_argument, NULL, 'o' },
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "no-mtab", no_argument, NULL, 'n' },
|
||||
{ "verbose", no_argument, NULL, 'v' },
|
||||
{ "version", no_argument, NULL, 'V' },
|
||||
{ NULL, 0, NULL, 0 }
|
||||
};
|
||||
|
||||
opterr = 0; /* We'll handle the errors, thank you. */
|
||||
|
||||
while ((c = getopt_long(argc, argv, sopt, lopt, NULL)) != -1) {
|
||||
switch (c) {
|
||||
case 1: /* A non-option argument */
|
||||
if (!opts.device) {
|
||||
opts.device = (char*)ntfs_malloc(PATH_MAX + 1);
|
||||
if (!opts.device)
|
||||
return -1;
|
||||
|
||||
/* Canonicalize device name (mtab, etc) */
|
||||
if (!realpath(optarg, opts.device)) {
|
||||
ntfs_log_perror("%s: Failed to access "
|
||||
"volume '%s'", EXEC_NAME, optarg);
|
||||
free(opts.device);
|
||||
opts.device = NULL;
|
||||
return -1;
|
||||
}
|
||||
} else if (!opts.mnt_point) {
|
||||
opts.mnt_point = optarg;
|
||||
} else {
|
||||
ntfs_log_error("%s: You must specify exactly one "
|
||||
"device and exactly one mount "
|
||||
"point.\n", EXEC_NAME);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case 'o':
|
||||
if (opts.options)
|
||||
if (strappend(&opts.options, ","))
|
||||
return -1;
|
||||
if (strappend(&opts.options, optarg))
|
||||
return -1;
|
||||
break;
|
||||
case 'h':
|
||||
usage();
|
||||
exit(9);
|
||||
case 'n':
|
||||
/*
|
||||
* no effect - automount passes it, meaning 'no-mtab'
|
||||
*/
|
||||
break;
|
||||
case 'v':
|
||||
/*
|
||||
* We must handle the 'verbose' option even if
|
||||
* we don't use it because mount(8) passes it.
|
||||
*/
|
||||
break;
|
||||
case 'V':
|
||||
ntfs_log_info("%s %s %s %d\n", EXEC_NAME, VERSION,
|
||||
FUSE_TYPE, fuse_version());
|
||||
exit(0);
|
||||
default:
|
||||
ntfs_log_error("%s: Unknown option '%s'.\n", EXEC_NAME,
|
||||
argv[optind - 1]);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!opts.device) {
|
||||
ntfs_log_error("%s: No device is specified.\n", EXEC_NAME);
|
||||
return -1;
|
||||
}
|
||||
if (!opts.mnt_point) {
|
||||
ntfs_log_error("%s: No mountpoint is specified.\n", EXEC_NAME);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(linux) || defined(__uClinux__)
|
||||
|
||||
static const char *dev_fuse_msg =
|
||||
|
@ -4105,7 +3611,7 @@ static int set_fuseblk_options(char **parsed_options)
|
|||
blksize = pagesize;
|
||||
|
||||
snprintf(options, sizeof(options), ",blkdev,blksize=%u", blksize);
|
||||
if (strappend(parsed_options, options))
|
||||
if (ntfs_strappend(parsed_options, options))
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
@ -4207,7 +3713,7 @@ int main(int argc, char *argv[])
|
|||
ntfs_set_locale();
|
||||
ntfs_log_set_handler(ntfs_log_handler_stderr);
|
||||
|
||||
if (parse_options(argc, argv)) {
|
||||
if (ntfs_parse_options(&opts, usage, argc, argv)) {
|
||||
usage();
|
||||
return NTFS_VOLUME_SYNTAX_ERROR;
|
||||
}
|
||||
|
@ -4217,7 +3723,7 @@ int main(int argc, char *argv[])
|
|||
goto err2;
|
||||
}
|
||||
|
||||
parsed_options = parse_mount_options(opts.options);
|
||||
parsed_options = parse_mount_options(ctx, &opts, TRUE);
|
||||
if (!parsed_options) {
|
||||
err = NTFS_VOLUME_SYNTAX_ERROR;
|
||||
goto err_out;
|
||||
|
@ -4306,15 +3812,17 @@ int main(int argc, char *argv[])
|
|||
if (ntfs_open_secure(ctx->vol) && (ctx->vol->major_ver >= 3))
|
||||
failed_secure = "Could not open file $Secure";
|
||||
if (!ntfs_build_mapping(&ctx->security,ctx->usermap_path,
|
||||
(ctx->vol->secure_flags & (1 << SECURITY_DEFAULT))
|
||||
(ctx->vol->secure_flags
|
||||
& ((1 << SECURITY_DEFAULT) | (1 << SECURITY_ACL)))
|
||||
&& !(ctx->vol->secure_flags & (1 << SECURITY_WANTED)))) {
|
||||
#if POSIXACLS
|
||||
/* use basic permissions if requested */
|
||||
if (ctx->vol->secure_flags & (1 << SECURITY_DEFAULT))
|
||||
permissions_mode = "User mapping built, Posix ACLs not used";
|
||||
else {
|
||||
permissions_mode = "User mapping built, Posix ACLs in use";
|
||||
#if KERNELACLS
|
||||
if (strappend(&parsed_options,
|
||||
if (ntfs_strappend(&parsed_options,
|
||||
",default_permissions,acl")) {
|
||||
err = NTFS_VOLUME_SYNTAX_ERROR;
|
||||
goto err_out;
|
||||
|
@ -4322,14 +3830,15 @@ int main(int argc, char *argv[])
|
|||
#endif /* KERNELACLS */
|
||||
}
|
||||
#else /* POSIXACLS */
|
||||
if (!(ctx->vol->secure_flags & (1 << SECURITY_DEFAULT))) {
|
||||
if (!(ctx->vol->secure_flags
|
||||
& ((1 << SECURITY_DEFAULT) | (1 << SECURITY_ACL)))) {
|
||||
/*
|
||||
* No explicit option but user mapping found
|
||||
* force default security
|
||||
*/
|
||||
#if KERNELPERMS
|
||||
ctx->vol->secure_flags |= (1 << SECURITY_DEFAULT);
|
||||
if (strappend(&parsed_options, ",default_permissions")) {
|
||||
if (ntfs_strappend(&parsed_options, ",default_permissions")) {
|
||||
err = NTFS_VOLUME_SYNTAX_ERROR;
|
||||
goto err_out;
|
||||
}
|
||||
|
@ -4346,7 +3855,7 @@ int main(int argc, char *argv[])
|
|||
if ((ctx->vol->secure_flags & (1 << SECURITY_WANTED))
|
||||
&& !(ctx->vol->secure_flags & (1 << SECURITY_DEFAULT))) {
|
||||
ctx->vol->secure_flags |= (1 << SECURITY_DEFAULT);
|
||||
if (strappend(&parsed_options, ",default_permissions")) {
|
||||
if (ntfs_strappend(&parsed_options, ",default_permissions")) {
|
||||
err = NTFS_VOLUME_SYNTAX_ERROR;
|
||||
goto err_out;
|
||||
}
|
||||
|
|
|
@ -128,6 +128,13 @@ When a user mapping file is defined, the options \fBuid=\fP, \fBgid=\fP,
|
|||
Set standard permissions on created files and use standard access control.
|
||||
This option is set by default when a user mapping file is present.
|
||||
.TP
|
||||
.B acl
|
||||
Enable setting Posix ACLs on created files and use them for access control.
|
||||
This option is only available on specific builds. It is set by default
|
||||
when a user mapping file is present and the
|
||||
.B permissions
|
||||
mount option is not set.
|
||||
.TP
|
||||
.B inherit
|
||||
When creating a new file, set its initial ownership and protections
|
||||
according to inheritance rules defined in parent directory. These rules
|
||||
|
@ -147,6 +154,14 @@ to not be visible.
|
|||
This option is obsolete. It has been superseded by the \fBrecover\fR and
|
||||
\fBnorecover\fR options.
|
||||
.TP
|
||||
.B recover
|
||||
Recover and try to mount a partition which was not unmounted properly by
|
||||
Windows. The Windows logfile is cleared, which may cause inconsistencies.
|
||||
Currently this is the default option.
|
||||
.TP
|
||||
.B norecover
|
||||
Do not try to mount a partition which was not unmounted properly by Windows.
|
||||
.TP
|
||||
.B ignore_case \fP(only with lowntfs-3g)
|
||||
Ignore character case when accessing a file (\fBFOO\fR, \fBFoo\fR, \fBfoo\fR,
|
||||
etc. designate the same file). All files are displayed with lower case in
|
||||
|
@ -157,7 +172,7 @@ Unlike in case of read-only mount, the read-write mount is denied if
|
|||
the NTFS volume is hibernated. One needs either to resume Windows and
|
||||
shutdown it properly, or use this option which will remove the Windows
|
||||
hibernation file. Please note, this means that the saved Windows
|
||||
session will be completely lost. Use this option for your own
|
||||
session will be completely lost. Use this option under your own
|
||||
responsibility.
|
||||
.TP
|
||||
.B atime, noatime, relatime
|
||||
|
|
549
src/ntfs-3g.c
549
src/ntfs-3g.c
|
@ -4,7 +4,7 @@
|
|||
* Copyright (c) 2005-2007 Yura Pakhuchiy
|
||||
* Copyright (c) 2005 Yuval Fledel
|
||||
* Copyright (c) 2006-2009 Szabolcs Szakacsits
|
||||
* Copyright (c) 2007-2010 Jean-Pierre Andre
|
||||
* Copyright (c) 2007-2011 Jean-Pierre Andre
|
||||
* Copyright (c) 2009 Erik Larsson
|
||||
*
|
||||
* This file is originated from the Linux-NTFS project.
|
||||
|
@ -37,12 +37,6 @@
|
|||
#error "***********************************************************"
|
||||
#endif
|
||||
|
||||
#ifdef FUSE_INTERNAL
|
||||
#define FUSE_TYPE "integrated FUSE"
|
||||
#else
|
||||
#define FUSE_TYPE "external FUSE"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STDIO_H
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
@ -68,7 +62,6 @@
|
|||
#ifdef HAVE_LIMITS_H
|
||||
#include <limits.h>
|
||||
#endif
|
||||
#include <getopt.h>
|
||||
#include <syslog.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
|
@ -104,6 +97,8 @@
|
|||
#include "xattrs.h"
|
||||
#include "misc.h"
|
||||
|
||||
#include "ntfs-3g_common.h"
|
||||
|
||||
/*
|
||||
* The following permission checking modes are governed by
|
||||
* the HPERMSCONFIG value in param.h
|
||||
|
@ -138,74 +133,20 @@ typedef enum {
|
|||
FSTYPE_FUSEBLK
|
||||
} fuse_fstype;
|
||||
|
||||
typedef enum {
|
||||
ATIME_ENABLED,
|
||||
ATIME_DISABLED,
|
||||
ATIME_RELATIVE
|
||||
} ntfs_atime_t;
|
||||
|
||||
typedef struct {
|
||||
fuse_fill_dir_t filler;
|
||||
void *buf;
|
||||
} ntfs_fuse_fill_context_t;
|
||||
|
||||
typedef enum {
|
||||
NF_STREAMS_INTERFACE_NONE, /* No access to named data streams. */
|
||||
NF_STREAMS_INTERFACE_XATTR, /* Map named data streams to xattrs. */
|
||||
NF_STREAMS_INTERFACE_OPENXATTR, /* Same, not limited to "user." */
|
||||
NF_STREAMS_INTERFACE_WINDOWS, /* "file:stream" interface. */
|
||||
} ntfs_fuse_streams_interface;
|
||||
|
||||
enum {
|
||||
CLOSE_COMPRESSED = 1,
|
||||
CLOSE_ENCRYPTED = 2
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
ntfs_volume *vol;
|
||||
unsigned int uid;
|
||||
unsigned int gid;
|
||||
unsigned int fmask;
|
||||
unsigned int dmask;
|
||||
ntfs_fuse_streams_interface streams;
|
||||
ntfs_atime_t atime;
|
||||
BOOL ro;
|
||||
BOOL show_sys_files;
|
||||
BOOL hide_hid_files;
|
||||
BOOL hide_dot_files;
|
||||
BOOL windows_names;
|
||||
BOOL compression;
|
||||
BOOL silent;
|
||||
BOOL recover;
|
||||
BOOL hiberfile;
|
||||
BOOL sync;
|
||||
BOOL debug;
|
||||
BOOL no_detach;
|
||||
BOOL blkdev;
|
||||
BOOL mounted;
|
||||
#ifdef HAVE_SETXATTR /* extended attributes interface required */
|
||||
BOOL efs_raw;
|
||||
#ifdef XATTR_MAPPINGS
|
||||
char *xattrmap_path;
|
||||
#endif /* XATTR_MAPPINGS */
|
||||
#endif /* HAVE_SETXATTR */
|
||||
struct fuse_chan *fc;
|
||||
BOOL inherit;
|
||||
unsigned int secure_flags;
|
||||
char *usermap_path;
|
||||
char *abs_mnt_point;
|
||||
struct PERMISSIONS_CACHE *seccache;
|
||||
struct SECURITY_CONTEXT security;
|
||||
} ntfs_fuse_context_t;
|
||||
static struct ntfs_options opts;
|
||||
|
||||
static struct options {
|
||||
char *mnt_point; /* Mount point */
|
||||
char *options; /* Mount options */
|
||||
char *device; /* Device to mount */
|
||||
} opts;
|
||||
const char *EXEC_NAME = "ntfs-3g";
|
||||
|
||||
static const char *EXEC_NAME = "ntfs-3g";
|
||||
static char def_opts[] = "allow_other,nonempty,";
|
||||
static ntfs_fuse_context_t *ctx;
|
||||
static u32 ntfs_sequence;
|
||||
|
||||
|
@ -226,7 +167,7 @@ static const char *usage_msg =
|
|||
"\n"
|
||||
"Copyright (C) 2005-2007 Yura Pakhuchiy\n"
|
||||
"Copyright (C) 2006-2009 Szabolcs Szakacsits\n"
|
||||
"Copyright (C) 2007-2010 Jean-Pierre Andre\n"
|
||||
"Copyright (C) 2007-2011 Jean-Pierre Andre\n"
|
||||
"Copyright (C) 2009 Erik Larsson\n"
|
||||
"\n"
|
||||
"Usage: %s [-o option[,...]] <device|image_file> <mount_point>\n"
|
||||
|
@ -1218,6 +1159,9 @@ static int ntfs_fuse_open(const char *org_path,
|
|||
&& (ni->flags & FILE_ATTR_ENCRYPTED))
|
||||
fi->fh |= CLOSE_ENCRYPTED;
|
||||
#endif /* HAVE_SETXATTR */
|
||||
/* deny opening metadata files for writing */
|
||||
if (ni->mft_no < FILE_first_user)
|
||||
res = -EPERM;
|
||||
}
|
||||
ntfs_attr_close(na);
|
||||
} else
|
||||
|
@ -1429,6 +1373,11 @@ static int ntfs_fuse_trunc(const char *org_path, off_t size,
|
|||
ni = ntfs_pathname_to_inode(ctx->vol, NULL, path);
|
||||
if (!ni)
|
||||
goto exit;
|
||||
/* deny truncating metadata files */
|
||||
if (ni->mft_no < FILE_first_user) {
|
||||
errno = EPERM;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
na = ntfs_attr_open(ni, AT_DATA, stream_name, stream_name_len);
|
||||
if (!na)
|
||||
|
@ -1981,6 +1930,13 @@ static int ntfs_fuse_rm(const char *org_path)
|
|||
res = -errno;
|
||||
goto exit;
|
||||
}
|
||||
/* deny unlinking metadata files */
|
||||
if (ni->mft_no < FILE_first_user) {
|
||||
errno = EPERM;
|
||||
res = -errno;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* Generate unicode filename. */
|
||||
name = strrchr(path, '/');
|
||||
name++;
|
||||
|
@ -2471,17 +2427,6 @@ enum {
|
|||
XATTRNS_OPEN
|
||||
} ;
|
||||
|
||||
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_system_prefix[] = "system.";
|
||||
static const int nf_ns_system_prefix_len = sizeof(nf_ns_system_prefix) - 1;
|
||||
static const char nf_ns_security_prefix[] = "security.";
|
||||
static const int nf_ns_security_prefix_len = sizeof(nf_ns_security_prefix) - 1;
|
||||
static const char nf_ns_trusted_prefix[] = "trusted.";
|
||||
static const int nf_ns_trusted_prefix_len = sizeof(nf_ns_trusted_prefix) - 1;
|
||||
|
||||
static const char xattr_ntfs_3g[] = "ntfs-3g.";
|
||||
|
||||
/*
|
||||
* Check whether access to internal data as an extended
|
||||
* attribute in system name space is allowed
|
||||
|
@ -2648,7 +2593,7 @@ 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)) {
|
||||
ret = ntfs_xattr_listxattr(ni, actx, list, size,
|
||||
ret = ntfs_fuse_listxattr_common(ni, actx, list, size,
|
||||
ctx->streams == NF_STREAMS_INTERFACE_XATTR);
|
||||
if (ret < 0)
|
||||
goto exit;
|
||||
|
@ -3419,346 +3364,6 @@ err_out:
|
|||
|
||||
}
|
||||
|
||||
#define STRAPPEND_MAX_INSIZE 8192
|
||||
#define strappend_is_large(x) ((x) > STRAPPEND_MAX_INSIZE)
|
||||
|
||||
static int strappend(char **dest, const char *append)
|
||||
{
|
||||
char *p;
|
||||
size_t size_append, size_dest = 0;
|
||||
|
||||
if (!dest)
|
||||
return -1;
|
||||
if (!append)
|
||||
return 0;
|
||||
|
||||
size_append = strlen(append);
|
||||
if (*dest)
|
||||
size_dest = strlen(*dest);
|
||||
|
||||
if (strappend_is_large(size_dest) || strappend_is_large(size_append)) {
|
||||
errno = EOVERFLOW;
|
||||
ntfs_log_perror("%s: Too large input buffer", EXEC_NAME);
|
||||
return -1;
|
||||
}
|
||||
|
||||
p = realloc(*dest, size_dest + size_append + 1);
|
||||
if (!p) {
|
||||
ntfs_log_perror("%s: Memory realloction failed", EXEC_NAME);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*dest = p;
|
||||
strcpy(*dest + size_dest, append);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bogus_option_value(char *val, const char *s)
|
||||
{
|
||||
if (val) {
|
||||
ntfs_log_error("'%s' option shouldn't have value.\n", s);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int missing_option_value(char *val, const char *s)
|
||||
{
|
||||
if (!val) {
|
||||
ntfs_log_error("'%s' option should have a value.\n", s);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char *parse_mount_options(const char *orig_opts)
|
||||
{
|
||||
char *options, *s, *opt, *val, *ret = NULL;
|
||||
BOOL no_def_opts = FALSE;
|
||||
int default_permissions = 0;
|
||||
int permissions = 0;
|
||||
int want_permissions = 0;
|
||||
|
||||
ctx->secure_flags = 0;
|
||||
#ifdef HAVE_SETXATTR /* extended attributes interface required */
|
||||
ctx->efs_raw = FALSE;
|
||||
#endif /* HAVE_SETXATTR */
|
||||
ctx->compression = DEFAULT_COMPRESSION;
|
||||
options = strdup(orig_opts ? orig_opts : "");
|
||||
if (!options) {
|
||||
ntfs_log_perror("%s: strdup failed", EXEC_NAME);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
s = options;
|
||||
while (s && *s && (val = strsep(&s, ","))) {
|
||||
opt = strsep(&val, "=");
|
||||
if (!strcmp(opt, "ro")) { /* Read-only mount. */
|
||||
if (bogus_option_value(val, "ro"))
|
||||
goto err_exit;
|
||||
ctx->ro = TRUE;
|
||||
if (strappend(&ret, "ro,"))
|
||||
goto err_exit;
|
||||
} else if (!strcmp(opt, "noatime")) {
|
||||
if (bogus_option_value(val, "noatime"))
|
||||
goto err_exit;
|
||||
ctx->atime = ATIME_DISABLED;
|
||||
} else if (!strcmp(opt, "atime")) {
|
||||
if (bogus_option_value(val, "atime"))
|
||||
goto err_exit;
|
||||
ctx->atime = ATIME_ENABLED;
|
||||
} else if (!strcmp(opt, "relatime")) {
|
||||
if (bogus_option_value(val, "relatime"))
|
||||
goto err_exit;
|
||||
ctx->atime = ATIME_RELATIVE;
|
||||
} else if (!strcmp(opt, "fake_rw")) {
|
||||
if (bogus_option_value(val, "fake_rw"))
|
||||
goto err_exit;
|
||||
ctx->ro = TRUE;
|
||||
} else if (!strcmp(opt, "fsname")) { /* Filesystem name. */
|
||||
/*
|
||||
* We need this to be able to check whether filesystem
|
||||
* mounted or not.
|
||||
*/
|
||||
ntfs_log_error("'fsname' is unsupported option.\n");
|
||||
goto err_exit;
|
||||
} else if (!strcmp(opt, "no_def_opts")) {
|
||||
if (bogus_option_value(val, "no_def_opts"))
|
||||
goto err_exit;
|
||||
no_def_opts = TRUE; /* Don't add default options. */
|
||||
ctx->silent = FALSE; /* cancel default silent */
|
||||
} else if (!strcmp(opt, "default_permissions")) {
|
||||
default_permissions = 1;
|
||||
} else if (!strcmp(opt, "permissions")) {
|
||||
permissions = 1;
|
||||
} else if (!strcmp(opt, "umask")) {
|
||||
if (missing_option_value(val, "umask"))
|
||||
goto err_exit;
|
||||
sscanf(val, "%o", &ctx->fmask);
|
||||
ctx->dmask = ctx->fmask;
|
||||
want_permissions = 1;
|
||||
} else if (!strcmp(opt, "fmask")) {
|
||||
if (missing_option_value(val, "fmask"))
|
||||
goto err_exit;
|
||||
sscanf(val, "%o", &ctx->fmask);
|
||||
want_permissions = 1;
|
||||
} else if (!strcmp(opt, "dmask")) {
|
||||
if (missing_option_value(val, "dmask"))
|
||||
goto err_exit;
|
||||
sscanf(val, "%o", &ctx->dmask);
|
||||
want_permissions = 1;
|
||||
} else if (!strcmp(opt, "uid")) {
|
||||
if (missing_option_value(val, "uid"))
|
||||
goto err_exit;
|
||||
sscanf(val, "%i", &ctx->uid);
|
||||
want_permissions = 1;
|
||||
} else if (!strcmp(opt, "gid")) {
|
||||
if (missing_option_value(val, "gid"))
|
||||
goto err_exit;
|
||||
sscanf(val, "%i", &ctx->gid);
|
||||
want_permissions = 1;
|
||||
} else if (!strcmp(opt, "show_sys_files")) {
|
||||
if (bogus_option_value(val, "show_sys_files"))
|
||||
goto err_exit;
|
||||
ctx->show_sys_files = TRUE;
|
||||
} else if (!strcmp(opt, "hide_hid_files")) {
|
||||
if (bogus_option_value(val, "hide_hid_files"))
|
||||
goto err_exit;
|
||||
ctx->hide_hid_files = TRUE;
|
||||
} else if (!strcmp(opt, "hide_dot_files")) {
|
||||
if (bogus_option_value(val, "hide_dot_files"))
|
||||
goto err_exit;
|
||||
ctx->hide_dot_files = TRUE;
|
||||
} else if (!strcmp(opt, "windows_names")) {
|
||||
if (bogus_option_value(val, "windows_names"))
|
||||
goto err_exit;
|
||||
ctx->windows_names = TRUE;
|
||||
} else if (!strcmp(opt, "compression")) {
|
||||
if (bogus_option_value(val, "compression"))
|
||||
goto err_exit;
|
||||
ctx->compression = TRUE;
|
||||
} else if (!strcmp(opt, "nocompression")) {
|
||||
if (bogus_option_value(val, "nocompression"))
|
||||
goto err_exit;
|
||||
ctx->compression = FALSE;
|
||||
} else if (!strcmp(opt, "silent")) {
|
||||
if (bogus_option_value(val, "silent"))
|
||||
goto err_exit;
|
||||
ctx->silent = TRUE;
|
||||
} else if (!strcmp(opt, "recover")) {
|
||||
if (bogus_option_value(val, "recover"))
|
||||
goto err_exit;
|
||||
ctx->recover = TRUE;
|
||||
} else if (!strcmp(opt, "norecover")) {
|
||||
if (bogus_option_value(val, "norecover"))
|
||||
goto err_exit;
|
||||
ctx->recover = FALSE;
|
||||
} else if (!strcmp(opt, "remove_hiberfile")) {
|
||||
if (bogus_option_value(val, "remove_hiberfile"))
|
||||
goto err_exit;
|
||||
ctx->hiberfile = TRUE;
|
||||
} else if (!strcmp(opt, "sync")) {
|
||||
if (bogus_option_value(val, "sync"))
|
||||
goto err_exit;
|
||||
ctx->sync = TRUE;
|
||||
if (strappend(&ret, "sync,"))
|
||||
goto err_exit;
|
||||
} else if (!strcmp(opt, "locale")) {
|
||||
if (missing_option_value(val, "locale"))
|
||||
goto err_exit;
|
||||
ntfs_set_char_encoding(val);
|
||||
#if defined(__APPLE__) || defined(__DARWIN__)
|
||||
#ifdef ENABLE_NFCONV
|
||||
} else if (!strcmp(opt, "nfconv")) {
|
||||
if (bogus_option_value(val, "nfconv"))
|
||||
goto err_exit;
|
||||
if (ntfs_macosx_normalize_filenames(1)) {
|
||||
ntfs_log_error("ntfs_macosx_normalize_filenames(1) failed!\n");
|
||||
goto err_exit;
|
||||
}
|
||||
} else if (!strcmp(opt, "nonfconv")) {
|
||||
if (bogus_option_value(val, "nonfconv"))
|
||||
goto err_exit;
|
||||
if (ntfs_macosx_normalize_filenames(0)) {
|
||||
ntfs_log_error("ntfs_macosx_normalize_filenames(0) failed!\n");
|
||||
goto err_exit;
|
||||
}
|
||||
#endif /* ENABLE_NFCONV */
|
||||
#endif /* defined(__APPLE__) || defined(__DARWIN__) */
|
||||
} else if (!strcmp(opt, "streams_interface")) {
|
||||
if (missing_option_value(val, "streams_interface"))
|
||||
goto err_exit;
|
||||
if (!strcmp(val, "none"))
|
||||
ctx->streams = NF_STREAMS_INTERFACE_NONE;
|
||||
else if (!strcmp(val, "xattr"))
|
||||
ctx->streams = NF_STREAMS_INTERFACE_XATTR;
|
||||
else if (!strcmp(val, "openxattr"))
|
||||
ctx->streams = NF_STREAMS_INTERFACE_OPENXATTR;
|
||||
else if (!strcmp(val, "windows"))
|
||||
ctx->streams = NF_STREAMS_INTERFACE_WINDOWS;
|
||||
else {
|
||||
ntfs_log_error("Invalid named data streams "
|
||||
"access interface.\n");
|
||||
goto err_exit;
|
||||
}
|
||||
} else if (!strcmp(opt, "user_xattr")) {
|
||||
ctx->streams = NF_STREAMS_INTERFACE_XATTR;
|
||||
} else if (!strcmp(opt, "noauto")) {
|
||||
/* Don't pass noauto option to fuse. */
|
||||
} else if (!strcmp(opt, "debug")) {
|
||||
if (bogus_option_value(val, "debug"))
|
||||
goto err_exit;
|
||||
ctx->debug = TRUE;
|
||||
ntfs_log_set_levels(NTFS_LOG_LEVEL_DEBUG);
|
||||
ntfs_log_set_levels(NTFS_LOG_LEVEL_TRACE);
|
||||
} else if (!strcmp(opt, "no_detach")) {
|
||||
if (bogus_option_value(val, "no_detach"))
|
||||
goto err_exit;
|
||||
ctx->no_detach = TRUE;
|
||||
} else if (!strcmp(opt, "remount")) {
|
||||
ntfs_log_error("Remounting is not supported at present."
|
||||
" You have to umount volume and then "
|
||||
"mount it once again.\n");
|
||||
goto err_exit;
|
||||
} else if (!strcmp(opt, "blksize")) {
|
||||
ntfs_log_info("WARNING: blksize option is ignored "
|
||||
"because ntfs-3g must calculate it.\n");
|
||||
} else if (!strcmp(opt, "inherit")) {
|
||||
/*
|
||||
* JPA do not overwrite inherited permissions
|
||||
* in create()
|
||||
*/
|
||||
ctx->inherit = TRUE;
|
||||
} else if (!strcmp(opt, "addsecurids")) {
|
||||
/*
|
||||
* JPA create security ids for files being read
|
||||
* with an individual security attribute
|
||||
*/
|
||||
ctx->secure_flags |= (1 << SECURITY_ADDSECURIDS);
|
||||
} else if (!strcmp(opt, "staticgrps")) {
|
||||
/*
|
||||
* JPA use static definition of groups
|
||||
* for file access control
|
||||
*/
|
||||
ctx->secure_flags |= (1 << SECURITY_STATICGRPS);
|
||||
} else if (!strcmp(opt, "usermapping")) {
|
||||
if (!val) {
|
||||
ntfs_log_error("'usermapping' option should have "
|
||||
"a value.\n");
|
||||
goto err_exit;
|
||||
}
|
||||
ctx->usermap_path = strdup(val);
|
||||
if (!ctx->usermap_path) {
|
||||
ntfs_log_error("no more memory to store "
|
||||
"'usermapping' option.\n");
|
||||
goto err_exit;
|
||||
}
|
||||
#ifdef HAVE_SETXATTR /* extended attributes interface required */
|
||||
#ifdef XATTR_MAPPINGS
|
||||
} else if (!strcmp(opt, "xattrmapping")) {
|
||||
if (!val) {
|
||||
ntfs_log_error("'xattrmapping' option should have "
|
||||
"a value.\n");
|
||||
goto err_exit;
|
||||
}
|
||||
ctx->xattrmap_path = strdup(val);
|
||||
if (!ctx->xattrmap_path) {
|
||||
ntfs_log_error("no more memory to store "
|
||||
"'xattrmapping' option.\n");
|
||||
goto err_exit;
|
||||
}
|
||||
#endif /* XATTR_MAPPINGS */
|
||||
} else if (!strcmp(opt, "efs_raw")) {
|
||||
if (bogus_option_value(val, "efs_raw"))
|
||||
goto err_exit;
|
||||
ctx->efs_raw = TRUE;
|
||||
#endif /* HAVE_SETXATTR */
|
||||
} else { /* Probably FUSE option. */
|
||||
if (strappend(&ret, opt))
|
||||
goto err_exit;
|
||||
if (val) {
|
||||
if (strappend(&ret, "="))
|
||||
goto err_exit;
|
||||
if (strappend(&ret, val))
|
||||
goto err_exit;
|
||||
}
|
||||
if (strappend(&ret, ","))
|
||||
goto err_exit;
|
||||
}
|
||||
}
|
||||
if (!no_def_opts && strappend(&ret, def_opts))
|
||||
goto err_exit;
|
||||
if ((default_permissions || permissions)
|
||||
&& strappend(&ret, "default_permissions,"))
|
||||
goto err_exit;
|
||||
|
||||
if (ctx->atime == ATIME_RELATIVE && strappend(&ret, "relatime,"))
|
||||
goto err_exit;
|
||||
else if (ctx->atime == ATIME_ENABLED && strappend(&ret, "atime,"))
|
||||
goto err_exit;
|
||||
else if (ctx->atime == ATIME_DISABLED && strappend(&ret, "noatime,"))
|
||||
goto err_exit;
|
||||
|
||||
if (strappend(&ret, "fsname="))
|
||||
goto err_exit;
|
||||
if (strappend(&ret, opts.device))
|
||||
goto err_exit;
|
||||
if (permissions)
|
||||
ctx->secure_flags |= (1 << SECURITY_DEFAULT);
|
||||
if (want_permissions)
|
||||
ctx->secure_flags |= (1 << SECURITY_WANTED);
|
||||
if (ctx->ro)
|
||||
ctx->secure_flags &= ~(1 << SECURITY_ADDSECURIDS);
|
||||
exit:
|
||||
free(options);
|
||||
return ret;
|
||||
err_exit:
|
||||
free(ret);
|
||||
ret = NULL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
ntfs_log_info(usage_msg, EXEC_NAME, VERSION, FUSE_TYPE, fuse_version(),
|
||||
|
@ -3776,97 +3381,6 @@ static char *realpath(const char *path, char *resolved_path)
|
|||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* parse_options - Read and validate the programs command line
|
||||
* Read the command line, verify the syntax and parse the options.
|
||||
*
|
||||
* Return: 0 success, -1 error.
|
||||
*/
|
||||
static int parse_options(int argc, char *argv[])
|
||||
{
|
||||
int c;
|
||||
|
||||
static const char *sopt = "-o:hnvV";
|
||||
static const struct option lopt[] = {
|
||||
{ "options", required_argument, NULL, 'o' },
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "no-mtab", no_argument, NULL, 'n' },
|
||||
{ "verbose", no_argument, NULL, 'v' },
|
||||
{ "version", no_argument, NULL, 'V' },
|
||||
{ NULL, 0, NULL, 0 }
|
||||
};
|
||||
|
||||
opterr = 0; /* We'll handle the errors, thank you. */
|
||||
|
||||
while ((c = getopt_long(argc, argv, sopt, lopt, NULL)) != -1) {
|
||||
switch (c) {
|
||||
case 1: /* A non-option argument */
|
||||
if (!opts.device) {
|
||||
opts.device = ntfs_malloc(PATH_MAX + 1);
|
||||
if (!opts.device)
|
||||
return -1;
|
||||
|
||||
/* Canonicalize device name (mtab, etc) */
|
||||
if (!realpath(optarg, opts.device)) {
|
||||
ntfs_log_perror("%s: Failed to access "
|
||||
"volume '%s'", EXEC_NAME, optarg);
|
||||
free(opts.device);
|
||||
opts.device = NULL;
|
||||
return -1;
|
||||
}
|
||||
} else if (!opts.mnt_point) {
|
||||
opts.mnt_point = optarg;
|
||||
} else {
|
||||
ntfs_log_error("%s: You must specify exactly one "
|
||||
"device and exactly one mount "
|
||||
"point.\n", EXEC_NAME);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case 'o':
|
||||
if (opts.options)
|
||||
if (strappend(&opts.options, ","))
|
||||
return -1;
|
||||
if (strappend(&opts.options, optarg))
|
||||
return -1;
|
||||
break;
|
||||
case 'h':
|
||||
usage();
|
||||
exit(9);
|
||||
case 'n':
|
||||
/*
|
||||
* no effect - automount passes it, meaning 'no-mtab'
|
||||
*/
|
||||
break;
|
||||
case 'v':
|
||||
/*
|
||||
* We must handle the 'verbose' option even if
|
||||
* we don't use it because mount(8) passes it.
|
||||
*/
|
||||
break;
|
||||
case 'V':
|
||||
ntfs_log_info("%s %s %s %d\n", EXEC_NAME, VERSION,
|
||||
FUSE_TYPE, fuse_version());
|
||||
exit(0);
|
||||
default:
|
||||
ntfs_log_error("%s: Unknown option '%s'.\n", EXEC_NAME,
|
||||
argv[optind - 1]);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!opts.device) {
|
||||
ntfs_log_error("%s: No device is specified.\n", EXEC_NAME);
|
||||
return -1;
|
||||
}
|
||||
if (!opts.mnt_point) {
|
||||
ntfs_log_error("%s: No mountpoint is specified.\n", EXEC_NAME);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(linux) || defined(__uClinux__)
|
||||
|
||||
static const char *dev_fuse_msg =
|
||||
|
@ -4012,7 +3526,7 @@ static int set_fuseblk_options(char **parsed_options)
|
|||
blksize = pagesize;
|
||||
|
||||
snprintf(options, sizeof(options), ",blkdev,blksize=%u", blksize);
|
||||
if (strappend(parsed_options, options))
|
||||
if (ntfs_strappend(parsed_options, options))
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
@ -4119,7 +3633,7 @@ int main(int argc, char *argv[])
|
|||
ntfs_set_locale();
|
||||
ntfs_log_set_handler(ntfs_log_handler_stderr);
|
||||
|
||||
if (parse_options(argc, argv)) {
|
||||
if (ntfs_parse_options(&opts, usage, argc, argv)) {
|
||||
usage();
|
||||
return NTFS_VOLUME_SYNTAX_ERROR;
|
||||
}
|
||||
|
@ -4129,7 +3643,7 @@ int main(int argc, char *argv[])
|
|||
goto err2;
|
||||
}
|
||||
|
||||
parsed_options = parse_mount_options(opts.options);
|
||||
parsed_options = parse_mount_options(ctx, &opts, FALSE);
|
||||
if (!parsed_options) {
|
||||
err = NTFS_VOLUME_SYNTAX_ERROR;
|
||||
goto err_out;
|
||||
|
@ -4218,15 +3732,17 @@ int main(int argc, char *argv[])
|
|||
if (ntfs_open_secure(ctx->vol) && (ctx->vol->major_ver >= 3))
|
||||
failed_secure = "Could not open file $Secure";
|
||||
if (!ntfs_build_mapping(&ctx->security,ctx->usermap_path,
|
||||
(ctx->vol->secure_flags & (1 << SECURITY_DEFAULT))
|
||||
(ctx->vol->secure_flags
|
||||
& ((1 << SECURITY_DEFAULT) | (1 << SECURITY_ACL)))
|
||||
&& !(ctx->vol->secure_flags & (1 << SECURITY_WANTED)))) {
|
||||
#if POSIXACLS
|
||||
/* use basic permissions if requested */
|
||||
if (ctx->vol->secure_flags & (1 << SECURITY_DEFAULT))
|
||||
permissions_mode = "User mapping built, Posix ACLs not used";
|
||||
else {
|
||||
permissions_mode = "User mapping built, Posix ACLs in use";
|
||||
#if KERNELACLS
|
||||
if (strappend(&parsed_options, ",default_permissions,acl")) {
|
||||
if (ntfs_strappend(&parsed_options, ",default_permissions,acl")) {
|
||||
err = NTFS_VOLUME_SYNTAX_ERROR;
|
||||
goto err_out;
|
||||
}
|
||||
|
@ -4234,13 +3750,14 @@ int main(int argc, char *argv[])
|
|||
}
|
||||
#else /* POSIXACLS */
|
||||
#if KERNELPERMS
|
||||
if (!(ctx->vol->secure_flags & (1 << SECURITY_DEFAULT))) {
|
||||
if (!(ctx->vol->secure_flags
|
||||
& ((1 << SECURITY_DEFAULT) | (1 << SECURITY_ACL)))) {
|
||||
/*
|
||||
* No explicit option but user mapping found
|
||||
* force default security
|
||||
*/
|
||||
ctx->vol->secure_flags |= (1 << SECURITY_DEFAULT);
|
||||
if (strappend(&parsed_options, ",default_permissions")) {
|
||||
if (ntfs_strappend(&parsed_options, ",default_permissions")) {
|
||||
err = NTFS_VOLUME_SYNTAX_ERROR;
|
||||
goto err_out;
|
||||
}
|
||||
|
@ -4257,7 +3774,7 @@ int main(int argc, char *argv[])
|
|||
if ((ctx->vol->secure_flags & (1 << SECURITY_WANTED))
|
||||
&& !(ctx->vol->secure_flags & (1 << SECURITY_DEFAULT))) {
|
||||
ctx->vol->secure_flags |= (1 << SECURITY_DEFAULT);
|
||||
if (strappend(&parsed_options, ",default_permissions")) {
|
||||
if (ntfs_strappend(&parsed_options, ",default_permissions")) {
|
||||
err = NTFS_VOLUME_SYNTAX_ERROR;
|
||||
goto err_out;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,674 @@
|
|||
/**
|
||||
* ntfs-3g_common.c - Common definitions for ntfs-3g and lowntfs-3g.
|
||||
*
|
||||
* Copyright (c) 2010-2011 Jean-Pierre Andre
|
||||
* Copyright (c) 2010 Erik Larsson
|
||||
*
|
||||
* 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_STDLIB_H
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STRING_H
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ERRNO_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
|
||||
#include <getopt.h>
|
||||
#include <fuse.h>
|
||||
|
||||
#include "inode.h"
|
||||
#include "security.h"
|
||||
#include "xattrs.h"
|
||||
#include "ntfs-3g_common.h"
|
||||
#include "misc.h"
|
||||
|
||||
const char xattr_ntfs_3g[] = "ntfs-3g.";
|
||||
|
||||
const char nf_ns_user_prefix[] = "user.";
|
||||
const int nf_ns_user_prefix_len = sizeof(nf_ns_user_prefix) - 1;
|
||||
const char nf_ns_system_prefix[] = "system.";
|
||||
const int nf_ns_system_prefix_len = sizeof(nf_ns_system_prefix) - 1;
|
||||
const char nf_ns_security_prefix[] = "security.";
|
||||
const int nf_ns_security_prefix_len = sizeof(nf_ns_security_prefix) - 1;
|
||||
const char nf_ns_trusted_prefix[] = "trusted.";
|
||||
const int nf_ns_trusted_prefix_len = sizeof(nf_ns_trusted_prefix) - 1;
|
||||
|
||||
static const char nf_ns_alt_xattr_efsinfo[] = "user.ntfs.efsinfo";
|
||||
|
||||
#ifdef HAVE_SETXATTR
|
||||
|
||||
static const char def_opts[] = "allow_other,nonempty,";
|
||||
|
||||
/*
|
||||
* Table of recognized options
|
||||
* Their order may be significant
|
||||
* The options invalid in some configuration should still
|
||||
* be present, so that an error can be returned
|
||||
*/
|
||||
const struct DEFOPTION optionlist[] = {
|
||||
{ "ro", OPT_RO, FLGOPT_APPEND | FLGOPT_BOGUS },
|
||||
{ "noatime", OPT_NOATIME, FLGOPT_BOGUS },
|
||||
{ "atime", OPT_ATIME, FLGOPT_BOGUS },
|
||||
{ "relatime", OPT_RELATIME, FLGOPT_BOGUS },
|
||||
{ "fake_rw", OPT_FAKE_RW, FLGOPT_BOGUS },
|
||||
{ "fsname", OPT_FSNAME, FLGOPT_NOSUPPORT },
|
||||
{ "no_def_opts", OPT_NO_DEF_OPTS, FLGOPT_BOGUS },
|
||||
{ "default_permissions", OPT_DEFAULT_PERMISSIONS, FLGOPT_BOGUS },
|
||||
{ "permissions", OPT_PERMISSIONS, FLGOPT_BOGUS },
|
||||
{ "acl", OPT_ACL, FLGOPT_BOGUS },
|
||||
{ "umask", OPT_UMASK, FLGOPT_OCTAL },
|
||||
{ "fmask", OPT_FMASK, FLGOPT_OCTAL },
|
||||
{ "dmask", OPT_DMASK, FLGOPT_OCTAL },
|
||||
{ "uid", OPT_UID, FLGOPT_DECIMAL },
|
||||
{ "gid", OPT_GID, FLGOPT_DECIMAL },
|
||||
{ "show_sys_files", OPT_SHOW_SYS_FILES, FLGOPT_BOGUS },
|
||||
{ "hide_hid_files", OPT_HIDE_HID_FILES, FLGOPT_BOGUS },
|
||||
{ "hide_dot_files", OPT_HIDE_DOT_FILES, FLGOPT_BOGUS },
|
||||
{ "ignore_case", OPT_IGNORE_CASE, FLGOPT_BOGUS },
|
||||
{ "windows_names", OPT_WINDOWS_NAMES, FLGOPT_BOGUS },
|
||||
{ "compression", OPT_COMPRESSION, FLGOPT_BOGUS },
|
||||
{ "nocompression", OPT_NOCOMPRESSION, FLGOPT_BOGUS },
|
||||
{ "silent", OPT_SILENT, FLGOPT_BOGUS },
|
||||
{ "recover", OPT_RECOVER, FLGOPT_BOGUS },
|
||||
{ "norecover", OPT_NORECOVER, FLGOPT_BOGUS },
|
||||
{ "remove_hiberfile", OPT_REMOVE_HIBERFILE, FLGOPT_BOGUS },
|
||||
{ "sync", OPT_SYNC, FLGOPT_BOGUS | FLGOPT_APPEND },
|
||||
{ "locale", OPT_LOCALE, FLGOPT_STRING },
|
||||
{ "nfconv", OPT_NFCONV, FLGOPT_BOGUS },
|
||||
{ "nonfconv", OPT_NONFCONV, FLGOPT_BOGUS },
|
||||
{ "streams_interface", OPT_STREAMS_INTERFACE, FLGOPT_STRING },
|
||||
{ "user_xattr", OPT_USER_XATTR, FLGOPT_BOGUS },
|
||||
{ "noauto", OPT_NOAUTO, FLGOPT_BOGUS },
|
||||
{ "debug", OPT_DEBUG, FLGOPT_BOGUS },
|
||||
{ "no_detach", OPT_NO_DETACH, FLGOPT_BOGUS },
|
||||
{ "remount", OPT_REMOUNT, FLGOPT_BOGUS },
|
||||
{ "blksize", OPT_BLKSIZE, FLGOPT_STRING },
|
||||
{ "inherit", OPT_INHERIT, FLGOPT_BOGUS },
|
||||
{ "addsecurids", OPT_ADDSECURIDS, FLGOPT_BOGUS },
|
||||
{ "staticgrps", OPT_STATICGRPS, FLGOPT_BOGUS },
|
||||
{ "usermapping", OPT_USERMAPPING, FLGOPT_STRING },
|
||||
{ "xattrmapping", OPT_XATTRMAPPING, FLGOPT_STRING },
|
||||
{ "efs_raw", OPT_EFS_RAW, FLGOPT_BOGUS },
|
||||
{ (const char*)NULL, 0, 0 } /* end marker */
|
||||
} ;
|
||||
|
||||
#define STRAPPEND_MAX_INSIZE 8192
|
||||
#define strappend_is_large(x) ((x) > STRAPPEND_MAX_INSIZE)
|
||||
|
||||
int ntfs_strappend(char **dest, const char *append)
|
||||
{
|
||||
char *p;
|
||||
size_t size_append, size_dest = 0;
|
||||
|
||||
if (!dest)
|
||||
return -1;
|
||||
if (!append)
|
||||
return 0;
|
||||
|
||||
size_append = strlen(append);
|
||||
if (*dest)
|
||||
size_dest = strlen(*dest);
|
||||
|
||||
if (strappend_is_large(size_dest) || strappend_is_large(size_append)) {
|
||||
errno = EOVERFLOW;
|
||||
ntfs_log_perror("%s: Too large input buffer", EXEC_NAME);
|
||||
return -1;
|
||||
}
|
||||
|
||||
p = (char*)realloc(*dest, size_dest + size_append + 1);
|
||||
if (!p) {
|
||||
ntfs_log_perror("%s: Memory realloction failed", EXEC_NAME);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*dest = p;
|
||||
strcpy(*dest + size_dest, append);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bogus_option_value(char *val, const char *s)
|
||||
{
|
||||
if (val) {
|
||||
ntfs_log_error("'%s' option shouldn't have value.\n", s);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int missing_option_value(char *val, const char *s)
|
||||
{
|
||||
if (!val) {
|
||||
ntfs_log_error("'%s' option should have a value.\n", s);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *parse_mount_options(ntfs_fuse_context_t *ctx,
|
||||
const struct ntfs_options *popts, BOOL low_fuse)
|
||||
{
|
||||
char *options, *s, *opt, *val, *ret = NULL;
|
||||
const char *orig_opts = popts->options;
|
||||
BOOL no_def_opts = FALSE;
|
||||
int default_permissions = 0;
|
||||
int permissions = 0;
|
||||
int acl = 0;
|
||||
int want_permissions = 0;
|
||||
int intarg;
|
||||
const struct DEFOPTION *poptl;
|
||||
|
||||
ctx->secure_flags = 0;
|
||||
#ifdef HAVE_SETXATTR /* extended attributes interface required */
|
||||
ctx->efs_raw = FALSE;
|
||||
#endif /* HAVE_SETXATTR */
|
||||
ctx->compression = DEFAULT_COMPRESSION;
|
||||
ctx->atime = ATIME_ENABLED;
|
||||
options = strdup(orig_opts ? orig_opts : "");
|
||||
if (!options) {
|
||||
ntfs_log_perror("%s: strdup failed", EXEC_NAME);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
s = options;
|
||||
while (s && *s && (val = strsep(&s, ","))) {
|
||||
opt = strsep(&val, "=");
|
||||
poptl = optionlist;
|
||||
while (poptl->name && strcmp(poptl->name,opt))
|
||||
poptl++;
|
||||
if (poptl->name) {
|
||||
if ((poptl->flags & FLGOPT_BOGUS)
|
||||
&& bogus_option_value(val, opt))
|
||||
goto err_exit;
|
||||
if ((poptl->flags & FLGOPT_OCTAL)
|
||||
&& (!val
|
||||
|| !sscanf(val, "%o", &intarg))) {
|
||||
ntfs_log_error("'%s' option needs an octal value\n",
|
||||
opt);
|
||||
goto err_exit;
|
||||
}
|
||||
if ((poptl->flags & FLGOPT_DECIMAL)
|
||||
&& (!val
|
||||
|| !sscanf(val, "%i", &intarg))) {
|
||||
ntfs_log_error("'%s' option needs a decimal value\n",
|
||||
opt);
|
||||
goto err_exit;
|
||||
}
|
||||
if ((poptl->flags & FLGOPT_STRING)
|
||||
&& missing_option_value(val, opt))
|
||||
goto err_exit;
|
||||
|
||||
switch (poptl->type) {
|
||||
case OPT_RO :
|
||||
case OPT_FAKE_RW :
|
||||
ctx->ro = TRUE;
|
||||
break;
|
||||
case OPT_NOATIME :
|
||||
ctx->atime = ATIME_DISABLED;
|
||||
break;
|
||||
case OPT_ATIME :
|
||||
ctx->atime = ATIME_ENABLED;
|
||||
break;
|
||||
case OPT_RELATIME :
|
||||
ctx->atime = ATIME_RELATIVE;
|
||||
break;
|
||||
case OPT_NO_DEF_OPTS :
|
||||
no_def_opts = TRUE; /* Don't add default options. */
|
||||
ctx->silent = FALSE; /* cancel default silent */
|
||||
break;
|
||||
case OPT_DEFAULT_PERMISSIONS :
|
||||
default_permissions = 1;
|
||||
break;
|
||||
case OPT_PERMISSIONS :
|
||||
permissions = 1;
|
||||
break;
|
||||
#if POSIXACLS
|
||||
case OPT_ACL :
|
||||
acl = 1;
|
||||
break;
|
||||
#endif
|
||||
case OPT_UMASK :
|
||||
ctx->dmask = ctx->fmask = intarg;
|
||||
want_permissions = 1;
|
||||
break;
|
||||
case OPT_FMASK :
|
||||
ctx->fmask = intarg;
|
||||
want_permissions = 1;
|
||||
break;
|
||||
case OPT_DMASK :
|
||||
ctx->dmask = intarg;
|
||||
want_permissions = 1;
|
||||
break;
|
||||
case OPT_UID :
|
||||
ctx->uid = intarg;
|
||||
want_permissions = 1;
|
||||
break;
|
||||
case OPT_GID :
|
||||
ctx->gid = intarg;
|
||||
want_permissions = 1;
|
||||
break;
|
||||
case OPT_SHOW_SYS_FILES :
|
||||
ctx->show_sys_files = TRUE;
|
||||
break;
|
||||
case OPT_HIDE_HID_FILES :
|
||||
ctx->hide_hid_files = TRUE;
|
||||
break;
|
||||
case OPT_HIDE_DOT_FILES :
|
||||
ctx->hide_dot_files = TRUE;
|
||||
break;
|
||||
case OPT_WINDOWS_NAMES :
|
||||
ctx->windows_names = TRUE;
|
||||
break;
|
||||
case OPT_IGNORE_CASE :
|
||||
if (low_fuse)
|
||||
ctx->ignore_case = TRUE;
|
||||
else {
|
||||
ntfs_log_error("'%s' is an unsupported option.\n",
|
||||
poptl->name);
|
||||
goto err_exit;
|
||||
}
|
||||
break;
|
||||
case OPT_COMPRESSION :
|
||||
ctx->compression = TRUE;
|
||||
break;
|
||||
case OPT_NOCOMPRESSION :
|
||||
ctx->compression = FALSE;
|
||||
break;
|
||||
case OPT_SILENT :
|
||||
ctx->silent = TRUE;
|
||||
break;
|
||||
case OPT_RECOVER :
|
||||
ctx->recover = TRUE;
|
||||
break;
|
||||
case OPT_NORECOVER :
|
||||
ctx->recover = FALSE;
|
||||
break;
|
||||
case OPT_REMOVE_HIBERFILE :
|
||||
ctx->hiberfile = TRUE;
|
||||
break;
|
||||
case OPT_SYNC :
|
||||
ctx->sync = TRUE;
|
||||
break;
|
||||
case OPT_LOCALE :
|
||||
ntfs_set_char_encoding(val);
|
||||
break;
|
||||
#if defined(__APPLE__) || defined(__DARWIN__)
|
||||
#ifdef ENABLE_NFCONV
|
||||
case OPT_NFCONV :
|
||||
if (ntfs_macosx_normalize_filenames(1)) {
|
||||
ntfs_log_error("ntfs_macosx_normalize_filenames(1) failed!\n");
|
||||
goto err_exit;
|
||||
}
|
||||
break;
|
||||
case OPT_NONFCONV :
|
||||
if (ntfs_macosx_normalize_filenames(0)) {
|
||||
ntfs_log_error("ntfs_macosx_normalize_filenames(0) failed!\n");
|
||||
goto err_exit;
|
||||
}
|
||||
break;
|
||||
#endif /* ENABLE_NFCONV */
|
||||
#endif /* defined(__APPLE__) || defined(__DARWIN__) */
|
||||
case OPT_STREAMS_INTERFACE :
|
||||
if (!strcmp(val, "none"))
|
||||
ctx->streams = NF_STREAMS_INTERFACE_NONE;
|
||||
else if (!strcmp(val, "xattr"))
|
||||
ctx->streams = NF_STREAMS_INTERFACE_XATTR;
|
||||
else if (!strcmp(val, "openxattr"))
|
||||
ctx->streams = NF_STREAMS_INTERFACE_OPENXATTR;
|
||||
else if (!low_fuse && !strcmp(val, "windows"))
|
||||
ctx->streams = NF_STREAMS_INTERFACE_WINDOWS;
|
||||
else {
|
||||
ntfs_log_error("Invalid named data streams "
|
||||
"access interface.\n");
|
||||
goto err_exit;
|
||||
}
|
||||
break;
|
||||
case OPT_USER_XATTR :
|
||||
ctx->streams = NF_STREAMS_INTERFACE_XATTR;
|
||||
break;
|
||||
case OPT_NOAUTO :
|
||||
/* Don't pass noauto option to fuse. */
|
||||
break;
|
||||
case OPT_DEBUG :
|
||||
ctx->debug = TRUE;
|
||||
ntfs_log_set_levels(NTFS_LOG_LEVEL_DEBUG);
|
||||
ntfs_log_set_levels(NTFS_LOG_LEVEL_TRACE);
|
||||
break;
|
||||
case OPT_NO_DETACH :
|
||||
ctx->no_detach = TRUE;
|
||||
break;
|
||||
case OPT_REMOUNT :
|
||||
ntfs_log_error("Remounting is not supported at present."
|
||||
" You have to umount volume and then "
|
||||
"mount it once again.\n");
|
||||
goto err_exit;
|
||||
case OPT_BLKSIZE :
|
||||
ntfs_log_info("WARNING: blksize option is ignored "
|
||||
"because ntfs-3g must calculate it.\n");
|
||||
break;
|
||||
case OPT_INHERIT :
|
||||
/*
|
||||
* do not overwrite inherited permissions
|
||||
* in create()
|
||||
*/
|
||||
ctx->inherit = TRUE;
|
||||
break;
|
||||
case OPT_ADDSECURIDS :
|
||||
/*
|
||||
* create security ids for files being read
|
||||
* with an individual security attribute
|
||||
*/
|
||||
ctx->secure_flags |= (1 << SECURITY_ADDSECURIDS);
|
||||
break;
|
||||
case OPT_STATICGRPS :
|
||||
/*
|
||||
* use static definition of groups
|
||||
* for file access control
|
||||
*/
|
||||
ctx->secure_flags |= (1 << SECURITY_STATICGRPS);
|
||||
break;
|
||||
case OPT_USERMAPPING :
|
||||
ctx->usermap_path = strdup(val);
|
||||
if (!ctx->usermap_path) {
|
||||
ntfs_log_error("no more memory to store "
|
||||
"'usermapping' option.\n");
|
||||
goto err_exit;
|
||||
}
|
||||
break;
|
||||
#ifdef HAVE_SETXATTR /* extended attributes interface required */
|
||||
#ifdef XATTR_MAPPINGS
|
||||
case OPT_XATTRMAPPING :
|
||||
ctx->xattrmap_path = strdup(val);
|
||||
if (!ctx->xattrmap_path) {
|
||||
ntfs_log_error("no more memory to store "
|
||||
"'xattrmapping' option.\n");
|
||||
goto err_exit;
|
||||
}
|
||||
break;
|
||||
#endif /* XATTR_MAPPINGS */
|
||||
case OPT_EFS_RAW :
|
||||
ctx->efs_raw = TRUE;
|
||||
break;
|
||||
#endif /* HAVE_SETXATTR */
|
||||
case OPT_FSNAME : /* Filesystem name. */
|
||||
/*
|
||||
* We need this to be able to check whether filesystem
|
||||
* mounted or not.
|
||||
* (falling through to default)
|
||||
*/
|
||||
default :
|
||||
ntfs_log_error("'%s' is an unsupported option.\n",
|
||||
poptl->name);
|
||||
goto err_exit;
|
||||
}
|
||||
if ((poptl->flags & FLGOPT_APPEND)
|
||||
&& (ntfs_strappend(&ret, poptl->name)
|
||||
|| ntfs_strappend(&ret, ",")))
|
||||
goto err_exit;
|
||||
} else { /* Probably FUSE option. */
|
||||
if (ntfs_strappend(&ret, opt))
|
||||
goto err_exit;
|
||||
if (val) {
|
||||
if (ntfs_strappend(&ret, "="))
|
||||
goto err_exit;
|
||||
if (ntfs_strappend(&ret, val))
|
||||
goto err_exit;
|
||||
}
|
||||
if (ntfs_strappend(&ret, ","))
|
||||
goto err_exit;
|
||||
}
|
||||
}
|
||||
if (!no_def_opts && ntfs_strappend(&ret, def_opts))
|
||||
goto err_exit;
|
||||
if ((default_permissions || (permissions && !acl))
|
||||
&& ntfs_strappend(&ret, "default_permissions,"))
|
||||
goto err_exit;
|
||||
/* The atime options exclude each other */
|
||||
if (ctx->atime == ATIME_RELATIVE && ntfs_strappend(&ret, "relatime,"))
|
||||
goto err_exit;
|
||||
else if (ctx->atime == ATIME_ENABLED && ntfs_strappend(&ret, "atime,"))
|
||||
goto err_exit;
|
||||
else if (ctx->atime == ATIME_DISABLED && ntfs_strappend(&ret, "noatime,"))
|
||||
goto err_exit;
|
||||
|
||||
if (ntfs_strappend(&ret, "fsname="))
|
||||
goto err_exit;
|
||||
if (ntfs_strappend(&ret, popts->device))
|
||||
goto err_exit;
|
||||
if (permissions && !acl)
|
||||
ctx->secure_flags |= (1 << SECURITY_DEFAULT);
|
||||
if (acl)
|
||||
ctx->secure_flags |= (1 << SECURITY_ACL);
|
||||
if (want_permissions)
|
||||
ctx->secure_flags |= (1 << SECURITY_WANTED);
|
||||
if (ctx->ro)
|
||||
ctx->secure_flags &= ~(1 << SECURITY_ADDSECURIDS);
|
||||
exit:
|
||||
free(options);
|
||||
return ret;
|
||||
err_exit:
|
||||
free(ret);
|
||||
ret = NULL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* parse_options - Read and validate the programs command line
|
||||
* Read the command line, verify the syntax and parse the options.
|
||||
*
|
||||
* Return: 0 success, -1 error.
|
||||
*/
|
||||
int ntfs_parse_options(struct ntfs_options *popts, void (*usage)(void),
|
||||
int argc, char *argv[])
|
||||
{
|
||||
int c;
|
||||
|
||||
static const char *sopt = "-o:hnvV";
|
||||
static const struct option lopt[] = {
|
||||
{ "options", required_argument, NULL, 'o' },
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "no-mtab", no_argument, NULL, 'n' },
|
||||
{ "verbose", no_argument, NULL, 'v' },
|
||||
{ "version", no_argument, NULL, 'V' },
|
||||
{ NULL, 0, NULL, 0 }
|
||||
};
|
||||
|
||||
opterr = 0; /* We'll handle the errors, thank you. */
|
||||
|
||||
while ((c = getopt_long(argc, argv, sopt, lopt, NULL)) != -1) {
|
||||
switch (c) {
|
||||
case 1: /* A non-option argument */
|
||||
if (!popts->device) {
|
||||
popts->device = ntfs_malloc(PATH_MAX + 1);
|
||||
if (!popts->device)
|
||||
return -1;
|
||||
|
||||
/* Canonicalize device name (mtab, etc) */
|
||||
if (!realpath(optarg, popts->device)) {
|
||||
ntfs_log_perror("%s: Failed to access "
|
||||
"volume '%s'", EXEC_NAME, optarg);
|
||||
free(popts->device);
|
||||
popts->device = NULL;
|
||||
return -1;
|
||||
}
|
||||
} else if (!popts->mnt_point) {
|
||||
popts->mnt_point = optarg;
|
||||
} else {
|
||||
ntfs_log_error("%s: You must specify exactly one "
|
||||
"device and exactly one mount "
|
||||
"point.\n", EXEC_NAME);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case 'o':
|
||||
if (popts->options)
|
||||
if (ntfs_strappend(&popts->options, ","))
|
||||
return -1;
|
||||
if (ntfs_strappend(&popts->options, optarg))
|
||||
return -1;
|
||||
break;
|
||||
case 'h':
|
||||
usage();
|
||||
exit(9);
|
||||
case 'n':
|
||||
/*
|
||||
* no effect - automount passes it, meaning 'no-mtab'
|
||||
*/
|
||||
break;
|
||||
case 'v':
|
||||
/*
|
||||
* We must handle the 'verbose' option even if
|
||||
* we don't use it because mount(8) passes it.
|
||||
*/
|
||||
break;
|
||||
case 'V':
|
||||
ntfs_log_info("%s %s %s %d\n", EXEC_NAME, VERSION,
|
||||
FUSE_TYPE, fuse_version());
|
||||
exit(0);
|
||||
default:
|
||||
ntfs_log_error("%s: Unknown option '%s'.\n", EXEC_NAME,
|
||||
argv[optind - 1]);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!popts->device) {
|
||||
ntfs_log_error("%s: No device is specified.\n", EXEC_NAME);
|
||||
return -1;
|
||||
}
|
||||
if (!popts->mnt_point) {
|
||||
ntfs_log_error("%s: No mountpoint is specified.\n", EXEC_NAME);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ntfs_fuse_listxattr_common(ntfs_inode *ni, ntfs_attr_search_ctx *actx,
|
||||
char *list, size_t size, BOOL prefixing)
|
||||
{
|
||||
int ret = 0;
|
||||
char *to = list;
|
||||
#ifdef XATTR_MAPPINGS
|
||||
BOOL accepted;
|
||||
const struct XATTRMAPPING *item;
|
||||
#endif /* XATTR_MAPPINGS */
|
||||
|
||||
/* 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);
|
||||
}
|
||||
#ifdef XATTR_MAPPINGS
|
||||
/* now append the system attributes mapped to user space */
|
||||
for (item=ni->vol->xattr_mapping; item; item=item->next) {
|
||||
switch (item->xattr) {
|
||||
case XATTR_NTFS_EFSINFO :
|
||||
accepted = ni->vol->efs_raw
|
||||
&& (ni->flags & FILE_ATTR_ENCRYPTED);
|
||||
break;
|
||||
case XATTR_NTFS_REPARSE_DATA :
|
||||
accepted = (ni->flags & FILE_ATTR_REPARSE_POINT)
|
||||
!= const_cpu_to_le32(0);
|
||||
break;
|
||||
// TODO : we are supposed to only return xattrs which are set
|
||||
// this is more complex for OBJECT_ID and DOS_NAME
|
||||
default : accepted = TRUE;
|
||||
break;
|
||||
}
|
||||
if (accepted) {
|
||||
ret += strlen(item->name) + 1;
|
||||
if (size) {
|
||||
if ((size_t)ret <= size) {
|
||||
strcpy(to, item->name);
|
||||
to += strlen(item->name);
|
||||
*to++ = 0;
|
||||
} else {
|
||||
ret = -ERANGE;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
#else /* XATTR_MAPPINGS */
|
||||
/* List efs info xattr for encrypted files */
|
||||
if (ni->vol->efs_raw && (ni->flags & FILE_ATTR_ENCRYPTED)) {
|
||||
ret += sizeof(nf_ns_alt_xattr_efsinfo);
|
||||
if ((size_t)ret <= size) {
|
||||
memcpy(to, nf_ns_alt_xattr_efsinfo,
|
||||
sizeof(nf_ns_alt_xattr_efsinfo));
|
||||
to += sizeof(nf_ns_alt_xattr_efsinfo);
|
||||
#endif /* XATTR_MAPPINGS */
|
||||
}
|
||||
}
|
||||
exit :
|
||||
return (ret);
|
||||
}
|
||||
|
||||
#endif /* HAVE_SETXATTR */
|
|
@ -0,0 +1,178 @@
|
|||
/*
|
||||
* ntfs-3g_common.h - Common declarations for ntfs-3g and lowntfs-3g.
|
||||
*
|
||||
* Copyright (c) 2010-2011 Jean-Pierre Andre
|
||||
* Copyright (c) 2010 Erik Larsson
|
||||
*
|
||||
* 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_3G_COMMON_H
|
||||
#define _NTFS_3G_COMMON_H
|
||||
|
||||
#include "inode.h"
|
||||
|
||||
struct ntfs_options {
|
||||
char *mnt_point; /* Mount point */
|
||||
char *options; /* Mount options */
|
||||
char *device; /* Device to mount */
|
||||
} ;
|
||||
|
||||
typedef enum {
|
||||
NF_STREAMS_INTERFACE_NONE, /* No access to named data streams. */
|
||||
NF_STREAMS_INTERFACE_XATTR, /* Map named data streams to xattrs. */
|
||||
NF_STREAMS_INTERFACE_OPENXATTR, /* Same, not limited to "user." */
|
||||
NF_STREAMS_INTERFACE_WINDOWS, /* "file:stream" interface. */
|
||||
} ntfs_fuse_streams_interface;
|
||||
|
||||
struct DEFOPTION {
|
||||
const char *name;
|
||||
int type;
|
||||
int flags;
|
||||
} ;
|
||||
/* Options, order not significant */
|
||||
enum {
|
||||
OPT_RO,
|
||||
OPT_NOATIME,
|
||||
OPT_ATIME,
|
||||
OPT_RELATIME,
|
||||
OPT_FAKE_RW,
|
||||
OPT_FSNAME,
|
||||
OPT_NO_DEF_OPTS,
|
||||
OPT_DEFAULT_PERMISSIONS,
|
||||
OPT_PERMISSIONS,
|
||||
OPT_ACL,
|
||||
OPT_UMASK,
|
||||
OPT_FMASK,
|
||||
OPT_DMASK,
|
||||
OPT_UID,
|
||||
OPT_GID,
|
||||
OPT_SHOW_SYS_FILES,
|
||||
OPT_HIDE_HID_FILES,
|
||||
OPT_HIDE_DOT_FILES,
|
||||
OPT_IGNORE_CASE,
|
||||
OPT_WINDOWS_NAMES,
|
||||
OPT_COMPRESSION,
|
||||
OPT_NOCOMPRESSION,
|
||||
OPT_SILENT,
|
||||
OPT_RECOVER,
|
||||
OPT_NORECOVER,
|
||||
OPT_REMOVE_HIBERFILE,
|
||||
OPT_SYNC,
|
||||
OPT_LOCALE,
|
||||
OPT_NFCONV,
|
||||
OPT_NONFCONV,
|
||||
OPT_STREAMS_INTERFACE,
|
||||
OPT_USER_XATTR,
|
||||
OPT_NOAUTO,
|
||||
OPT_DEBUG,
|
||||
OPT_NO_DETACH,
|
||||
OPT_REMOUNT,
|
||||
OPT_BLKSIZE,
|
||||
OPT_INHERIT,
|
||||
OPT_ADDSECURIDS,
|
||||
OPT_STATICGRPS,
|
||||
OPT_USERMAPPING,
|
||||
OPT_XATTRMAPPING,
|
||||
OPT_EFS_RAW,
|
||||
} ;
|
||||
|
||||
/* Option flags */
|
||||
enum {
|
||||
FLGOPT_BOGUS = 1,
|
||||
FLGOPT_STRING = 2,
|
||||
FLGOPT_OCTAL = 4,
|
||||
FLGOPT_DECIMAL = 8,
|
||||
FLGOPT_APPEND = 16,
|
||||
FLGOPT_NOSUPPORT = 32
|
||||
} ;
|
||||
|
||||
typedef enum {
|
||||
ATIME_ENABLED,
|
||||
ATIME_DISABLED,
|
||||
ATIME_RELATIVE
|
||||
} ntfs_atime_t;
|
||||
|
||||
typedef struct {
|
||||
ntfs_volume *vol;
|
||||
unsigned int uid;
|
||||
unsigned int gid;
|
||||
unsigned int fmask;
|
||||
unsigned int dmask;
|
||||
ntfs_fuse_streams_interface streams;
|
||||
ntfs_atime_t atime;
|
||||
BOOL ro;
|
||||
BOOL show_sys_files;
|
||||
BOOL hide_hid_files;
|
||||
BOOL hide_dot_files;
|
||||
BOOL windows_names;
|
||||
BOOL ignore_case;
|
||||
BOOL compression;
|
||||
BOOL acl;
|
||||
BOOL silent;
|
||||
BOOL recover;
|
||||
BOOL hiberfile;
|
||||
BOOL sync;
|
||||
BOOL debug;
|
||||
BOOL no_detach;
|
||||
BOOL blkdev;
|
||||
BOOL mounted;
|
||||
#ifdef HAVE_SETXATTR /* extended attributes interface required */
|
||||
BOOL efs_raw;
|
||||
#ifdef XATTR_MAPPINGS
|
||||
char *xattrmap_path;
|
||||
#endif /* XATTR_MAPPINGS */
|
||||
#endif /* HAVE_SETXATTR */
|
||||
struct fuse_chan *fc;
|
||||
BOOL inherit;
|
||||
unsigned int secure_flags;
|
||||
char *usermap_path;
|
||||
char *abs_mnt_point;
|
||||
struct PERMISSIONS_CACHE *seccache;
|
||||
struct SECURITY_CONTEXT security;
|
||||
struct open_file *open_files; /* only defined in lowntfs-3g */
|
||||
u64 latest_ghost;
|
||||
} ntfs_fuse_context_t;
|
||||
|
||||
extern const char *EXEC_NAME;
|
||||
|
||||
#ifdef FUSE_INTERNAL
|
||||
#define FUSE_TYPE "integrated FUSE"
|
||||
#else
|
||||
#define FUSE_TYPE "external FUSE"
|
||||
#endif
|
||||
|
||||
extern const char xattr_ntfs_3g[];
|
||||
|
||||
extern const char nf_ns_user_prefix[];
|
||||
extern const int nf_ns_user_prefix_len;
|
||||
extern const char nf_ns_system_prefix[];
|
||||
extern const int nf_ns_system_prefix_len;
|
||||
extern const char nf_ns_security_prefix[];
|
||||
extern const int nf_ns_security_prefix_len;
|
||||
extern const char nf_ns_trusted_prefix[];
|
||||
extern const int nf_ns_trusted_prefix_len;
|
||||
|
||||
int ntfs_strappend(char **dest, const char *append);
|
||||
char *parse_mount_options(ntfs_fuse_context_t *ctx,
|
||||
const struct ntfs_options *popts, BOOL low_fuse);
|
||||
int ntfs_parse_options(struct ntfs_options *popts, void (*usage)(void),
|
||||
int argc, char *argv[]);
|
||||
|
||||
int ntfs_fuse_listxattr_common(ntfs_inode *ni, ntfs_attr_search_ctx *actx,
|
||||
char *list, size_t size, BOOL prefixing);
|
||||
|
||||
#endif /* _NTFS_3G_COMMON_H */
|
|
@ -178,6 +178,12 @@
|
|||
*
|
||||
* May 2010, version 1.3.18
|
||||
* - redefined early error logging
|
||||
*
|
||||
* Mar 2011, version 1.3.19
|
||||
* - fixed interface to ntfs_initialize_file_security()
|
||||
*
|
||||
* Apr 2011, version 1.3.20
|
||||
* - fixed false memory leak detection
|
||||
*/
|
||||
|
||||
/*
|
||||
|
@ -201,7 +207,7 @@
|
|||
* General parameters which may have to be adapted to needs
|
||||
*/
|
||||
|
||||
#define AUDT_VERSION "1.3.18"
|
||||
#define AUDT_VERSION "1.3.20"
|
||||
|
||||
#define GET_FILE_SECURITY "ntfs_get_file_security"
|
||||
#define SET_FILE_SECURITY "ntfs_set_file_security"
|
||||
|
@ -343,7 +349,7 @@ int ntfs_get_gsid(void *scapi, gid_t gid, char *buf);
|
|||
int ntfs_get_user(void *scapi, const char *usid);
|
||||
int ntfs_get_group(void *scapi, const char *gsid);
|
||||
|
||||
void *ntfs_initialize_file_security(const char *device, int flags);
|
||||
void *ntfs_initialize_file_security(const char *device, unsigned long flags);
|
||||
BOOL ntfs_leave_file_security(void *scapi);
|
||||
|
||||
#else
|
||||
|
@ -369,7 +375,8 @@ typedef int (*type_get_gsid)(void *scapi, gid_t gid, char *buf);
|
|||
typedef int (*type_get_user)(void *scapi, const char *usid);
|
||||
typedef int (*type_get_group)(void *scapi, const char *gsid);
|
||||
|
||||
typedef void *(*type_initialize_file_security)(const char *device, int flags);
|
||||
typedef void *(*type_initialize_file_security)(const char *device,
|
||||
unsigned long flags);
|
||||
typedef BOOL (*type_leave_file_security)(void *scapi);
|
||||
|
||||
type_get_file_security ntfs_get_file_security;
|
||||
|
@ -400,7 +407,7 @@ type_leave_file_security ntfs_leave_file_security;
|
|||
BOOL open_security_api(void);
|
||||
BOOL close_security_api(void);
|
||||
#ifndef WIN32
|
||||
BOOL open_volume(const char*, int flags);
|
||||
BOOL open_volume(const char*, unsigned long flags);
|
||||
BOOL close_volume(const char*);
|
||||
#endif
|
||||
unsigned int get2l(const char*, int);
|
||||
|
@ -707,7 +714,7 @@ BOOL close_security_api(void)
|
|||
* Assumes a single volume is opened
|
||||
*/
|
||||
|
||||
BOOL open_volume(const char *volume, int flags)
|
||||
BOOL open_volume(const char *volume, unsigned long flags)
|
||||
{
|
||||
BOOL ok;
|
||||
|
||||
|
@ -5011,7 +5018,11 @@ void showfull(const char *fullname, BOOL isdir)
|
|||
| POSIX_ACL_GROUP
|
||||
| POSIX_ACL_MASK))))
|
||||
showposix(pxdesc);
|
||||
#if USESTUBS
|
||||
stdfree(pxdesc); /* allocated within library */
|
||||
#else
|
||||
free(pxdesc);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
if ((opt_r || opt_b) && (securindex < MAXSECURID)
|
||||
|
|
Loading…
Reference in New Issue