*Update to version 2011.1.15 of NTFS-3G

Change log can be found here:
http://www.tuxera.com/community/release-history/
This commit is contained in:
dimok321 2011-01-25 21:50:24 +00:00
parent 9ecbdae751
commit 4948b69293
23 changed files with 627 additions and 187 deletions

View File

@ -4,7 +4,7 @@
* This module is part of ntfs-3g library, but may also be
* integrated in tools running over Linux or Windows
*
* Copyright (c) 2007-2009 Jean-Pierre Andre
* Copyright (c) 2007-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
@ -3956,33 +3956,6 @@ static SID *encodesid(const char *sidstr)
return (sid);
}
/*
* Early logging before the logs are redirected
*
* (not quite satisfactory : this appears before the ntfs-g banner,
* and with a different pid)
*/
static void log_early_error(const char *format, ...)
__attribute__((format(printf, 1, 2)));
static void log_early_error(const char *format, ...)
{
va_list args;
va_start(args, format);
#ifdef HAVE_SYSLOG_H
openlog("ntfs-3g", LOG_PID, LOG_USER);
ntfs_log_handler_syslog(NULL, NULL, 0,
NTFS_LOG_LEVEL_ERROR, NULL,
format, args);
#else
vfprintf(stderr,format,args);
#endif
va_end(args);
}
/*
* Get a single mapping item from buffer
*
@ -4045,7 +4018,7 @@ static struct MAPLIST *getmappingitem(FILEREADER reader, void *fileid,
if (pu && pg)
*pu = *pg = '\0';
else {
log_early_error("Bad mapping item \"%s\"\n",
ntfs_log_early_error("Bad mapping item \"%s\"\n",
item->maptext);
free(item);
item = (struct MAPLIST*)NULL;
@ -4174,7 +4147,7 @@ struct MAPPING *ntfs_do_user_mapping(struct MAPLIST *firstitem)
if (pwd)
uid = pwd->pw_uid;
else
log_early_error("Invalid user \"%s\"\n",
ntfs_log_early_error("Invalid user \"%s\"\n",
item->uidstr);
}
}
@ -4254,7 +4227,7 @@ struct MAPPING *ntfs_do_group_mapping(struct MAPLIST *firstitem)
if (grp)
gid = grp->gr_gid;
else
log_early_error("Invalid group \"%s\"\n",
ntfs_log_early_error("Invalid group \"%s\"\n",
item->gidstr);
}
}

View File

@ -402,7 +402,7 @@ ntfs_attr *ntfs_attr_open(ntfs_inode *ni, const ATTR_TYPES type,
ntfs_attr *na = NULL;
ntfschar *newname = NULL;
ATTR_RECORD *a;
BOOL cs;
le16 cs;
ntfs_log_enter("Entering for inode %lld, attr 0x%x.\n",
(unsigned long long)ni->mft_no, type);
@ -588,6 +588,74 @@ int ntfs_attr_map_runlist(ntfs_attr *na, VCN vcn)
return -1;
}
#if PARTIAL_RUNLIST_UPDATING
/*
* Map the runlist of an attribute from some point to the end
*
* Returns 0 if success,
* -1 if it failed (errno telling why)
*/
static int ntfs_attr_map_partial_runlist(ntfs_attr *na, VCN vcn)
{
LCN lcn;
VCN last_vcn;
VCN highest_vcn;
VCN needed;
runlist_element *rl;
ATTR_RECORD *a;
BOOL startseen;
ntfs_attr_search_ctx *ctx;
lcn = ntfs_rl_vcn_to_lcn(na->rl, vcn);
if (lcn >= 0 || lcn == LCN_HOLE || lcn == LCN_ENOENT)
return 0;
ctx = ntfs_attr_get_search_ctx(na->ni, NULL);
if (!ctx)
return -1;
/* Get the last vcn in the attribute. */
last_vcn = na->allocated_size >> na->ni->vol->cluster_size_bits;
needed = vcn;
highest_vcn = 0;
startseen = FALSE;
do {
/* Find the attribute in the mft record. */
if (!ntfs_attr_lookup(na->type, na->name, na->name_len, CASE_SENSITIVE,
needed, NULL, 0, ctx)) {
a = ctx->attr;
/* Decode and merge the runlist. */
rl = ntfs_mapping_pairs_decompress(na->ni->vol, a,
na->rl);
if (rl) {
na->rl = rl;
highest_vcn = le64_to_cpu(a->highest_vcn);
/* corruption detection */
if (((highest_vcn + 1) < last_vcn)
&& ((highest_vcn + 1) <= needed)) {
ntfs_log_error("Corrupt attribute list\n");
rl = (runlist_element*)NULL;
}
needed = highest_vcn + 1;
if (!a->lowest_vcn)
startseen = TRUE;
}
} else
rl = (runlist_element*)NULL;
} while (rl && (needed < last_vcn));
ntfs_attr_put_search_ctx(ctx);
/* mark fully mapped if we did so */
if (rl && startseen)
NAttrSetFullyMapped(na);
return (rl ? 0 : -1);
}
#endif
/**
* ntfs_attr_map_whole_runlist - map the whole runlist of an ntfs attribute
* @na: ntfs attribute for which to map the runlist
@ -1149,9 +1217,27 @@ static int ntfs_attr_fill_hole(ntfs_attr *na, s64 count, s64 *ofs,
"%lld\n", (long long)count, (long long)cur_vcn,
(long long)from_vcn, (long long)to_write, (long long)*ofs);
/* Map whole runlist to be able update mapping pairs later. */
/* Map the runlist to be able to update mapping pairs later. */
#if PARTIAL_RUNLIST_UPDATING
if ((!na->rl
|| !NAttrDataAppending(na))) {
if (ntfs_attr_map_whole_runlist(na))
goto err_out;
} else {
/* make sure the previous non-hole is mapped */
rlc = *rl;
rlc--;
if (((*rl)->lcn == LCN_HOLE)
&& cur_vcn
&& (rlc->vcn < 0)) {
if (ntfs_attr_map_partial_runlist(na, cur_vcn - 1))
goto err_out;
}
}
#else
if (ntfs_attr_map_whole_runlist(na))
goto err_out;
#endif
/* Restore @*rl, it probably get lost during runlist mapping. */
*rl = ntfs_attr_find_vcn(na, cur_vcn);
@ -1510,14 +1596,27 @@ static int borrow_from_hole(ntfs_attr *na, runlist_element **prl,
if (undecided || nothole) {
runlist_element *orl = na->rl;
s64 olcn = (*prl)->lcn;
#if PARTIAL_RUNLIST_UPDATING
VCN prevblock;
#endif
/*
* Map the full runlist (needed to compute the
* compressed size), unless the runlist has not
* yet been created (data just made non-resident)
* Map the runlist, unless it has not been created.
* If appending data, a partial mapping from the
* end of previous block will do.
*/
irl = *prl - na->rl;
#if PARTIAL_RUNLIST_UPDATING
prevblock = pos >> cluster_size_bits;
if (prevblock)
prevblock--;
if (!NAttrBeingNonResident(na)
&& (NAttrDataAppending(na)
? ntfs_attr_map_partial_runlist(na,prevblock)
: ntfs_attr_map_whole_runlist(na))) {
#else
if (!NAttrBeingNonResident(na)
&& ntfs_attr_map_whole_runlist(na)) {
#endif
rl = (runlist_element*)NULL;
} else {
/*
@ -1649,6 +1748,7 @@ s64 ntfs_attr_pwrite(ntfs_attr *na, const s64 pos, s64 count, const void *b)
} need_to = { 0, 0 };
BOOL wasnonresident = FALSE;
BOOL compressed;
BOOL sparse;
BOOL updatemap;
ntfs_log_enter("Entering for inode %lld, attr 0x%x, pos 0x%llx, count "
@ -1703,16 +1803,38 @@ s64 ntfs_attr_pwrite(ntfs_attr *na, const s64 pos, s64 count, const void *b)
fullcount = count;
/* If the write reaches beyond the end, extend the attribute. */
old_data_size = na->data_size;
/* identify whether this is appending to a non resident data attribute */
if ((na->type == AT_DATA) && (pos >= old_data_size)
&& NAttrNonResident(na))
NAttrSetDataAppending(na);
if (pos + count > na->data_size) {
#if PARTIAL_RUNLIST_UPDATING
/*
* When appending data, the attribute is first extended
* before being filled with data. This may cause the
* 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...
*/
if (NAttrDataAppending(na))
NAttrSetDelaySparsing(na);
#endif
if (ntfs_attr_truncate(na, pos + count)) {
NAttrClearDelaySparsing(na);
ntfs_log_perror("Failed to enlarge attribute");
goto errno_set;
}
NAttrClearDelaySparsing(na);
/* resizing may change the compression mode */
compressed = (na->data_flags & ATTR_COMPRESSION_MASK)
!= const_cpu_to_le16(0);
need_to.undo_data_size = 1;
}
sparse = (na->data_flags & ATTR_IS_SPARSE) != const_cpu_to_le16(0);
/*
* For compressed data, a single full block was allocated
* to deal with compression, possibly in a previous call.
@ -1768,8 +1890,29 @@ s64 ntfs_attr_pwrite(ntfs_attr *na, const s64 pos, s64 count, const void *b)
/* Handle writes beyond initialized_size. */
if (pos + count > na->initialized_size) {
if (ntfs_attr_map_whole_runlist(na))
goto err_out;
#if PARTIAL_RUNLIST_UPDATING
/*
* When appending, we only need to map the end of the runlist,
* starting at the last previously allocated run, so that
* we are able a new one to it.
* However, for compressed file, we need the full compression
* block, which may be split in several extents.
*/
if (NAttrDataAppending(na)) {
VCN block_begin = pos >> vol->cluster_size_bits;
if (compressed)
block_begin &= -na->compression_block_clusters;
if (block_begin)
block_begin--;
if (ntfs_attr_map_partial_runlist(na, block_begin))
goto err_out;
if ((update_from == -1) || (block_begin < update_from))
update_from = block_begin;
} else
#endif
if (ntfs_attr_map_whole_runlist(na))
goto err_out;
/*
* For a compressed attribute, we must be sure there is an
* available entry, and, when reopening a compressed file,
@ -2046,8 +2189,12 @@ done:
* of the mapping list. This makes a difference only if
* inode extents were needed.
*/
#if PARTIAL_RUNLIST_UPDATING
updatemap = NAttrFullyMapped(na) || NAttrDataAppending(na);
#else
updatemap = (compressed
? NAttrFullyMapped(na) != 0 : update_from != -1);
#endif
if (updatemap)
if (ntfs_attr_update_mapping_pairs(na,
(update_from < 0 ? 0 : update_from))) {
@ -4864,6 +5011,15 @@ static int ntfs_resident_attr_resize_i(ntfs_attr *na, const s64 newsize,
ntfs_attr_close(tna);
continue;
}
if ((tna->type == AT_DATA) && !tna->name_len) {
/*
* If we had to make the unnamed data attribute
* non-resident, propagate its new allocated size
* to all name attributes and directory indexes
*/
tna->ni->allocated_size = tna->allocated_size;
NInoFileNameSetDirty(tna->ni);
}
if (((tna->data_flags & ATTR_COMPRESSION_MASK)
== ATTR_IS_COMPRESSED)
&& ntfs_attr_pclose(tna)) {
@ -5204,15 +5360,21 @@ 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. */
sparse = ntfs_rl_sparse(na->rl);
if (sparse == -1) {
errno = EIO;
goto error;
/* Update sparse bit, unless this is an intermediate state */
if (NAttrDelaySparsing(na))
sparse = (a->flags & ATTR_IS_SPARSE) != const_cpu_to_le16(0);
else {
sparse = ntfs_rl_sparse(na->rl);
if (sparse == -1) {
errno = EIO;
goto error;
}
}
/* Attribute become sparse. */
if (sparse && !(a->flags & (ATTR_IS_SPARSE | ATTR_IS_COMPRESSED))) {
/* Check whether attribute becomes sparse, unless check is delayed. */
if (!NAttrDelaySparsing(na)
&& sparse
&& !(a->flags & (ATTR_IS_SPARSE | ATTR_IS_COMPRESSED))) {
/*
* Move attribute to another mft record, if attribute is too
* small to add compressed_size field to it and we have no
@ -5245,6 +5407,7 @@ static int ntfs_attr_update_meta(ATTR_RECORD *a, ntfs_attr *na, MFT_RECORD *m,
NAttrSetSparse(na);
a->flags |= ATTR_IS_SPARSE;
na->data_flags = a->flags;
a->compression_unit = STANDARD_COMPRESSION_UNIT; /* Windows
set it so, even if attribute is not actually compressed. */
@ -5278,7 +5441,8 @@ static int ntfs_attr_update_meta(ATTR_RECORD *a, ntfs_attr *na, MFT_RECORD *m,
}
/* Update compressed size if required. */
if (sparse || (na->data_flags & ATTR_COMPRESSION_MASK)) {
if (NAttrFullyMapped(na)
&& (sparse || (na->data_flags & ATTR_COMPRESSION_MASK))) {
s64 new_compr_size;
new_compr_size = ntfs_rl_get_compressed_size(na->ni->vol, na->rl);
@ -5338,6 +5502,59 @@ retry:
return -1;
}
#if PARTIAL_RUNLIST_UPDATING
/*
* For a file just been made sparse, we will have
* to reformat the first extent, so be sure the
* runlist is fully mapped and fully processed.
* 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)
&& (!NAttrFullyMapped(na) || from_vcn)
&& !(na->data_flags & ATTR_IS_COMPRESSED)) {
BOOL changed;
if (!(na->data_flags & ATTR_IS_SPARSE)) {
int sparse;
runlist_element *xrl;
/*
* If attribute was not sparse, we only
* have to check whether there is a hole
* in the updated region.
*/
xrl = na->rl;
if (xrl->lcn == LCN_RL_NOT_MAPPED)
xrl++;
sparse = ntfs_rl_sparse(xrl);
if (sparse < 0) {
ntfs_log_error("Could not check whether sparse\n");
errno = EIO;
return (-1);
}
changed = sparse > 0;
} else {
/*
* If attribute was sparse, the compressed
* size has been maintained, and it gives
* and easy way to check whether the
* attribute is still sparse.
*/
changed = (((na->data_size - 1)
| (na->ni->vol->cluster_size - 1)) + 1)
== na->compressed_size;
}
if (changed) {
if (ntfs_attr_map_whole_runlist(na)) {
ntfs_log_error("Could not map whole for sparse change\n");
errno = EIO;
return (-1);
}
from_vcn = 0;
}
}
#endif
if (na->ni->nr_extents == -1)
base_ni = na->ni->base_ni;
else
@ -5534,6 +5751,34 @@ 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) {
@ -5864,6 +6109,8 @@ static int ntfs_non_resident_attr_expand_i(ntfs_attr *na, const s64 newsize)
return -1;
}
if (na->type == AT_DATA)
NAttrSetDataAppending(na);
/* Save for future use. */
org_alloc_size = na->allocated_size;
/* The first cluster outside the new allocation. */
@ -5874,10 +6121,26 @@ static int ntfs_non_resident_attr_expand_i(ntfs_attr *na, const s64 newsize)
* clusters if there is a change.
*/
if ((na->allocated_size >> vol->cluster_size_bits) < first_free_vcn) {
#if PARTIAL_RUNLIST_UPDATING
s64 start_update;
/*
* Update from the last previously allocated run,
* as we may have to expand an existing hole.
*/
start_update = na->allocated_size >> vol->cluster_size_bits;
if (start_update)
start_update--;
if (ntfs_attr_map_partial_runlist(na, start_update)) {
ntfs_log_perror("failed to map partial runlist");
return -1;
}
#else
if (ntfs_attr_map_whole_runlist(na)) {
ntfs_log_perror("ntfs_attr_map_whole_runlist failed");
return -1;
}
#endif
/*
* If we extend $DATA attribute on NTFS 3+ volume, we can add
@ -5953,8 +6216,11 @@ static int ntfs_non_resident_attr_expand_i(ntfs_attr *na, const s64 newsize)
/* Prepare to mapping pairs update. */
na->allocated_size = first_free_vcn << vol->cluster_size_bits;
/* Write mapping pairs for new runlist. */
if (ntfs_attr_update_mapping_pairs(na, 0 /*na->allocated_size >>
vol->cluster_size_bits*/)) {
#if PARTIAL_RUNLIST_UPDATING
if (ntfs_attr_update_mapping_pairs(na, start_update)) {
#else
if (ntfs_attr_update_mapping_pairs(na, 0)) {
#endif
err = errno;
ntfs_log_perror("Mapping pairs update failed");
goto rollback;
@ -6285,6 +6551,89 @@ err_exit:
return ret;
}
/*
* Read some data from a data attribute
*
* Returns the amount of data read, negative if there was an error
*/
int ntfs_attr_data_read(ntfs_inode *ni,
ntfschar *stream_name, int stream_name_len,
char *buf, size_t size, off_t offset)
{
ntfs_attr *na = NULL;
int res, total = 0;
na = ntfs_attr_open(ni, AT_DATA, stream_name, stream_name_len);
if (!na) {
res = -errno;
goto exit;
}
if ((size_t)offset < (size_t)na->data_size) {
if (offset + size > (size_t)na->data_size)
size = na->data_size - offset;
while (size) {
res = ntfs_attr_pread(na, offset, size, buf + total);
if ((off_t)res < (off_t)size)
ntfs_log_perror("ntfs_attr_pread partial read "
"(%lld : %lld <> %d)",
(long long)offset,
(long long)size, res);
if (res <= 0) {
res = -errno;
goto exit;
}
size -= res;
offset += res;
total += res;
}
}
res = total;
exit:
if (na)
ntfs_attr_close(na);
return res;
}
/*
* Write some data into a data attribute
*
* Returns the amount of data written, negative if there was an error
*/
int ntfs_attr_data_write(ntfs_inode *ni,
ntfschar *stream_name, int stream_name_len,
char *buf, size_t size, off_t offset)
{
ntfs_attr *na = NULL;
int res, total = 0;
na = ntfs_attr_open(ni, AT_DATA, stream_name, stream_name_len);
if (!na) {
res = -errno;
goto exit;
}
while (size) {
res = ntfs_attr_pwrite(na, offset, size, buf + total);
if (res < (s64)size)
ntfs_log_perror("ntfs_attr_pwrite partial write (%lld: "
"%lld <> %d)", (long long)offset,
(long long)size, res);
if (res <= 0) {
res = -errno;
goto exit;
}
size -= res;
offset += res;
total += res;
}
res = total;
exit:
if (na)
ntfs_attr_close(na);
return res;
}
int ntfs_attr_exist(ntfs_inode *ni, const ATTR_TYPES type, ntfschar *name,

View File

@ -4,6 +4,7 @@
* Copyright (c) 2000-2004 Anton Altaparmakov
* Copyright (c) 2004-2005 Yura Pakhuchiy
* Copyright (c) 2006-2007 Szabolcs Szakacsits
* 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
@ -201,6 +202,8 @@ typedef enum {
NA_NonResident, /* 1: Attribute is not resident. */
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;
@ -224,6 +227,14 @@ typedef enum {
#define NAttrSetFullyMapped(na) set_nattr_flag(na, FullyMapped)
#define NAttrClearFullyMapped(na) clear_nattr_flag(na, FullyMapped)
#define NAttrDataAppending(na) test_nattr_flag(na, DataAppending)
#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)
@ -370,6 +381,12 @@ extern int ntfs_attr_exist(ntfs_inode *ni, const ATTR_TYPES type,
extern int ntfs_attr_remove(ntfs_inode *ni, const ATTR_TYPES type,
ntfschar *name, u32 name_len);
extern s64 ntfs_attr_get_free_bits(ntfs_attr *na);
extern int ntfs_attr_data_read(ntfs_inode *ni,
ntfschar *stream_name, int stream_name_len,
char *buf, size_t size, off_t offset);
extern int ntfs_attr_data_write(ntfs_inode *ni,
ntfschar *stream_name, int stream_name_len,
char *buf, size_t size, off_t offset);
#endif /* defined _NTFS_ATTRIB_H */

View File

@ -1,7 +1,7 @@
/**
* cache.c : deal with LRU caches
*
* Copyright (c) 2008-2009 Jean-Pierre Andre
* Copyright (c) 2008-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
@ -298,7 +298,7 @@ struct CACHED_GENERIC *ntfs_enter_cache(struct CACHE_HEADER *cache,
if (cache->most_recent_entry)
cache->most_recent_entry->previous = current;
cache->most_recent_entry = current;
memcpy(current->fixed, item->fixed, cache->fixed_size);
memcpy(current->payload, item->payload, cache->fixed_size);
if (item->varsize) {
if (current->variable) {
memcpy(current->variable,

View File

@ -1,7 +1,7 @@
/*
* cache.h : deal with indexed LRU caches
*
* Copyright (c) 2008-2009 Jean-Pierre Andre
* Copyright (c) 2008-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
@ -29,11 +29,7 @@ struct CACHED_GENERIC {
struct CACHED_GENERIC *previous;
void *variable;
size_t varsize;
union {
/* force alignment for pointers and u64 */
u64 u64align;
void *ptralign;
} fixed[0];
union ALIGNMENT payload[0];
} ;
struct CACHED_INODE {
@ -41,6 +37,7 @@ struct CACHED_INODE {
struct CACHED_INODE *previous;
const char *pathname;
size_t varsize;
union ALIGNMENT payload[0];
/* above fields must match "struct CACHED_GENERIC" */
u64 inum;
} ;
@ -50,6 +47,7 @@ struct CACHED_NIDATA {
struct CACHED_NIDATA *previous;
const char *pathname; /* not used */
size_t varsize; /* not used */
union ALIGNMENT payload[0];
/* above fields must match "struct CACHED_GENERIC" */
u64 inum;
ntfs_inode *ni;
@ -60,6 +58,7 @@ struct CACHED_LOOKUP {
struct CACHED_LOOKUP *previous;
const char *name;
size_t namesize;
union ALIGNMENT payload[0];
/* above fields must match "struct CACHED_GENERIC" */
u64 parent;
u64 inum;

View File

@ -62,6 +62,10 @@
#include "logging.h"
#include "misc.h"
#undef le16_to_cpup
/* the standard le16_to_cpup() crashes for unaligned data on some processors */
#define le16_to_cpup(p) (*(u8*)(p) + (((u8*)(p))[1] << 8))
/**
* enum ntfs_compression_constants - constants used in the compression code
*/

View File

@ -298,13 +298,13 @@
#define PACKAGE_NAME "ntfs-3g"
/* Define to the full name and version of this package. */
#define PACKAGE_STRING "ntfs-3g 2010.8.8"
#define PACKAGE_STRING "ntfs-3g 2011.1.15"
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "ntfs-3g"
/* Define to the version of this package. */
#define PACKAGE_VERSION "2010.8.8"
#define PACKAGE_VERSION "2011.1.15"
/* POSIX ACL support */
#undef POSIXACLS
@ -347,6 +347,9 @@
first (like Intel and VAX, unlike Motorola and SPARC). */
#undef WORDS_LITTLEENDIAN
/* system extended attributes mappings */
#undef XATTR_MAPPINGS
/* Number of bits in a file offset, on hosts where this is settable. */
#define _FILE_OFFSET_BITS 64

View File

@ -3,6 +3,7 @@
*
* Copyright (c) 2004-2006 Anton Altaparmakov
* Copyright (c) 2004-2006 Szabolcs Szakacsits
* 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
@ -154,6 +155,25 @@ int ntfs_device_free(struct ntfs_device *dev)
return 0;
}
/*
* Sync the device
*
* returns zero if successful.
*/
int ntfs_device_sync(struct ntfs_device *dev)
{
int ret;
struct ntfs_device_operations *dops;
if (NDevDirty(dev)) {
dops = dev->d_ops;
ret = dops->sync(dev);
} else
ret = 0;
return ret;
}
/**
* ntfs_pread - positioned read from disk
* @dev: device to read from
@ -260,6 +280,9 @@ s64 ntfs_pwrite(struct ntfs_device *dev, const s64 pos, s64 count,
total = written;
break;
}
if (NDevSync(dev) && total && dops->sync(dev)) {
total--; /* on sync error, return partially written */
}
ret = total;
out:
return ret;

View File

@ -41,6 +41,7 @@ typedef enum {
ND_ReadOnly, /* 1: Device is read-only. */
ND_Dirty, /* 1: Device is dirty, needs sync. */
ND_Block, /* 1: Device is a block device. */
ND_Sync, /* 1: Device is mounted with "-o sync" */
} ntfs_device_state_bits;
#define test_ndev_flag(nd, flag) test_bit(ND_##flag, (nd)->d_state)
@ -63,6 +64,10 @@ typedef enum {
#define NDevSetBlock(nd) set_ndev_flag(nd, Block)
#define NDevClearBlock(nd) clear_ndev_flag(nd, Block)
#define NDevSync(nd) test_ndev_flag(nd, Sync)
#define NDevSetSync(nd) set_ndev_flag(nd, Sync)
#define NDevClearSync(nd) clear_ndev_flag(nd, Sync)
/**
* struct ntfs_device -
*
@ -102,6 +107,7 @@ struct ntfs_device_operations {
extern struct ntfs_device *ntfs_device_alloc(const char *name, const long state,
struct ntfs_device_operations *dops, void *priv_data);
extern int ntfs_device_free(struct ntfs_device *dev);
extern int ntfs_device_sync(struct ntfs_device *dev);
extern s64 ntfs_pread(struct ntfs_device *dev, const s64 pos, s64 count,
void *b);

View File

@ -356,7 +356,7 @@ u64 ntfs_inode_lookup_by_name(ntfs_inode *dir_ni,
ntfs_attr_put_search_ctx(ctx);
if (mref)
return mref;
ntfs_log_debug("Entry not found.\n");
ntfs_log_debug("Entry not found - between root entries.\n");
errno = ENOENT;
return -1;
} /* Child node present, descend into it. */
@ -1812,7 +1812,7 @@ search:
while (!ntfs_attr_lookup(AT_FILE_NAME, AT_UNNAMED, 0, CASE_SENSITIVE,
0, NULL, 0, actx)) {
char *s;
BOOL case_sensitive = IGNORE_CASE;
IGNORE_CASE_BOOL case_sensitive = IGNORE_CASE;
errno = 0;
fn = (FILE_NAME_ATTR*)((u8*)actx->attr +
@ -1844,8 +1844,9 @@ search:
(long long unsigned)MREF_LE(fn->parent_directory));
continue;
}
if (fn->file_name_type == FILE_NAME_POSIX || case_sensitive_match)
if (case_sensitive_match
|| ((fn->file_name_type == FILE_NAME_POSIX)
&& NVolCaseSensitive(ni->vol)))
case_sensitive = CASE_SENSITIVE;
if (ntfs_names_are_equal(fn->file_name, fn->file_name_length,

View File

@ -481,6 +481,9 @@ ntfs_inode *ntfs_inode_open(ntfs_volume *vol, const MFT_REF mref)
} else {
ni = ntfs_inode_real_open(vol, mref);
}
if (!ni) {
debug_double_inode(item.inum, 0);
}
#else
ni = ntfs_inode_real_open(vol, mref);
#endif
@ -842,6 +845,12 @@ static int ntfs_inode_sync_file_name(ntfs_inode *ni, ntfs_inode *dir_ni)
else {
fnx->allocated_size = cpu_to_sle64(ni->allocated_size);
fnx->data_size = cpu_to_sle64(ni->data_size);
/*
* The file name record has also to be fixed if some
* attribute update implied the unnamed data to be
* made non-resident
*/
fn->allocated_size = fnx->allocated_size;
}
/* update or clear the reparse tag in the index */
fnx->reparse_point_tag = reparse_tag;

View File

@ -3,6 +3,7 @@
*
* Copyright (c) 2005 Richard Russon
* Copyright (c) 2005-2008 Szabolcs Szakacsits
* 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
@ -388,6 +389,29 @@ out:
}
#endif
/*
* Early logging before the logs are redirected
*
* (not quite satisfactory : this appears before the ntfs-g banner,
* and with a different pid)
*/
void ntfs_log_early_error(const char *format, ...)
{
va_list args;
va_start(args, format);
#ifdef HAVE_SYSLOG_H
openlog("ntfs-3g", LOG_PID, LOG_USER);
ntfs_log_handler_syslog(NULL, NULL, 0,
NTFS_LOG_LEVEL_ERROR, NULL,
format, args);
#else
vfprintf(stderr,format,args);
#endif
va_end(args);
}
/**
* ntfs_log_handler_fprintf - Basic logging handler
* @function: Function in which the log line occurred

View File

@ -114,5 +114,8 @@ int ntfs_log_redirect(const char *function, const char *file, int line,
#define ntfs_log_leave(FORMAT, ARGS...)do {} while (0)
#endif /* DEBUG */
void ntfs_log_early_error(const char *format, ...)
__attribute__((format(printf, 1, 2)));
#endif /* _LOGGING_H_ */

View File

@ -107,7 +107,11 @@
*/
typedef struct {
GUID object_id;
union {
/* alignment may be needed to evaluate collations */
u32 alignment;
GUID guid;
} object_id;
} OBJECT_ID_INDEX_KEY;
typedef struct {

View File

@ -1,7 +1,7 @@
/*
* param.h - Parameter values for ntfs-3g
*
* Copyright (c) 2009 Jean-Pierre Andre
* Copyright (c) 2009-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
@ -50,6 +50,20 @@ enum {
/* maximum cluster size for allowing compression for new files */
#define MAX_COMPRESSION_CLUSTER_SIZE 4096
/*
* Parameters for runlists
*/
/* only update the final extent of a runlist when appending data */
#define PARTIAL_RUNLIST_UPDATING 1
/*
* Parameters for user and xattr mappings
*/
#define XATTRMAPPINGFILE ".NTFS-3G/XattrMapping" /* default mapping file */
/*
* Permission checking modes for high level and low level
*
@ -58,7 +72,8 @@ enum {
*
* Stick to the recommended values unless you understand the consequences
* on protection and performances. Use of cacheing is good for
* performances, but bad on security.
* performances, but bad on security with internal fuse or external
* fuse older than 2.8
*
* Possible values for high level :
* 1 : no cache, kernel control (recommended)
@ -67,7 +82,7 @@ enum {
*
* Possible values for low level :
* 2 : no cache, kernel control
* 3 : use kernel/fuse cache, kernel control
* 3 : use kernel/fuse cache, kernel control (external fuse >= 2.8)
* 5 : no cache, file system control (recommended)
* 8 : no cache, kernel control for ACLs
*
@ -77,6 +92,10 @@ enum {
*/
#define HPERMSCONFIG 1
#if defined(FUSE_INTERNAL) || !defined(FUSE_VERSION) || (FUSE_VERSION < 28)
#define LPERMSCONFIG 5
#else
#define LPERMSCONFIG 3
#endif
#endif /* defined _NTFS_PARAM_H */

View File

@ -5,7 +5,7 @@
* Copyright (c) 2002-2005 Richard Russon
* Copyright (c) 2002-2008 Szabolcs Szakacsits
* Copyright (c) 2004 Yura Pakhuchiy
* Copyright (c) 2007-2009 Jean-Pierre Andre
* Copyright (c) 2007-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
@ -1418,28 +1418,18 @@ int ntfs_write_significant_bytes(u8 *dst, const u8 *dst_max, const s64 n)
{
s64 l = n;
int i;
s8 j;
i = 0;
do {
if (dst > dst_max)
goto err_out;
*dst++ = l;
i++;
while ((l > 0x7f) || (l < -0x80)) {
if (dst > dst_max)
goto err_out;
*dst++ = l & 0xffLL;
l >>= 8;
*dst++ = l;
i++;
} while (l != 0LL && l != -1LL);
j = (n >> 8 * (i - 1)) & 0xff;
/* If the sign bit is wrong, we need an extra byte. */
if (n < 0LL && j >= 0) {
if (dst > dst_max)
goto err_out;
i++;
*dst = (u8)-1;
} else if (n > 0LL && j < 0) {
if (dst > dst_max)
goto err_out;
i++;
*dst = 0;
}
return i;
err_out:

View File

@ -4,7 +4,7 @@
* Copyright (c) 2004 Anton Altaparmakov
* Copyright (c) 2005-2006 Szabolcs Szakacsits
* Copyright (c) 2006 Yura Pakhuchiy
* Copyright (c) 2007-2009 Jean-Pierre Andre
* Copyright (c) 2007-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
@ -404,91 +404,6 @@ le32 ntfs_security_hash(const SECURITY_DESCRIPTOR_RELATIVE *sd, const u32 len)
return cpu_to_le32(hash);
}
/*
* Internal read
* copied and pasted from ntfs_fuse_read() and made independent
* of fuse context
*/
static int ntfs_local_read(ntfs_inode *ni,
ntfschar *stream_name, int stream_name_len,
char *buf, size_t size, off_t offset)
{
ntfs_attr *na = NULL;
int res, total = 0;
na = ntfs_attr_open(ni, AT_DATA, stream_name, stream_name_len);
if (!na) {
res = -errno;
goto exit;
}
if ((size_t)offset < (size_t)na->data_size) {
if (offset + size > (size_t)na->data_size)
size = na->data_size - offset;
while (size) {
res = ntfs_attr_pread(na, offset, size, buf);
if ((off_t)res < (off_t)size)
ntfs_log_perror("ntfs_attr_pread partial read "
"(%lld : %lld <> %d)",
(long long)offset,
(long long)size, res);
if (res <= 0) {
res = -errno;
goto exit;
}
size -= res;
offset += res;
total += res;
}
}
res = total;
exit:
if (na)
ntfs_attr_close(na);
return res;
}
/*
* Internal write
* copied and pasted from ntfs_fuse_write() and made independent
* of fuse context
*/
static int ntfs_local_write(ntfs_inode *ni,
ntfschar *stream_name, int stream_name_len,
char *buf, size_t size, off_t offset)
{
ntfs_attr *na = NULL;
int res, total = 0;
na = ntfs_attr_open(ni, AT_DATA, stream_name, stream_name_len);
if (!na) {
res = -errno;
goto exit;
}
while (size) {
res = ntfs_attr_pwrite(na, offset, size, buf);
if (res < (s64)size)
ntfs_log_perror("ntfs_attr_pwrite partial write (%lld: "
"%lld <> %d)", (long long)offset,
(long long)size, res);
if (res <= 0) {
res = -errno;
goto exit;
}
size -= res;
offset += res;
total += res;
}
res = total;
exit:
if (na)
ntfs_attr_close(na);
return res;
}
/*
* Get the first entry of current index block
* cut and pasted form ntfs_ie_get_first() in index.c
@ -531,7 +446,7 @@ static int entersecurity_stuff(ntfs_volume *vol, off_t offs)
if (stuff) {
memset(stuff, 0, STUFFSZ);
do {
written = ntfs_local_write(vol->secure_ni,
written = ntfs_attr_data_write(vol->secure_ni,
STREAM_SDS, 4, stuff, STUFFSZ, offs);
if (written == STUFFSZ) {
total += STUFFSZ;
@ -589,10 +504,10 @@ static int entersecurity_data(ntfs_volume *vol,
phsds->security_id = keyid;
phsds->offset = cpu_to_le64(offs);
phsds->length = cpu_to_le32(fullsz - gap);
written1 = ntfs_local_write(vol->secure_ni,
written1 = ntfs_attr_data_write(vol->secure_ni,
STREAM_SDS, 4, fullattr, fullsz,
offs - gap);
written2 = ntfs_local_write(vol->secure_ni,
written2 = ntfs_attr_data_write(vol->secure_ni,
STREAM_SDS, 4, fullattr, fullsz,
offs - gap + ALIGN_SDS_BLOCK);
if ((written1 == fullsz)
@ -950,7 +865,7 @@ static le32 setsecurityattr(ntfs_volume *vol,
+ sizeof(SECURITY_DESCRIPTOR_HEADER);
oldattr = (char*)ntfs_malloc(size);
if (oldattr) {
rdsize = ntfs_local_read(
rdsize = ntfs_attr_data_read(
vol->secure_ni,
STREAM_SDS, 4,
oldattr, size, offs);
@ -1772,7 +1687,7 @@ static char *retrievesecurityattr(ntfs_volume *vol, SII_INDEX_KEY id)
securattr = (char*)ntfs_malloc(size);
if (securattr) {
rdsize = ntfs_local_read(
rdsize = ntfs_attr_data_read(
ni, STREAM_SDS, 4,
securattr, size, offs);
if ((rdsize != size)
@ -4097,7 +4012,7 @@ static int basicread(void *fileid, char *buf, size_t size, off_t offs __attribut
static int localread(void *fileid, char *buf, size_t size, off_t offs)
{
return (ntfs_local_read((ntfs_inode*)fileid,
return (ntfs_attr_data_read((ntfs_inode*)fileid,
AT_UNNAMED, 0, buf, size, offs));
}
@ -4919,7 +4834,7 @@ int ntfs_read_sds(struct SECURITY_API *scapi,
got = -1; /* default return */
if (scapi && (scapi->magic == MAGIC_API)) {
if (scapi->security.vol->secure_ni)
got = ntfs_local_read(scapi->security.vol->secure_ni,
got = ntfs_attr_data_read(scapi->security.vol->secure_ni,
STREAM_SDS, 4, buf, size, offset);
else
errno = EOPNOTSUPP;

View File

@ -4,7 +4,7 @@
*
* Copyright (c) 2004 Anton Altaparmakov
* Copyright (c) 2005-2006 Szabolcs Szakacsits
* Copyright (c) 2007-2008 Jean-Pierre Andre
* Copyright (c) 2007-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
@ -85,6 +85,7 @@ struct CACHED_PERMISSIONS_LEGACY {
struct CACHED_PERMISSIONS_LEGACY *previous;
void *variable;
size_t varsize;
union ALIGNMENT payload[0];
/* above fields must match "struct CACHED_GENERIC" */
u64 mft_no;
struct CACHED_PERMISSIONS perm;
@ -99,6 +100,7 @@ struct CACHED_SECURID {
struct CACHED_SECURID *previous;
void *variable;
size_t varsize;
union ALIGNMENT payload[0];
/* above fields must match "struct CACHED_GENERIC" */
uid_t uid;
gid_t gid;
@ -181,6 +183,7 @@ struct POSIX_SECURITY {
int defcnt;
int firstdef;
u16 tagsset;
s32 alignment[0];
struct POSIX_ACL acl;
} ;

View File

@ -129,5 +129,13 @@ typedef enum {
#define STATUS_KEEP_SEARCHING (-3)
#define STATUS_NOT_FOUND (-4)
/*
* Force alignment in a struct if required by processor
*/
union ALIGNMENT {
u64 u64align;
void *ptralign;
} ;
#endif /* defined _NTFS_TYPES_H */

View File

@ -3,7 +3,7 @@
*
* Copyright (c) 2000-2004 Anton Altaparmakov
* Copyright (c) 2002-2009 Szabolcs Szakacsits
* Copyright (c) 2008-2009 Jean-Pierre Andre
* Copyright (c) 2008-2010 Jean-Pierre Andre
* Copyright (c) 2008 Bernhard Kaindl
*
* This program/include file is free software; you can redistribute it and/or
@ -166,24 +166,22 @@ int ntfs_names_full_collate(const ntfschar *name1, const u32 name1_len,
cnt = min(name1_len, name2_len);
if (cnt > 0) {
if (ic == CASE_SENSITIVE) {
do {
c1 = le16_to_cpu(*name1);
while (--cnt && (*name1 == *name2)) {
name1++;
c2 = le16_to_cpu(*name2);
name2++;
} while (--cnt && (c1 == c2));
u1 = c1;
u2 = c2;
}
u1 = c1 = le16_to_cpu(*name1);
u2 = c2 = le16_to_cpu(*name2);
if (u1 < upcase_len)
u1 = le16_to_cpu(upcase[u1]);
if (u2 < upcase_len)
u2 = le16_to_cpu(upcase[u2]);
if ((u1 == u2) && cnt)
do {
u1 = le16_to_cpu(*name1);
name1++;
u2 = le16_to_cpu(*name2);
u1 = le16_to_cpu(*name1);
name2++;
u2 = le16_to_cpu(*name2);
if (u1 < upcase_len)
u1 = le16_to_cpu(upcase[u1]);
if (u2 < upcase_len)

View File

@ -868,6 +868,7 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, unsigned long flags)
VOLUME_INFORMATION *vinf;
ntfschar *vname;
int i, j, eo;
unsigned int k;
u32 u;
vol = ntfs_volume_startup(dev, flags);
@ -1025,6 +1026,17 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, unsigned long flags)
ntfs_log_perror("Failed to close $UpCase");
goto error_exit;
}
/* Consistency check of $UpCase, restricted to plain ASCII chars */
k = 0x20;
while ((k < vol->upcase_len)
&& (k < 0x7f)
&& (le16_to_cpu(vol->upcase[k])
== ((k < 'a') || (k > 'z') ? k : k + 'A' - 'a')))
k++;
if (k < 0x7f) {
ntfs_log_error("Corrupted file $UpCase\n");
goto io_error_exit;
}
/*
* Now load $Volume and set the version information and flags in the

View File

@ -5,6 +5,7 @@
* Copyright (c) 2004-2005 Richard Russon
* Copyright (c) 2005-2006 Yura Pakhuchiy
* Copyright (c) 2005-2009 Szabolcs Szakacsits
* 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
@ -251,7 +252,9 @@ struct _ntfs_volume {
s64 free_mft_records; /* Same for free mft records (see above) */
BOOL efs_raw; /* volume is mounted for raw access to
efs-encrypted files */
#ifdef XATTR_MAPPINGS
struct XATTRMAPPING *xattr_mapping;
#endif /* XATTR_MAPPINGS */
#if CACHE_INODE_SIZE
struct CACHE_HEADER *xinode_cache;
#endif

77
source/xattrs.h Normal file
View File

@ -0,0 +1,77 @@
/*
* xattrs.h : definitions related to 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
*/
#ifndef _NTFS_XATTR_H_
#define _NTFS_XATTR_H_
/*
* Identification of data mapped to the system name space
*/
enum SYSTEMXATTRS {
XATTR_UNMAPPED,
XATTR_NTFS_ACL,
XATTR_NTFS_ATTRIB,
XATTR_NTFS_ATTRIB_BE,
XATTR_NTFS_EFSINFO,
XATTR_NTFS_REPARSE_DATA,
XATTR_NTFS_OBJECT_ID,
XATTR_NTFS_DOS_NAME,
XATTR_NTFS_TIMES,
XATTR_NTFS_TIMES_BE,
XATTR_NTFS_CRTIME,
XATTR_NTFS_CRTIME_BE,
XATTR_POSIX_ACC,
XATTR_POSIX_DEF
} ;
struct XATTRMAPPING {
struct XATTRMAPPING *next;
enum SYSTEMXATTRS xattr;
char name[1]; /* variable length */
} ;
#ifdef XATTR_MAPPINGS
struct XATTRMAPPING *ntfs_xattr_build_mapping(ntfs_volume *vol,
const char *path);
void ntfs_xattr_free_mapping(struct XATTRMAPPING*);
#endif /* XATTR_MAPPINGS */
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,
ntfs_inode *ni, ntfs_inode *dir_ni,
char *value, size_t size);
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 ntfs_xattr_system_removexattr(struct SECURITY_CONTEXT *scx,
enum SYSTEMXATTRS attr,
ntfs_inode *ni, ntfs_inode *dir_ni);
#endif /* _NTFS_XATTR_H_ */