mirror of
https://github.com/Maschell/libntfs-wiiu.git
synced 2024-12-17 23:51:50 +01:00
*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:
parent
76fea547e9
commit
ee41c26551
@ -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);
|
||||
}
|
||||
}
|
||||
|
383
source/attrib.c
383
source/attrib.c
@ -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,
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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_ */
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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 */
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
} ;
|
||||
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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
77
source/xattrs.h
Normal 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_ */
|
Loading…
Reference in New Issue
Block a user