mirror of
https://github.com/wiiu-env/libntfs.git
synced 2024-11-05 01:55:06 +01:00
*Update to version 2011.4.12 of NTFS-3G
Change log can be found here: http://www.tuxera.com/community/release-history/
This commit is contained in:
parent
c2d09d1d98
commit
a33b746ad5
143
source/attrib.c
143
source/attrib.c
@ -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);
|
||||
@ -5348,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;
|
||||
|
||||
@ -5361,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);
|
||||
@ -5372,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))) {
|
||||
/*
|
||||
@ -5474,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;
|
||||
@ -5510,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;
|
||||
@ -5616,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;
|
||||
@ -5751,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) {
|
||||
@ -5912,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;
|
||||
}
|
||||
@ -6082,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;
|
||||
@ -6146,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;
|
||||
@ -6217,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
|
||||
@ -6306,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;
|
||||
}
|
||||
@ -6320,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
|
||||
@ -6336,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;
|
||||
@ -6401,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
|
||||
@ -6410,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
|
||||
*
|
||||
@ -6471,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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -1,11 +1,19 @@
|
||||
/* config.h.in. Generated from configure.ac by autoheader. */
|
||||
|
||||
/* Define this to 1 if you want to enable support of encrypted files in
|
||||
libntfs and utilities. */
|
||||
#undef ENABLE_CRYPTO
|
||||
|
||||
/* Define to 1 if debug should be enabled */
|
||||
#undef ENABLE_DEBUG
|
||||
|
||||
/* Define to 1 if the nfconv patch should be enabled */
|
||||
#undef ENABLE_NFCONV
|
||||
|
||||
/* Define this to 1 if you want to enable generation of DCE compliant UUIDs.
|
||||
*/
|
||||
#undef ENABLE_UUID
|
||||
|
||||
/* Define to 1 if using internal fuse */
|
||||
#undef FUSE_INTERNAL
|
||||
|
||||
@ -120,6 +128,9 @@
|
||||
/* Define to 1 if you have the <mntent.h> header file. */
|
||||
#undef HAVE_MNTENT_H
|
||||
|
||||
/* Define to 1 if you have the <pwd.h> header file. */
|
||||
#define HAVE_PWD_H 1
|
||||
|
||||
/* Define to 1 if you have the `realpath' function. */
|
||||
#undef HAVE_REALPATH
|
||||
|
||||
|
@ -112,7 +112,7 @@ static int ntfs_device_gekko_io_open(struct ntfs_device *dev, int flags)
|
||||
}
|
||||
|
||||
// Check that there is a valid NTFS boot sector at the start of the device
|
||||
NTFS_BOOT_SECTOR *boot = (NTFS_BOOT_SECTOR *) ntfs_malloc(MAX_SECTOR_SIZE);
|
||||
NTFS_BOOT_SECTOR *boot = (NTFS_BOOT_SECTOR *) ntfs_alloc(MAX_SECTOR_SIZE);
|
||||
if(boot == NULL) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
|
@ -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.
|
||||
|
@ -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)))
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
*
|
||||
|
@ -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);
|
||||
|
@ -70,7 +70,7 @@
|
||||
#include "misc.h"
|
||||
|
||||
const char *ntfs_home =
|
||||
"Ntfs-3g news, support and information: http://ntfs-3g.org\n";
|
||||
"News, support and information: http://tuxera.com\n";
|
||||
|
||||
static const char *invalid_ntfs_msg =
|
||||
"The device '%s' doesn't seem to have a valid NTFS.\n"
|
||||
@ -113,7 +113,7 @@ static const char *fakeraid_msg =
|
||||
static const char *access_denied_msg =
|
||||
"Please check '%s' and the ntfs-3g binary permissions,\n"
|
||||
"and the mounting user ID. More explanation is provided at\n"
|
||||
"http://ntfs-3g.org/support.html#unprivileged\n";
|
||||
"http://tuxera.com/community/ntfs-3g-faq/#unprivileged\n";
|
||||
|
||||
/**
|
||||
* ntfs_volume_alloc - Create an NTFS volume object and initialise it
|
||||
@ -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:
|
||||
|
@ -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;
|
||||
|
791
source/xattrs.c
Normal file
791
source/xattrs.c
Normal file
@ -0,0 +1,791 @@
|
||||
/**
|
||||
* xattrs.c : common functions to deal with system extended attributes
|
||||
*
|
||||
* Copyright (c) 2010 Jean-Pierre Andre
|
||||
*
|
||||
* This program/include file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as published
|
||||
* by the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program/include file is distributed in the hope that it will be
|
||||
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
|
||||
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program (in the main directory of the NTFS-3G
|
||||
* distribution in the file COPYING); if not, write to the Free Software
|
||||
* Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SETXATTR /* extended attributes support required */
|
||||
|
||||
#ifdef HAVE_STDIO_H
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
#ifdef HAVE_STDLIB_H
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
#ifdef HAVE_STRING_H
|
||||
#include <string.h>
|
||||
#endif
|
||||
#ifdef HAVE_FCNTL_H
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#ifdef HAVE_ERRNO_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
|
||||
#include "types.h"
|
||||
#include "param.h"
|
||||
#include "layout.h"
|
||||
#include "attrib.h"
|
||||
#include "index.h"
|
||||
#include "dir.h"
|
||||
#include "security.h"
|
||||
#include "acls.h"
|
||||
#include "efs.h"
|
||||
#include "reparse.h"
|
||||
#include "object_id.h"
|
||||
#include "misc.h"
|
||||
#include "logging.h"
|
||||
#include "xattrs.h"
|
||||
|
||||
#if POSIXACLS
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
|
||||
/*
|
||||
* Posix ACL structures
|
||||
*/
|
||||
|
||||
struct LE_POSIX_ACE {
|
||||
le16 tag;
|
||||
le16 perms;
|
||||
le32 id;
|
||||
} __attribute__((__packed__));
|
||||
|
||||
struct LE_POSIX_ACL {
|
||||
u8 version;
|
||||
u8 flags;
|
||||
le16 filler;
|
||||
struct LE_POSIX_ACE ace[0];
|
||||
} __attribute__((__packed__));
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
static const char xattr_ntfs_3g[] = "ntfs-3g.";
|
||||
static const char nf_ns_user_prefix[] = "user.";
|
||||
static const int nf_ns_user_prefix_len = sizeof(nf_ns_user_prefix) - 1;
|
||||
|
||||
static const char nf_ns_xattr_ntfs_acl[] = "system.ntfs_acl";
|
||||
static const char nf_ns_xattr_attrib[] = "system.ntfs_attrib";
|
||||
static const char nf_ns_xattr_attrib_be[] = "system.ntfs_attrib_be";
|
||||
static const char nf_ns_xattr_efsinfo[] = "system.ntfs_efsinfo";
|
||||
static const char nf_ns_xattr_reparse[] = "system.ntfs_reparse_data";
|
||||
static const char nf_ns_xattr_object_id[] = "system.ntfs_object_id";
|
||||
static const char nf_ns_xattr_dos_name[] = "system.ntfs_dos_name";
|
||||
static const char nf_ns_xattr_times[] = "system.ntfs_times";
|
||||
static const char nf_ns_xattr_times_be[] = "system.ntfs_times_be";
|
||||
static const char nf_ns_xattr_crtime[] = "system.ntfs_crtime";
|
||||
static const char nf_ns_xattr_crtime_be[] = "system.ntfs_crtime_be";
|
||||
static const char nf_ns_xattr_posix_access[] = "system.posix_acl_access";
|
||||
static const char nf_ns_xattr_posix_default[] = "system.posix_acl_default";
|
||||
|
||||
static const char nf_ns_alt_xattr_efsinfo[] = "user.ntfs.efsinfo";
|
||||
|
||||
struct XATTRNAME {
|
||||
enum SYSTEMXATTRS xattr;
|
||||
const char *name;
|
||||
} ;
|
||||
|
||||
static struct XATTRNAME nf_ns_xattr_names[] = {
|
||||
{ XATTR_NTFS_ACL, nf_ns_xattr_ntfs_acl },
|
||||
{ XATTR_NTFS_ATTRIB, nf_ns_xattr_attrib },
|
||||
{ XATTR_NTFS_ATTRIB_BE, nf_ns_xattr_attrib_be },
|
||||
{ XATTR_NTFS_EFSINFO, nf_ns_xattr_efsinfo },
|
||||
{ XATTR_NTFS_REPARSE_DATA, nf_ns_xattr_reparse },
|
||||
{ XATTR_NTFS_OBJECT_ID, nf_ns_xattr_object_id },
|
||||
{ XATTR_NTFS_DOS_NAME, nf_ns_xattr_dos_name },
|
||||
{ XATTR_NTFS_TIMES, nf_ns_xattr_times },
|
||||
{ XATTR_NTFS_TIMES_BE, nf_ns_xattr_times_be },
|
||||
{ XATTR_NTFS_CRTIME, nf_ns_xattr_crtime },
|
||||
{ XATTR_NTFS_CRTIME_BE, nf_ns_xattr_crtime_be },
|
||||
{ XATTR_POSIX_ACC, nf_ns_xattr_posix_access },
|
||||
{ XATTR_POSIX_DEF, nf_ns_xattr_posix_default },
|
||||
{ XATTR_UNMAPPED, (char*)NULL } /* terminator */
|
||||
};
|
||||
|
||||
/*
|
||||
* Make an integer big-endian
|
||||
*
|
||||
* Swap bytes on a small-endian computer and does nothing on a
|
||||
* big-endian computer.
|
||||
*/
|
||||
|
||||
static void fix_big_endian(char *p, int size)
|
||||
{
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
int i,j;
|
||||
int c;
|
||||
|
||||
i = 0;
|
||||
j = size - 1;
|
||||
while (i < j) {
|
||||
c = p[i];
|
||||
p[i++] = p[j];
|
||||
p[j--] = c;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if POSIXACLS
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
|
||||
/*
|
||||
* Make a Posix ACL CPU endian
|
||||
*/
|
||||
|
||||
static int le_acl_to_cpu(const struct LE_POSIX_ACL *le_acl, size_t size,
|
||||
struct POSIX_ACL *acl)
|
||||
{
|
||||
int i;
|
||||
int cnt;
|
||||
|
||||
acl->version = le_acl->version;
|
||||
acl->flags = le_acl->flags;
|
||||
acl->filler = 0;
|
||||
cnt = (size - sizeof(struct LE_POSIX_ACL)) / sizeof(struct LE_POSIX_ACE);
|
||||
for (i=0; i<cnt; i++) {
|
||||
acl->ace[i].tag = le16_to_cpu(le_acl->ace[i].tag);
|
||||
acl->ace[i].perms = le16_to_cpu(le_acl->ace[i].perms);
|
||||
acl->ace[i].id = le32_to_cpu(le_acl->ace[i].id);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Make a Posix ACL little endian
|
||||
*/
|
||||
|
||||
int cpu_to_le_acl(const struct POSIX_ACL *acl, size_t size,
|
||||
struct LE_POSIX_ACL *le_acl)
|
||||
{
|
||||
int i;
|
||||
int cnt;
|
||||
|
||||
le_acl->version = acl->version;
|
||||
le_acl->flags = acl->flags;
|
||||
le_acl->filler = const_cpu_to_le16(0);
|
||||
cnt = (size - sizeof(struct POSIX_ACL)) / sizeof(struct POSIX_ACE);
|
||||
for (i=0; i<cnt; i++) {
|
||||
le_acl->ace[i].tag = cpu_to_le16(acl->ace[i].tag);
|
||||
le_acl->ace[i].perms = cpu_to_le16(acl->ace[i].perms);
|
||||
le_acl->ace[i].id = cpu_to_le32(acl->ace[i].id);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Determine whether an extended attribute is mapped to
|
||||
* internal data (original name in system namespace, or renamed)
|
||||
*/
|
||||
|
||||
enum SYSTEMXATTRS ntfs_xattr_system_type(const char *name,
|
||||
ntfs_volume *vol)
|
||||
{
|
||||
struct XATTRNAME *p;
|
||||
enum SYSTEMXATTRS ret;
|
||||
#ifdef XATTR_MAPPINGS
|
||||
const struct XATTRMAPPING *q;
|
||||
#endif /* XATTR_MAPPINGS */
|
||||
|
||||
p = nf_ns_xattr_names;
|
||||
while (p->name && strcmp(p->name,name))
|
||||
p++;
|
||||
ret = p->xattr;
|
||||
#ifdef XATTR_MAPPINGS
|
||||
if (!p->name && vol && vol->xattr_mapping) {
|
||||
q = vol->xattr_mapping;
|
||||
while (q && strcmp(q->name,name))
|
||||
q = q->next;
|
||||
if (q)
|
||||
ret = q->xattr;
|
||||
}
|
||||
#else /* XATTR_MAPPINGS */
|
||||
if (!p->name
|
||||
&& vol
|
||||
&& vol->efs_raw
|
||||
&& !strcmp(nf_ns_alt_xattr_efsinfo,name))
|
||||
ret = XATTR_NTFS_EFSINFO;
|
||||
#endif /* XATTR_MAPPINGS */
|
||||
return (ret);
|
||||
}
|
||||
|
||||
#ifdef XATTR_MAPPINGS
|
||||
|
||||
/*
|
||||
* Basic read from a user mapping file on another volume
|
||||
*/
|
||||
|
||||
static int basicread(void *fileid, char *buf, size_t size, off_t offs __attribute__((unused)))
|
||||
{
|
||||
return (read(*(int*)fileid, buf, size));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Read from a user mapping file on current NTFS partition
|
||||
*/
|
||||
|
||||
static int localread(void *fileid, char *buf, size_t size, off_t offs)
|
||||
{
|
||||
return (ntfs_attr_data_read((ntfs_inode*)fileid,
|
||||
AT_UNNAMED, 0, buf, size, offs));
|
||||
}
|
||||
|
||||
/*
|
||||
* Get a single mapping item from buffer
|
||||
*
|
||||
* Always reads a full line, truncating long lines
|
||||
* Refills buffer when exhausted
|
||||
* Returns pointer to item, or NULL when there is no more
|
||||
* Note : errors are logged, but not returned
|
||||
// TODO partially share with acls.c
|
||||
*/
|
||||
|
||||
static struct XATTRMAPPING *getmappingitem(FILEREADER reader, void *fileid,
|
||||
off_t *poffs, char *buf, int *psrc, s64 *psize)
|
||||
{
|
||||
int src;
|
||||
int dst;
|
||||
char *pe;
|
||||
char *ps;
|
||||
char *pu;
|
||||
enum SYSTEMXATTRS xattr;
|
||||
int gotend;
|
||||
char maptext[LINESZ];
|
||||
struct XATTRMAPPING *item;
|
||||
|
||||
src = *psrc;
|
||||
dst = 0;
|
||||
do {
|
||||
gotend = 0;
|
||||
while ((src < *psize)
|
||||
&& (buf[src] != '\n')) {
|
||||
/* ignore spaces */
|
||||
if ((dst < LINESZ)
|
||||
&& (buf[src] != '\r')
|
||||
&& (buf[src] != '\t')
|
||||
&& (buf[src] != ' '))
|
||||
maptext[dst++] = buf[src];
|
||||
src++;
|
||||
}
|
||||
if (src >= *psize) {
|
||||
*poffs += *psize;
|
||||
*psize = reader(fileid, buf, (size_t)BUFSZ, *poffs);
|
||||
src = 0;
|
||||
} else {
|
||||
gotend = 1;
|
||||
src++;
|
||||
maptext[dst] = '\0';
|
||||
dst = 0;
|
||||
}
|
||||
} while (*psize && ((maptext[0] == '#') || !gotend));
|
||||
item = (struct XATTRMAPPING*)NULL;
|
||||
if (gotend) {
|
||||
/* decompose into system name and user name */
|
||||
ps = maptext;
|
||||
pu = strchr(maptext,':');
|
||||
if (pu) {
|
||||
*pu++ = 0;
|
||||
pe = strchr(pu,':');
|
||||
if (pe)
|
||||
*pe = 0;
|
||||
/* check name validity */
|
||||
if ((strlen(pu) < 6) || strncmp(pu,"user.",5))
|
||||
pu = (char*)NULL;
|
||||
xattr = ntfs_xattr_system_type(ps,
|
||||
(ntfs_volume*)NULL);
|
||||
if (xattr == XATTR_UNMAPPED)
|
||||
pu = (char*)NULL;
|
||||
}
|
||||
if (pu) {
|
||||
item = (struct XATTRMAPPING*)ntfs_malloc(
|
||||
sizeof(struct XATTRMAPPING)
|
||||
+ strlen(pu));
|
||||
if (item) {
|
||||
item->xattr = xattr;
|
||||
strcpy(item->name,pu);
|
||||
item->next = (struct XATTRMAPPING*)NULL;
|
||||
}
|
||||
} else {
|
||||
ntfs_log_early_error("Bad xattr mapping item, aborting\n");
|
||||
}
|
||||
}
|
||||
*psrc = src;
|
||||
return (item);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read xattr mapping file and split into their attribute.
|
||||
* Parameters are kept in a chained list.
|
||||
* Returns the head of list, if any
|
||||
* Errors are logged, but not returned
|
||||
*
|
||||
* If an absolute path is provided, the mapping file is assumed
|
||||
* to be located in another mounted file system, and plain read()
|
||||
* are used to get its contents.
|
||||
* If a relative path is provided, the mapping file is assumed
|
||||
* to be located on the current file system, and internal IO
|
||||
* have to be used since we are still mounting and we have not
|
||||
* entered the fuse loop yet.
|
||||
*/
|
||||
|
||||
static struct XATTRMAPPING *ntfs_read_xattr_mapping(FILEREADER reader,
|
||||
void *fileid)
|
||||
{
|
||||
char buf[BUFSZ];
|
||||
struct XATTRMAPPING *item;
|
||||
struct XATTRMAPPING *current;
|
||||
struct XATTRMAPPING *firstitem;
|
||||
struct XATTRMAPPING *lastitem;
|
||||
BOOL duplicated;
|
||||
int src;
|
||||
off_t offs;
|
||||
s64 size;
|
||||
|
||||
firstitem = (struct XATTRMAPPING*)NULL;
|
||||
lastitem = (struct XATTRMAPPING*)NULL;
|
||||
offs = 0;
|
||||
size = reader(fileid, buf, (size_t)BUFSZ, (off_t)0);
|
||||
if (size > 0) {
|
||||
src = 0;
|
||||
do {
|
||||
item = getmappingitem(reader, fileid, &offs,
|
||||
buf, &src, &size);
|
||||
if (item) {
|
||||
/* check no double mapping */
|
||||
duplicated = FALSE;
|
||||
for (current=firstitem; current; current=current->next)
|
||||
if ((current->xattr == item->xattr)
|
||||
|| !strcmp(current->name,item->name))
|
||||
duplicated = TRUE;
|
||||
if (duplicated) {
|
||||
free(item);
|
||||
ntfs_log_early_error("Conflicting xattr mapping ignored\n");
|
||||
} else {
|
||||
item->next = (struct XATTRMAPPING*)NULL;
|
||||
if (lastitem)
|
||||
lastitem->next = item;
|
||||
else
|
||||
firstitem = item;
|
||||
lastitem = item;
|
||||
}
|
||||
}
|
||||
} while (item);
|
||||
}
|
||||
return (firstitem);
|
||||
}
|
||||
|
||||
/*
|
||||
* Build the extended attribute mappings to user namespace
|
||||
*
|
||||
* Note : no error is returned. If we refused mounting when there
|
||||
* is an error it would be too difficult to fix the offending file
|
||||
*/
|
||||
|
||||
struct XATTRMAPPING *ntfs_xattr_build_mapping(ntfs_volume *vol,
|
||||
const char *xattrmap_path)
|
||||
{
|
||||
struct XATTRMAPPING *firstmapping;
|
||||
struct XATTRMAPPING *mapping;
|
||||
BOOL user_efs;
|
||||
BOOL notfound;
|
||||
ntfs_inode *ni;
|
||||
int fd;
|
||||
|
||||
firstmapping = (struct XATTRMAPPING*)NULL;
|
||||
notfound = FALSE;
|
||||
if (!xattrmap_path)
|
||||
xattrmap_path = XATTRMAPPINGFILE;
|
||||
if (xattrmap_path[0] == '/') {
|
||||
fd = open(xattrmap_path,O_RDONLY);
|
||||
if (fd > 0) {
|
||||
firstmapping = ntfs_read_xattr_mapping(basicread, (void*)&fd);
|
||||
close(fd);
|
||||
} else
|
||||
notfound = TRUE;
|
||||
} else {
|
||||
ni = ntfs_pathname_to_inode(vol, NULL, xattrmap_path);
|
||||
if (ni) {
|
||||
firstmapping = ntfs_read_xattr_mapping(localread, ni);
|
||||
ntfs_inode_close(ni);
|
||||
} else
|
||||
notfound = TRUE;
|
||||
}
|
||||
if (notfound && strcmp(xattrmap_path, XATTRMAPPINGFILE)) {
|
||||
ntfs_log_early_error("Could not open \"%s\"\n",xattrmap_path);
|
||||
}
|
||||
if (vol->efs_raw) {
|
||||
user_efs = TRUE;
|
||||
for (mapping=firstmapping; mapping; mapping=mapping->next)
|
||||
if (mapping->xattr == XATTR_NTFS_EFSINFO)
|
||||
user_efs = FALSE;
|
||||
} else
|
||||
user_efs = FALSE;
|
||||
if (user_efs) {
|
||||
mapping = (struct XATTRMAPPING*)ntfs_malloc(
|
||||
sizeof(struct XATTRMAPPING)
|
||||
+ strlen(nf_ns_alt_xattr_efsinfo));
|
||||
if (mapping) {
|
||||
mapping->next = firstmapping;
|
||||
mapping->xattr = XATTR_NTFS_EFSINFO;
|
||||
strcpy(mapping->name,nf_ns_alt_xattr_efsinfo);
|
||||
firstmapping = mapping;
|
||||
}
|
||||
}
|
||||
return (firstmapping);
|
||||
}
|
||||
|
||||
void ntfs_xattr_free_mapping(struct XATTRMAPPING *mapping)
|
||||
{
|
||||
struct XATTRMAPPING *p, *q;
|
||||
|
||||
p = mapping;
|
||||
while (p) {
|
||||
q = p->next;
|
||||
free(p);
|
||||
p = q;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* XATTR_MAPPINGS */
|
||||
|
||||
|
||||
int ntfs_xattr_system_getxattr(struct SECURITY_CONTEXT *scx,
|
||||
enum SYSTEMXATTRS attr,
|
||||
ntfs_inode *ni, ntfs_inode *dir_ni,
|
||||
char *value, size_t size)
|
||||
{
|
||||
int res;
|
||||
int i;
|
||||
#if POSIXACLS
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
struct POSIX_ACL *acl;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* the returned value is the needed
|
||||
* size. If it is too small, no copy
|
||||
* is done, and the caller has to
|
||||
* issue a new call with correct size.
|
||||
*/
|
||||
switch (attr) {
|
||||
case XATTR_NTFS_ACL :
|
||||
res = ntfs_get_ntfs_acl(scx, ni, value, size);
|
||||
break;
|
||||
#if POSIXACLS
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
case XATTR_POSIX_ACC :
|
||||
acl = (struct POSIX_ACL*)ntfs_malloc(size);
|
||||
if (acl) {
|
||||
res = ntfs_get_posix_acl(scx, ni,
|
||||
nf_ns_xattr_posix_access, (char*)acl, size);
|
||||
if (res > 0) {
|
||||
if (cpu_to_le_acl(acl,res,
|
||||
(struct LE_POSIX_ACL*)value))
|
||||
res = -errno;
|
||||
}
|
||||
free(acl);
|
||||
} else
|
||||
res = -errno;
|
||||
break;
|
||||
case XATTR_POSIX_DEF :
|
||||
acl = (struct POSIX_ACL*)ntfs_malloc(size);
|
||||
if (acl) {
|
||||
res = ntfs_get_posix_acl(scx, ni,
|
||||
nf_ns_xattr_posix_default, (char*)acl, size);
|
||||
if (res > 0) {
|
||||
if (cpu_to_le_acl(acl,res,
|
||||
(struct LE_POSIX_ACL*)value))
|
||||
res = -errno;
|
||||
}
|
||||
free(acl);
|
||||
} else
|
||||
res = -errno;
|
||||
break;
|
||||
#else
|
||||
case XATTR_POSIX_ACC :
|
||||
res = ntfs_get_posix_acl(scx, ni, nf_ns_xattr_posix_access,
|
||||
value, size);
|
||||
break;
|
||||
case XATTR_POSIX_DEF :
|
||||
res = ntfs_get_posix_acl(scx, ni, nf_ns_xattr_posix_default,
|
||||
value, size);
|
||||
break;
|
||||
#endif
|
||||
#endif
|
||||
case XATTR_NTFS_ATTRIB :
|
||||
res = ntfs_get_ntfs_attrib(ni, value, size);
|
||||
break;
|
||||
case XATTR_NTFS_ATTRIB_BE :
|
||||
res = ntfs_get_ntfs_attrib(ni, value, size);
|
||||
if ((res == 4) && value) {
|
||||
if (size >= 4)
|
||||
fix_big_endian(value,4);
|
||||
else
|
||||
res = -EINVAL;
|
||||
}
|
||||
break;
|
||||
case XATTR_NTFS_EFSINFO :
|
||||
if (ni->vol->efs_raw)
|
||||
res = ntfs_get_efs_info(ni, value, size);
|
||||
else
|
||||
res = -EPERM;
|
||||
break;
|
||||
case XATTR_NTFS_REPARSE_DATA :
|
||||
res = ntfs_get_ntfs_reparse_data(ni, value, size);
|
||||
break;
|
||||
case XATTR_NTFS_OBJECT_ID :
|
||||
res = ntfs_get_ntfs_object_id(ni, value, size);
|
||||
break;
|
||||
case XATTR_NTFS_DOS_NAME:
|
||||
if (dir_ni)
|
||||
res = ntfs_get_ntfs_dos_name(ni, dir_ni, value, size);
|
||||
else
|
||||
res = -errno;
|
||||
break;
|
||||
case XATTR_NTFS_TIMES:
|
||||
res = ntfs_inode_get_times(ni, value, size);
|
||||
break;
|
||||
case XATTR_NTFS_TIMES_BE:
|
||||
res = ntfs_inode_get_times(ni, value, size);
|
||||
if ((res > 0) && value) {
|
||||
for (i=0; (i+1)*sizeof(u64)<=(unsigned int)res; i++)
|
||||
fix_big_endian(&value[i*sizeof(u64)],
|
||||
sizeof(u64));
|
||||
}
|
||||
break;
|
||||
case XATTR_NTFS_CRTIME:
|
||||
res = ntfs_inode_get_times(ni, value,
|
||||
(size >= sizeof(u64) ? sizeof(u64) : size));
|
||||
break;
|
||||
case XATTR_NTFS_CRTIME_BE:
|
||||
res = ntfs_inode_get_times(ni, value,
|
||||
(size >= sizeof(u64) ? sizeof(u64) : size));
|
||||
if ((res >= (int)sizeof(u64)) && value)
|
||||
fix_big_endian(value,sizeof(u64));
|
||||
break;
|
||||
default :
|
||||
errno = EOPNOTSUPP;
|
||||
res = -errno;
|
||||
break;
|
||||
}
|
||||
return (res);
|
||||
}
|
||||
|
||||
int ntfs_xattr_system_setxattr(struct SECURITY_CONTEXT *scx,
|
||||
enum SYSTEMXATTRS attr,
|
||||
ntfs_inode *ni, ntfs_inode *dir_ni,
|
||||
const char *value, size_t size, int flags)
|
||||
{
|
||||
int res;
|
||||
int i;
|
||||
char buf[4*sizeof(u64)];
|
||||
#if POSIXACLS
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
struct POSIX_ACL *acl;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
switch (attr) {
|
||||
case XATTR_NTFS_ACL :
|
||||
res = ntfs_set_ntfs_acl(scx, ni, value, size, flags);
|
||||
break;
|
||||
#if POSIXACLS
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
case XATTR_POSIX_ACC :
|
||||
acl = (struct POSIX_ACL*)ntfs_malloc(size);
|
||||
if (acl) {
|
||||
if (!le_acl_to_cpu((const struct LE_POSIX_ACL*)value,
|
||||
size, acl)) {
|
||||
res = ntfs_set_posix_acl(scx ,ni ,
|
||||
nf_ns_xattr_posix_access,
|
||||
(char*)acl, size, flags);
|
||||
} else
|
||||
res = -errno;
|
||||
free(acl);
|
||||
} else
|
||||
res = -errno;
|
||||
break;
|
||||
case XATTR_POSIX_DEF :
|
||||
acl = (struct POSIX_ACL*)ntfs_malloc(size);
|
||||
if (acl) {
|
||||
if (!le_acl_to_cpu((const struct LE_POSIX_ACL*)value,
|
||||
size, acl)) {
|
||||
res = ntfs_set_posix_acl(scx ,ni ,
|
||||
nf_ns_xattr_posix_default,
|
||||
(char*)acl, size, flags);
|
||||
} else
|
||||
res = -errno;
|
||||
free(acl);
|
||||
} else
|
||||
res = -errno;
|
||||
break;
|
||||
#else
|
||||
case XATTR_POSIX_ACC :
|
||||
res = ntfs_set_posix_acl(scx ,ni , nf_ns_xattr_posix_access,
|
||||
value, size, flags);
|
||||
break;
|
||||
case XATTR_POSIX_DEF :
|
||||
res = ntfs_set_posix_acl(scx, ni, nf_ns_xattr_posix_default,
|
||||
value, size, flags);
|
||||
break;
|
||||
#endif
|
||||
#endif
|
||||
case XATTR_NTFS_ATTRIB :
|
||||
res = ntfs_set_ntfs_attrib(ni, value, size, flags);
|
||||
break;
|
||||
case XATTR_NTFS_ATTRIB_BE :
|
||||
if (value && (size >= 4)) {
|
||||
memcpy(buf,value,4);
|
||||
fix_big_endian(buf,4);
|
||||
res = ntfs_set_ntfs_attrib(ni, buf, 4, flags);
|
||||
} else
|
||||
res = ntfs_set_ntfs_attrib(ni, value, size, flags);
|
||||
break;
|
||||
case XATTR_NTFS_EFSINFO :
|
||||
if (ni->vol->efs_raw)
|
||||
res = ntfs_set_efs_info(ni, value, size, flags);
|
||||
else
|
||||
res = -EPERM;
|
||||
break;
|
||||
case XATTR_NTFS_REPARSE_DATA :
|
||||
res = ntfs_set_ntfs_reparse_data(ni, value, size, flags);
|
||||
break;
|
||||
case XATTR_NTFS_OBJECT_ID :
|
||||
res = ntfs_set_ntfs_object_id(ni, value, size, flags);
|
||||
break;
|
||||
case XATTR_NTFS_DOS_NAME:
|
||||
if (dir_ni)
|
||||
/* warning : this closes both inodes */
|
||||
res = ntfs_set_ntfs_dos_name(ni, dir_ni, value,
|
||||
size, flags);
|
||||
else
|
||||
res = -errno;
|
||||
break;
|
||||
case XATTR_NTFS_TIMES:
|
||||
res = ntfs_inode_set_times(ni, value, size, flags);
|
||||
break;
|
||||
case XATTR_NTFS_TIMES_BE:
|
||||
if (value && (size > 0) && (size <= 4*sizeof(u64))) {
|
||||
memcpy(buf,value,size);
|
||||
for (i=0; (i+1)*sizeof(u64)<=size; i++)
|
||||
fix_big_endian(&buf[i*sizeof(u64)],
|
||||
sizeof(u64));
|
||||
res = ntfs_inode_set_times(ni, buf, size, flags);
|
||||
} else
|
||||
res = ntfs_inode_set_times(ni, value, size, flags);
|
||||
break;
|
||||
case XATTR_NTFS_CRTIME:
|
||||
res = ntfs_inode_set_times(ni, value,
|
||||
(size >= sizeof(u64) ? sizeof(u64) : size), flags);
|
||||
break;
|
||||
case XATTR_NTFS_CRTIME_BE:
|
||||
if (value && (size >= sizeof(u64))) {
|
||||
memcpy(buf,value,sizeof(u64));
|
||||
fix_big_endian(buf,sizeof(u64));
|
||||
res = ntfs_inode_set_times(ni, buf, sizeof(u64), flags);
|
||||
} else
|
||||
res = ntfs_inode_set_times(ni, value, size, flags);
|
||||
break;
|
||||
default :
|
||||
errno = EOPNOTSUPP;
|
||||
res = -errno;
|
||||
break;
|
||||
}
|
||||
return (res);
|
||||
}
|
||||
|
||||
int ntfs_xattr_system_removexattr(struct SECURITY_CONTEXT *scx,
|
||||
enum SYSTEMXATTRS attr,
|
||||
ntfs_inode *ni, ntfs_inode *dir_ni)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = 0;
|
||||
switch (attr) {
|
||||
/*
|
||||
* Removal of NTFS ACL, ATTRIB, EFSINFO or TIMES
|
||||
* is never allowed
|
||||
*/
|
||||
case XATTR_NTFS_ACL :
|
||||
case XATTR_NTFS_ATTRIB :
|
||||
case XATTR_NTFS_ATTRIB_BE :
|
||||
case XATTR_NTFS_EFSINFO :
|
||||
case XATTR_NTFS_TIMES :
|
||||
case XATTR_NTFS_TIMES_BE :
|
||||
case XATTR_NTFS_CRTIME :
|
||||
case XATTR_NTFS_CRTIME_BE :
|
||||
res = -EPERM;
|
||||
break;
|
||||
#if POSIXACLS
|
||||
case XATTR_POSIX_ACC :
|
||||
case XATTR_POSIX_DEF :
|
||||
if (ni) {
|
||||
if (!ntfs_allowed_as_owner(scx, ni)
|
||||
|| ntfs_remove_posix_acl(scx, ni,
|
||||
(attr == XATTR_POSIX_ACC ?
|
||||
nf_ns_xattr_posix_access :
|
||||
nf_ns_xattr_posix_default)))
|
||||
res = -errno;
|
||||
} else
|
||||
res = -errno;
|
||||
break;
|
||||
#endif
|
||||
case XATTR_NTFS_REPARSE_DATA :
|
||||
if (ni) {
|
||||
if (!ntfs_allowed_as_owner(scx, ni)
|
||||
|| ntfs_remove_ntfs_reparse_data(ni))
|
||||
res = -errno;
|
||||
} else
|
||||
res = -errno;
|
||||
break;
|
||||
case XATTR_NTFS_OBJECT_ID :
|
||||
if (ni) {
|
||||
if (!ntfs_allowed_as_owner(scx, ni)
|
||||
|| ntfs_remove_ntfs_object_id(ni))
|
||||
res = -errno;
|
||||
} else
|
||||
res = -errno;
|
||||
break;
|
||||
case XATTR_NTFS_DOS_NAME:
|
||||
if (ni && dir_ni) {
|
||||
if (ntfs_remove_ntfs_dos_name(ni,dir_ni))
|
||||
res = -errno;
|
||||
/* ni and dir_ni have been closed */
|
||||
} else
|
||||
res = -errno;
|
||||
break;
|
||||
default :
|
||||
errno = EOPNOTSUPP;
|
||||
res = -errno;
|
||||
break;
|
||||
}
|
||||
return (res);
|
||||
}
|
||||
|
||||
#endif /* HAVE_SETXATTR */
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user