*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:
dimok321 2011-05-14 19:20:44 +00:00
parent 86f2292aae
commit c156b4fa1b
16 changed files with 1028 additions and 89 deletions

View File

@ -5,7 +5,7 @@
* Copyright (c) 2002-2005 Richard Russon * Copyright (c) 2002-2005 Richard Russon
* Copyright (c) 2002-2008 Szabolcs Szakacsits * Copyright (c) 2002-2008 Szabolcs Szakacsits
* Copyright (c) 2004-2007 Yura Pakhuchiy * 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 * Copyright (c) 2010 Erik Larsson
* *
* This program/include file is free software; you can redistribute it and/or * 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 last_vcn;
VCN highest_vcn; VCN highest_vcn;
VCN needed; VCN needed;
VCN existing_vcn;
runlist_element *rl; runlist_element *rl;
ATTR_RECORD *a; ATTR_RECORD *a;
BOOL startseen; 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) if (lcn >= 0 || lcn == LCN_HOLE || lcn == LCN_ENOENT)
return 0; return 0;
existing_vcn = (na->rl ? na->rl->vcn : -1);
ctx = ntfs_attr_get_search_ctx(na->ni, NULL); ctx = ntfs_attr_get_search_ctx(na->ni, NULL);
if (!ctx) if (!ctx)
return -1; return -1;
@ -643,6 +646,11 @@ static int ntfs_attr_map_partial_runlist(ntfs_attr *na, VCN vcn)
needed = highest_vcn + 1; needed = highest_vcn + 1;
if (!a->lowest_vcn) if (!a->lowest_vcn)
startseen = TRUE; startseen = TRUE;
/* reaching a previously allocated part ? */
if ((existing_vcn >= 0)
&& (needed >= existing_vcn)) {
needed = last_vcn;
}
} }
} else } else
rl = (runlist_element*)NULL; rl = (runlist_element*)NULL;
@ -1182,12 +1190,27 @@ static int ntfs_attr_fill_zero(ntfs_attr *na, s64 pos, s64 count)
rli++; rli++;
} }
size = min(end - pos, NTFS_BUF_SIZE); size = min(end - pos, NTFS_BUF_SIZE);
written = ntfs_rl_pwrite(vol, rli, ofsi, pos, size, buf); /*
if (written <= 0) { * If the zeroed block is fully within a hole,
ntfs_log_perror("Failed to zero space"); * we need not write anything, so advance as far
goto err_free; * 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; ret = 0;
@ -1711,6 +1734,9 @@ static int borrow_from_hole(ntfs_attr *na, runlist_element **prl,
return (compressed_part); 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 * ntfs_attr_pwrite - positioned write to an ntfs attribute
* @na: ntfs attribute to write to * @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 * attribute to be made temporarily sparse, which
* implies reformating the inode and reorganizing the * implies reformating the inode and reorganizing the
* full runlist. To avoid unnecessary reorganization, * full runlist. To avoid unnecessary reorganization,
* we delay sparse testing until the data is filled in. * we avoid sparse testing until the data is filled in.
*
* Note : should add a specific argument to truncate()
* instead of the hackish test of a flag...
*/ */
if (NAttrDataAppending(na)) if (ntfs_attr_truncate_i(na, pos + count,
NAttrSetDelaySparsing(na); (NAttrDataAppending(na) ?
#endif HOLES_DELAY : HOLES_OK))) {
if (ntfs_attr_truncate(na, pos + count)) {
NAttrClearDelaySparsing(na);
ntfs_log_perror("Failed to enlarge attribute"); ntfs_log_perror("Failed to enlarge attribute");
goto errno_set; 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 */ /* resizing may change the compression mode */
compressed = (na->data_flags & ATTR_COMPRESSION_MASK) compressed = (na->data_flags & ATTR_COMPRESSION_MASK)
!= const_cpu_to_le16(0); != 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. * update allocated and compressed size.
*/ */
static int ntfs_attr_update_meta(ATTR_RECORD *a, ntfs_attr *na, MFT_RECORD *m, 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; 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); a->allocated_size = cpu_to_sle64(na->allocated_size);
/* Update sparse bit, unless this is an intermediate state */ /* 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); sparse = (a->flags & ATTR_IS_SPARSE) != const_cpu_to_le16(0);
else { else {
sparse = ntfs_rl_sparse(na->rl); 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. */ /* Check whether attribute becomes sparse, unless check is delayed. */
if (!NAttrDelaySparsing(na) if ((holes != HOLES_DELAY)
&& sparse && sparse
&& !(a->flags & (ATTR_IS_SPARSE | ATTR_IS_COMPRESSED))) { && !(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 * 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_attr_search_ctx *ctx;
ntfs_inode *ni, *base_ni; ntfs_inode *ni, *base_ni;
@ -5510,7 +5537,7 @@ retry:
* Same if the file was sparse and is not any more. * Same if the file was sparse and is not any more.
* Note : not needed if the full runlist is to be processed * Note : not needed if the full runlist is to be processed
*/ */
if (!NAttrDelaySparsing(na) if ((holes != HOLES_DELAY)
&& (!NAttrFullyMapped(na) || from_vcn) && (!NAttrFullyMapped(na) || from_vcn)
&& !(na->data_flags & ATTR_IS_COMPRESSED)) { && !(na->data_flags & ATTR_IS_COMPRESSED)) {
BOOL changed; BOOL changed;
@ -5616,7 +5643,7 @@ retry:
continue; 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 -1: return -1;
case -2: goto retry; case -2: goto retry;
case -3: goto put_err_out; case -3: goto put_err_out;
@ -5751,34 +5778,6 @@ retry:
goto put_err_out; 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. */ /* Deallocate not used attribute extents and return with success. */
if (finished_build) { if (finished_build) {
@ -5912,7 +5911,7 @@ int ntfs_attr_update_mapping_pairs(ntfs_attr *na, VCN from_vcn)
int ret; int ret;
ntfs_log_enter("Entering\n"); 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"); ntfs_log_leave("\n");
return ret; return ret;
} }
@ -6082,7 +6081,8 @@ put_err_out:
* ERANGE - @newsize is not valid for the attribute type of @na. * ERANGE - @newsize is not valid for the attribute type of @na.
* ENOSPC - There is no enough space in base mft to resize $ATTRIBUTE_LIST. * 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; LCN lcn_seek_from;
VCN first_free_vcn; 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 * If we extend $DATA attribute on NTFS 3+ volume, we can add
* sparse runs instead of real allocation of clusters. * 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); rl = ntfs_malloc(0x1000);
if (!rl) if (!rl)
return -1; 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; na->allocated_size = first_free_vcn << vol->cluster_size_bits;
/* Write mapping pairs for new runlist. */ /* Write mapping pairs for new runlist. */
#if PARTIAL_RUNLIST_UPDATING #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 #else
if (ntfs_attr_update_mapping_pairs(na, 0)) { if (ntfs_attr_update_mapping_pairs(na, 0)) {
#endif #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; int ret;
ntfs_log_enter("Entering\n"); 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"); ntfs_log_leave("\n");
return ret; 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 * ntfs_attr_truncate - resize an ntfs attribute
* @na: open ntfs attribute to resize * @na: open ntfs attribute to resize
* @newsize: new size (in bytes) to which to resize the attribute * @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 * 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 * 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. * EOPNOTSUPP - The desired resize is not implemented yet.
* EACCES - Encrypted attribute. * 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; int ret = STATUS_ERROR;
s64 fullsize; s64 fullsize;
@ -6401,7 +6405,8 @@ int ntfs_attr_truncate(ntfs_attr *na, const s64 newsize)
else else
fullsize = newsize; fullsize = newsize;
if (fullsize > na->data_size) if (fullsize > na->data_size)
ret = ntfs_non_resident_attr_expand(na, fullsize); ret = ntfs_non_resident_attr_expand(na, fullsize,
holes);
else else
ret = ntfs_non_resident_attr_shrink(na, fullsize); ret = ntfs_non_resident_attr_shrink(na, fullsize);
} else } else
@ -6410,7 +6415,25 @@ out:
ntfs_log_leave("Return status %d\n", ret); ntfs_log_leave("Return status %d\n", ret);
return 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 * Stuff a hole in a compressed file
* *
@ -6471,7 +6494,7 @@ static int stuff_hole(ntfs_attr *na, const s64 pos)
if (!ret if (!ret
&& ((na->initialized_size + end_size) < pos) && ((na->initialized_size + end_size) < pos)
&& ntfs_non_resident_attr_expand(na, && ntfs_non_resident_attr_expand(na,
pos - end_size)) pos - end_size, HOLES_OK))
ret = -1; ret = -1;
else else
na->initialized_size na->initialized_size

View File

@ -58,6 +58,12 @@ typedef enum {
LCN_EIO = -5, LCN_EIO = -5,
} ntfs_lcn_special_values; } 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 * struct ntfs_attr_search_ctx - search context used in attribute search functions
* @mrec: buffer containing mft record to search * @mrec: buffer containing mft record to search
@ -203,7 +209,6 @@ typedef enum {
NA_BeingNonResident, /* 1: Attribute is being made not resident. */ NA_BeingNonResident, /* 1: Attribute is being made not resident. */
NA_FullyMapped, /* 1: Attribute has been fully mapped */ NA_FullyMapped, /* 1: Attribute has been fully mapped */
NA_DataAppending, /* 1: Attribute is being appended to */ NA_DataAppending, /* 1: Attribute is being appended to */
NA_DelaySparsing, /* 1: Delay checking attribute being sparse */
NA_ComprClosing, /* 1: Compressed attribute is being closed */ NA_ComprClosing, /* 1: Compressed attribute is being closed */
} ntfs_attr_state_bits; } ntfs_attr_state_bits;
@ -231,10 +236,6 @@ typedef enum {
#define NAttrSetDataAppending(na) set_nattr_flag(na, DataAppending) #define NAttrSetDataAppending(na) set_nattr_flag(na, DataAppending)
#define NAttrClearDataAppending(na) clear_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 NAttrComprClosing(na) test_nattr_flag(na, ComprClosing)
#define NAttrSetComprClosing(na) set_nattr_flag(na, ComprClosing) #define NAttrSetComprClosing(na) set_nattr_flag(na, ComprClosing)
#define NAttrClearComprClosing(na) clear_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_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(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 * get_attribute_value_length - return the length of the value of an attribute

View File

@ -5,7 +5,7 @@
* Copyright (c) 2004-2005 Anton Altaparmakov * Copyright (c) 2004-2005 Anton Altaparmakov
* Copyright (c) 2004-2006 Szabolcs Szakacsits * Copyright (c) 2004-2006 Szabolcs Szakacsits
* Copyright (c) 2005 Yura Pakhuchiy * 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 * 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 * 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 : case 1 :
/* there is a single hole, may have to merge */ /* there is a single hole, may have to merge */
freerl->vcn = freevcn; freerl->vcn = freevcn;
freerl->length = freecnt;
if (freerl[1].lcn == LCN_HOLE) { if (freerl[1].lcn == LCN_HOLE) {
freerl->length += freerl[1].length; freerl->length += freerl[1].length;
erl = freerl; erl = freerl;

View File

@ -1,11 +1,19 @@
/* config.h.in. Generated from configure.ac by autoheader. */ /* 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 */ /* Define to 1 if debug should be enabled */
#undef ENABLE_DEBUG #undef ENABLE_DEBUG
/* Define to 1 if the nfconv patch should be enabled */ /* Define to 1 if the nfconv patch should be enabled */
#undef ENABLE_NFCONV #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 */ /* Define to 1 if using internal fuse */
#undef FUSE_INTERNAL #undef FUSE_INTERNAL
@ -120,6 +128,9 @@
/* Define to 1 if you have the <mntent.h> header file. */ /* Define to 1 if you have the <mntent.h> header file. */
#undef HAVE_MNTENT_H #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. */ /* Define to 1 if you have the `realpath' function. */
#undef HAVE_REALPATH #undef HAVE_REALPATH

View File

@ -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 // 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) { if(boot == NULL) {
errno = ENOMEM; errno = ENOMEM;
return -1; return -1;

View File

@ -1121,6 +1121,7 @@ static int ntfs_ir_reparent(ntfs_index_context *icx)
INDEX_ENTRY *ie; INDEX_ENTRY *ie;
INDEX_BLOCK *ib = NULL; INDEX_BLOCK *ib = NULL;
VCN new_ib_vcn; VCN new_ib_vcn;
int ix_root_size;
int ret = STATUS_ERROR; int ret = STATUS_ERROR;
ntfs_log_trace("Entering\n"); ntfs_log_trace("Entering\n");
@ -1150,6 +1151,7 @@ static int ntfs_ir_reparent(ntfs_index_context *icx)
if (ntfs_ib_write(icx, ib)) if (ntfs_ib_write(icx, ib))
goto clear_bmp; goto clear_bmp;
retry :
ir = ntfs_ir_lookup(icx->ni, icx->name, icx->name_len, &ctx); ir = ntfs_ir_lookup(icx->ni, icx->name, icx->name_len, &ctx);
if (!ir) if (!ir)
goto clear_bmp; 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) ir->index.index_length = cpu_to_le32(le32_to_cpu(ir->index.entries_offset)
+ le16_to_cpu(ie->length)); + le16_to_cpu(ie->length));
ir->index.allocated_size = ir->index.index_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, if (ntfs_resident_attr_value_resize(ctx->mrec, ctx->attr,
sizeof(INDEX_ROOT) - sizeof(INDEX_HEADER) + ix_root_size)) {
le32_to_cpu(ir->index.allocated_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 */ /* FIXME: revert index root */
goto clear_bmp; goto clear_bmp;
}
/* /*
* FIXME: do it earlier if we have enough space in IR (should always), * FIXME: do it earlier if we have enough space in IR (should always),
* so in error case we wouldn't lose the IB. * so in error case we wouldn't lose the IB.

View File

@ -311,6 +311,7 @@ typedef enum {
#define MFT_REF_MASK_LE const_cpu_to_le64(MFT_REF_MASK_CPU) #define MFT_REF_MASK_LE const_cpu_to_le64(MFT_REF_MASK_CPU)
typedef u64 MFT_REF; typedef u64 MFT_REF;
typedef le64 leMFT_REF; /* a little-endian MFT_MREF */
#define MK_MREF(m, s) ((MFT_REF)(((MFT_REF)(s) << 48) | \ #define MK_MREF(m, s) ((MFT_REF)(((MFT_REF)(s) << 48) | \
((MFT_REF)(m) & MFT_REF_MASK_CPU))) ((MFT_REF)(m) & MFT_REF_MASK_CPU)))

View File

@ -200,8 +200,13 @@ static u64 ntfs_fix_file_name(ntfs_inode *dir_ni, ntfschar *uname,
*/ */
lemref = entry->indexed_file; lemref = entry->indexed_file;
mref = le64_to_cpu(lemref); mref = le64_to_cpu(lemref);
for (i=0; i<found->file_name_length; i++) if (NVolCaseSensitive(vol) || !vol->locase) {
uname[i] = found->file_name[i]; 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); ntfs_index_ctx_put(icx);

View File

@ -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, struct SECURITY_API *ntfs_initialize_file_security(const char *device,
int flags) unsigned long flags)
{ {
ntfs_volume *vol; ntfs_volume *vol;
unsigned long mntflag; unsigned long mntflag;

View File

@ -137,6 +137,7 @@ struct PERMISSIONS_CACHE {
enum { enum {
SECURITY_DEFAULT, /* rely on fuse for permissions checking */ SECURITY_DEFAULT, /* rely on fuse for permissions checking */
SECURITY_RAW, /* force same ownership/permissions on files */ SECURITY_RAW, /* force same ownership/permissions on files */
SECURITY_ACL, /* enable Posix ACLs (when compiled in) */
SECURITY_ADDSECURIDS, /* upgrade old security descriptors */ SECURITY_ADDSECURIDS, /* upgrade old security descriptors */
SECURITY_STATICGRPS, /* use static groups for access control */ SECURITY_STATICGRPS, /* use static groups for access control */
SECURITY_WANTED /* a security related option was present */ 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 *ntfs_read_sdh(struct SECURITY_API *scapi,
INDEX_ENTRY *entry); INDEX_ENTRY *entry);
struct SECURITY_API *ntfs_initialize_file_security(const char *device, struct SECURITY_API *ntfs_initialize_file_security(const char *device,
int flags); unsigned long flags);
BOOL ntfs_leave_file_security(struct SECURITY_API *scx); BOOL ntfs_leave_file_security(struct SECURITY_API *scx);
int ntfs_get_usid(struct SECURITY_API *scapi, uid_t uid, char *buf); int ntfs_get_usid(struct SECURITY_API *scapi, uid_t uid, char *buf);

View File

@ -3,7 +3,7 @@
* *
* Copyright (c) 2000-2004 Anton Altaparmakov * Copyright (c) 2000-2004 Anton Altaparmakov
* Copyright (c) 2002-2009 Szabolcs Szakacsits * 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 * Copyright (c) 2008 Bernhard Kaindl
* *
* This program/include file is free software; you can redistribute it and/or * 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) 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 */ static int uc_run_table[][3] = { /* Start, End, Add */
{0x0061, 0x007B, -32}, {0x0451, 0x045D, -80}, {0x1F70, 0x1F72, 74}, {0x0061, 0x007B, -32}, {0x0451, 0x045D, -80}, {0x1F70, 0x1F72, 74},
{0x00E0, 0x00F7, -32}, {0x045E, 0x0460, -80}, {0x1F72, 0x1F76, 86}, {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}, {0x01A8, 0x01A7}, {0x01DD, 0x018E}, {0x0268, 0x0197},
{0} {0}
}; };
#endif /* Vista */
int i, r; int i, r;
int k, off; 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 * Build a table for converting to lower case
* *

View File

@ -61,6 +61,7 @@ extern char *ntfs_uppercase_mbs(const char *low,
const ntfschar *upcase, u32 upcase_len); const ntfschar *upcase, u32 upcase_len);
extern void ntfs_upcase_table_build(ntfschar *uc, u32 uc_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_locase_table_build(const ntfschar *uc, u32 uc_cnt);
extern ntfschar *ntfs_str2ucs(const char *s, int *len); extern ntfschar *ntfs_str2ucs(const char *s, int *len);

View File

@ -70,7 +70,7 @@
#include "misc.h" #include "misc.h"
const char *ntfs_home = 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 = static const char *invalid_ntfs_msg =
"The device '%s' doesn't seem to have a valid NTFS.\n" "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 = static const char *access_denied_msg =
"Please check '%s' and the ntfs-3g binary permissions,\n" "Please check '%s' and the ntfs-3g binary permissions,\n"
"and the mounting user ID. More explanation is provided at\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 * 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; goto error_exit;
/* Create the default upcase table. */ /* Create the default upcase table. */
vol->upcase_len = 65536; vol->upcase_len = ntfs_upcase_build_default(&vol->upcase);
vol->upcase = ntfs_malloc(vol->upcase_len * sizeof(ntfschar)); if (!vol->upcase_len || !vol->upcase)
if (!vol->upcase)
goto error_exit; goto error_exit;
ntfs_upcase_table_build(vol->upcase,
vol->upcase_len * sizeof(ntfschar));
/* Default with no locase table and case sensitive file names */ /* Default with no locase table and case sensitive file names */
vol->locase = (ntfschar*)NULL; vol->locase = (ntfschar*)NULL;
NVolSetCaseSensitive(vol); 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. * Check for dirty logfile and hibernated Windows.
* We care only about read-write mounts. * We care only about read-write mounts.
*/ */
if (!(flags & MS_RDONLY)) { if (!(flags & (MS_RDONLY | MS_FORENSIC))) {
if (!(flags & MS_IGNORE_HIBERFILE) && if (!(flags & MS_IGNORE_HIBERFILE) &&
ntfs_volume_check_hiberfile(vol, 1) < 0) ntfs_volume_check_hiberfile(vol, 1) < 0)
goto error_exit; goto error_exit;
@ -1196,10 +1193,10 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, unsigned long flags)
if (ntfs_logfile_reset(vol)) if (ntfs_logfile_reset(vol))
goto error_exit; goto error_exit;
} }
}
/* make $TXF_DATA resident if present on the root directory */ /* make $TXF_DATA resident if present on the root directory */
if (!NVolReadOnly(vol) && fix_txf_data(vol)) if (fix_txf_data(vol))
goto error_exit; goto error_exit;
}
return vol; return vol;
io_error_exit: io_error_exit:

View File

@ -58,6 +58,7 @@
#endif #endif
#define MS_IGNORE_HIBERFILE 0x20000000 #define MS_IGNORE_HIBERFILE 0x20000000
#define MS_FORENSIC 0x04000000 /* No modification during mount */
/* Forward declaration */ /* Forward declaration */
typedef struct _ntfs_volume ntfs_volume; typedef struct _ntfs_volume ntfs_volume;

791
source/xattrs.c Normal file
View 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 */

View File

@ -59,8 +59,6 @@ void ntfs_xattr_free_mapping(struct XATTRMAPPING*);
enum SYSTEMXATTRS ntfs_xattr_system_type(const char *name, enum SYSTEMXATTRS ntfs_xattr_system_type(const char *name,
ntfs_volume *vol); 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, int ntfs_xattr_system_getxattr(struct SECURITY_CONTEXT *scx,
enum SYSTEMXATTRS attr, enum SYSTEMXATTRS attr,