*Update to version 2012.1.15 of NTFS-3G

Change log can be found here:
http://www.tuxera.com/community/release-history/
This commit is contained in:
strtoul 2012-02-05 20:43:39 +00:00
parent 894b7ef3a5
commit a770baf29b
27 changed files with 680 additions and 340 deletions

View File

@ -522,9 +522,7 @@ gid_t ntfs_find_group(const struct MAPPING* groupmapping, const SID * gsid)
{
gid_t gid;
const struct MAPPING *p;
int gsidsz;
gsidsz = ntfs_sid_size(gsid);
p = groupmapping;
while (p && p->xid && !ntfs_same_sid(gsid, p->sid))
p = p->next;
@ -1901,7 +1899,6 @@ static int buildacls_posix(struct MAPPING* const mapping[],
const SID *sid;
int acecnt;
int usidsz;
int gsidsz;
int wsidsz;
int asidsz;
int ssidsz;
@ -1909,7 +1906,6 @@ static int buildacls_posix(struct MAPPING* const mapping[],
le32 grants;
usidsz = ntfs_sid_size(usid);
gsidsz = ntfs_sid_size(gsid);
wsidsz = ntfs_sid_size(worldsid);
asidsz = ntfs_sid_size(adminsid);
ssidsz = ntfs_sid_size(systemsid);
@ -3132,7 +3128,6 @@ static int norm_ownadmin_permissions_posix(struct POSIX_SECURITY *posix_desc,
u16 tag;
u16 tagsset;
struct POSIX_ACE *pxace;
int acccnt;
mode_t denywrld;
mode_t allow;
mode_t deny;
@ -3141,7 +3136,6 @@ static int norm_ownadmin_permissions_posix(struct POSIX_SECURITY *posix_desc,
mode = 0;
pxace = posix_desc->acl.ace;
acccnt = posix_desc->acccnt;
tagsset = 0;
denywrld = 0;
/*
@ -3881,12 +3875,10 @@ struct POSIX_SECURITY *ntfs_build_permissions_posix(
int ntfs_build_permissions(const char *securattr,
const SID *usid, const SID *gsid, BOOL isdir)
{
const SECURITY_DESCRIPTOR_RELATIVE *phead;
int perm;
BOOL adminowns;
BOOL groupowns;
phead = (const SECURITY_DESCRIPTOR_RELATIVE*)securattr;
adminowns = ntfs_same_sid(usid,adminsid)
|| ntfs_same_sid(gsid,adminsid);
groupowns = !adminowns && ntfs_same_sid(gsid,usid);
@ -3969,7 +3961,6 @@ static struct MAPLIST *getmappingitem(FILEREADER reader, void *fileid,
{
int src;
int dst;
char *p;
char *q;
char *pu;
char *pg;
@ -4003,7 +3994,6 @@ static struct MAPLIST *getmappingitem(FILEREADER reader, void *fileid,
if (gotend) {
pu = pg = (char*)NULL;
/* decompose into uid, gid and sid */
p = item->maptext;
item->uidstr = item->maptext;
item->gidstr = strchr(item->uidstr, ':');
if (item->gidstr) {

View File

@ -475,9 +475,10 @@ ntfs_attr *ntfs_attr_open(ntfs_inode *ni, const ATTR_TYPES type,
}
cs = a->flags & (ATTR_IS_COMPRESSED | ATTR_IS_SPARSE);
/* a file may be sparse though its unnamed data is not (cf $UsnJrnl) */
if (na->type == AT_DATA && na->name == AT_UNNAMED &&
((!(a->flags & ATTR_IS_SPARSE) != !NAttrSparse(na)) ||
(((a->flags & ATTR_IS_SPARSE) && !NAttrSparse(na)) ||
(!(a->flags & ATTR_IS_ENCRYPTED) != !NAttrEncrypted(na)))) {
errno = EIO;
ntfs_log_perror("Inode %lld has corrupt attribute flags "
@ -1774,7 +1775,6 @@ 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 "
@ -1850,7 +1850,7 @@ s64 ntfs_attr_pwrite(ntfs_attr *na, const s64 pos, s64 count, const void *b)
goto errno_set;
}
#else
if (ntfs_attr_truncate(na, pos + count)) {
if (ntfs_attr_truncate_i(na, pos + count, HOLES_OK)) {
ntfs_log_perror("Failed to enlarge attribute");
goto errno_set;
}
@ -1860,7 +1860,6 @@ s64 ntfs_attr_pwrite(ntfs_attr *na, const s64 pos, s64 count, const void *b)
!= 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.
@ -2221,7 +2220,7 @@ done:
updatemap = (compressed
? NAttrFullyMapped(na) != 0 : update_from != -1);
#endif
if (updatemap)
if (updatemap) {
if (ntfs_attr_update_mapping_pairs(na,
(update_from < 0 ? 0 : update_from))) {
/*
@ -2231,6 +2230,10 @@ done:
total = -1;
goto out;
}
if (!wasnonresident)
NAttrClearBeingNonResident(na);
NAttrClearDataAppending(na);
}
out:
ntfs_log_leave("\n");
return total;
@ -2292,7 +2295,8 @@ err_out:
if (updatemap)
ntfs_attr_update_mapping_pairs(na, 0);
/* Restore original data_size if needed. */
if (need_to.undo_data_size && ntfs_attr_truncate(na, old_data_size))
if (need_to.undo_data_size
&& ntfs_attr_truncate_i(na, old_data_size, HOLES_OK))
ntfs_log_perror("Failed to restore data_size");
errno = eo;
errno_set:
@ -2310,7 +2314,6 @@ int ntfs_attr_pclose(ntfs_attr *na)
ntfs_attr_search_ctx *ctx = NULL;
runlist_element *rl;
int eo;
s64 hole;
int compressed_part;
BOOL compressed;
@ -2422,7 +2425,6 @@ int ntfs_attr_pclose(ntfs_attr *na)
goto rl_err_out;
}
if (rl->lcn < (LCN)0) {
hole = rl->vcn + rl->length;
if (rl->lcn != (LCN)LCN_HOLE) {
errno = EIO;
ntfs_log_perror("%s: Unexpected LCN (%lld)",
@ -2475,6 +2477,7 @@ retry:
goto out;
}
out:
NAttrClearComprClosing(na);
ntfs_log_leave("\n");
return (!ok);
rl_err_out:
@ -2531,6 +2534,7 @@ s64 ntfs_attr_mst_pread(ntfs_attr *na, const s64 pos, const s64 bk_cnt,
{
s64 br;
u8 *end;
BOOL warn;
ntfs_log_trace("Entering for inode 0x%llx, attr type 0x%x, pos 0x%llx.\n",
(unsigned long long)na->ni->mft_no, na->type,
@ -2544,9 +2548,11 @@ s64 ntfs_attr_mst_pread(ntfs_attr *na, const s64 pos, const s64 bk_cnt,
if (br <= 0)
return br;
br /= bk_size;
/* log errors unless silenced */
warn = !na->ni || !na->ni->vol || !NVolNoFixupWarn(na->ni->vol);
for (end = (u8*)dst + br * bk_size; (u8*)dst < end; dst = (u8*)dst +
bk_size)
ntfs_mst_post_read_fixup((NTFS_RECORD*)dst, bk_size);
ntfs_mst_post_read_fixup_warn((NTFS_RECORD*)dst, bk_size, warn);
/* Finally, return the number of blocks read. */
return br;
}
@ -3544,6 +3550,14 @@ int ntfs_attr_size_bounds_check(const ntfs_volume *vol, const ATTR_TYPES type,
min_size = sle64_to_cpu(ad->min_size);
max_size = sle64_to_cpu(ad->max_size);
/* The $AttrDef generated by Windows specifies 2 as min_size for the
* volume name attribute, but in reality Windows sets it to 0 when
* clearing the volume name. If we want to be able to clear the volume
* name we must also accept 0 as min_size, despite the $AttrDef
* definition. */
if(type == AT_VOLUME_NAME)
min_size = 0;
if ((min_size && (size < min_size)) ||
((max_size > 0) && (size > max_size))) {
@ -4296,7 +4310,7 @@ add_non_resident:
goto rm_attr_err_out;
}
/* Resize and set attribute value. */
if (ntfs_attr_truncate(na, size) ||
if (ntfs_attr_truncate_i(na, size, HOLES_OK) ||
(val && (ntfs_attr_pwrite(na, 0, size, val) != size))) {
err = errno;
ntfs_log_perror("Failed to initialize just added attribute");
@ -4877,6 +4891,7 @@ cluster_free_err_out:
ntfs_log_trace("Eeek! Failed to release allocated clusters in error "
"code path. Leaving inconsistent metadata...\n");
NAttrClearNonResident(na);
NAttrClearFullyMapped(na);
na->allocated_size = na->data_size;
na->rl = NULL;
free(rl);
@ -5000,7 +5015,7 @@ static int ntfs_resident_attr_resize_i(ntfs_attr *na, const s64 newsize,
return (ret);
}
/* Resize non-resident attribute */
return ntfs_attr_truncate(na, newsize);
return ntfs_attr_truncate_i(na, newsize, HOLES_OK);
} else if (errno != ENOSPC && errno != EPERM) {
err = errno;
ntfs_log_perror("Failed to make attribute non-resident");
@ -5348,7 +5363,6 @@ static int ntfs_attr_make_resident(ntfs_attr *na, ntfs_attr_search_ctx *ctx)
* record is in a transiently corrupted state at this moment in time.
*/
if (ntfs_cluster_free(vol, na, 0, -1) < 0) {
err = errno;
ntfs_log_perror("Eeek! Failed to release allocated clusters");
ntfs_log_trace("Ignoring error and leaving behind wasted "
"clusters.\n");
@ -5360,6 +5374,7 @@ static int ntfs_attr_make_resident(ntfs_attr *na, ntfs_attr_search_ctx *ctx)
/* Update in-memory struct ntfs_attr. */
NAttrClearNonResident(na);
NAttrClearFullyMapped(na);
NAttrClearSparse(na);
NAttrClearEncrypted(na);
na->initialized_size = na->data_size;
@ -5453,6 +5468,7 @@ static int ntfs_attr_update_meta(ATTR_RECORD *a, ntfs_attr *na, MFT_RECORD *m,
NAttrClearSparse(na);
a->flags &= ~ATTR_IS_SPARSE;
na->data_flags = a->flags;
a->compression_unit = 0;
memmove((u8*)a + le16_to_cpu(a->name_offset) - 8,
@ -6422,7 +6438,12 @@ out:
int ntfs_attr_truncate(ntfs_attr *na, const s64 newsize)
{
return (ntfs_attr_truncate_i(na, newsize, HOLES_OK));
int r;
r = ntfs_attr_truncate_i(na, newsize, HOLES_OK);
NAttrClearDataAppending(na);
NAttrClearBeingNonResident(na);
return (r);
}
/*

View File

@ -376,7 +376,6 @@ int ntfs_invalidate_cache(struct CACHE_HEADER *cache,
int flags)
{
struct CACHED_GENERIC *current;
struct CACHED_GENERIC *previous;
struct CACHED_GENERIC *next;
struct HASH_ENTRY *link;
int count;
@ -412,7 +411,6 @@ int ntfs_invalidate_cache(struct CACHE_HEADER *cache,
* Search sequentially in LRU list
*/
current = cache->most_recent_entry;
previous = (struct CACHED_GENERIC*)NULL;
while (current) {
if (!compare(current, item)) {
next = current->next;
@ -423,7 +421,6 @@ int ntfs_invalidate_cache(struct CACHE_HEADER *cache,
current = next;
count++;
} else {
previous = current;
current = current->next;
}
}

View File

@ -81,259 +81,215 @@ typedef enum {
NTFS_SB_IS_COMPRESSED = 0x8000,
} ntfs_compression_constants;
#define THRESHOLD 3 /* minimal match length for compression */
#define NIL NTFS_SB_SIZE /* End of tree's node */
struct COMPRESS_CONTEXT {
const unsigned char *inbuf;
unsigned int len;
unsigned int nbt;
int match_position;
unsigned int match_length;
u16 lson[NTFS_SB_SIZE + 1];
u16 rson[NTFS_SB_SIZE + 257];
u16 dad[NTFS_SB_SIZE + 1];
int bufsize;
int size;
int rel;
int mxsz;
s16 head[256];
s16 lson[NTFS_SB_SIZE];
s16 rson[NTFS_SB_SIZE];
} ;
/*
* Initialize the match tree
*/
static void ntfs_init_compress_tree(struct COMPRESS_CONTEXT *pctx)
{
int i;
for (i = NTFS_SB_SIZE + 1; i <= NTFS_SB_SIZE + 256; i++)
pctx->rson[i] = NIL; /* root */
for (i = 0; i < NTFS_SB_SIZE; i++)
pctx->dad[i] = NIL; /* node */
}
/*
* Insert a new node into match tree for quickly locating
* further similar strings
*/
static void ntfs_new_node (struct COMPRESS_CONTEXT *pctx,
unsigned int r)
{
unsigned int pp;
BOOL less;
BOOL done;
const unsigned char *key;
int c;
unsigned long mxi;
unsigned int mxl;
mxl = (1 << (16 - pctx->nbt)) + 2;
less = FALSE;
done = FALSE;
key = &pctx->inbuf[r];
pp = NTFS_SB_SIZE + 1 + key[0];
pctx->rson[r] = pctx->lson[r] = NIL;
pctx->match_length = 0;
do {
if (!less) {
if (pctx->rson[pp] != NIL)
pp = pctx->rson[pp];
else {
pctx->rson[pp] = r;
pctx->dad[r] = pp;
done = TRUE;
}
} else {
if (pctx->lson[pp] != NIL)
pp = pctx->lson[pp];
else {
pctx->lson[pp] = r;
pctx->dad[r] = pp;
done = TRUE;
}
}
if (!done) {
register unsigned long i;
register const unsigned char *p1,*p2;
i = 1;
mxi = NTFS_SB_SIZE - r;
if (mxi < 2)
less = FALSE;
else {
p1 = key;
p2 = &pctx->inbuf[pp];
/* this loop has a significant impact on performances */
do {
} while ((p1[i] == p2[i]) && (++i < mxi));
less = (i < mxi) && (p1[i] < p2[i]);
}
if (i >= THRESHOLD) {
if (i > pctx->match_length) {
pctx->match_position =
r - pp + 2*NTFS_SB_SIZE - 1;
if ((pctx->match_length = i) > mxl) {
i = pctx->rson[pp];
pctx->rson[r] = i;
pctx->dad[i] = r;
i = pctx->lson[pp];
pctx->lson[r] = i;
pctx->dad[i] = r;
i = pctx->dad[pp];
pctx->dad[r] = i;
if (pctx->rson[i] == pp)
pctx->rson[i] = r;
else
pctx->lson[i] = r;
/* remove pp */
pctx->dad[pp] = NIL;
done = TRUE;
pctx->match_length = mxl;
}
} else
if ((i == pctx->match_length)
&& ((c = (r - pp + 2*NTFS_SB_SIZE - 1))
< pctx->match_position))
pctx->match_position = c;
}
}
} while (!done);
}
/*
* Search for the longest previous string matching the
* current one
* Search for the longest sequence matching current position
*
* Returns the end of the longest current string which matched
* or zero if there was a bug
* A binary tree is maintained to locate all previously met sequences,
* and this function has to be called for all of them.
*
* This function is heavily used, it has to be optimized carefully
*
* Returns the size of the longest match,
* zero if no match is found.
*/
static unsigned int ntfs_nextmatch(struct COMPRESS_CONTEXT *pctx,
unsigned int rr, int dd)
static int ntfs_best_match(struct COMPRESS_CONTEXT *pctx, int i)
{
unsigned int bestlen = 0;
s16 *prev;
int node;
register long j;
long maxpos;
long startj;
long bestj;
int bufsize;
int bestnode;
register const unsigned char *p1,*p2;
do {
rr++;
if (pctx->match_length > 0)
pctx->match_length--;
if (!pctx->len) {
ntfs_log_error("compress bug : void run\n");
goto bug;
}
if (--pctx->len) {
if (rr >= NTFS_SB_SIZE) {
ntfs_log_error("compress bug : buffer overflow\n");
goto bug;
}
if (((rr + bestlen) < NTFS_SB_SIZE)) {
while ((unsigned int)(1 << pctx->nbt)
<= (rr - 1))
pctx->nbt++;
ntfs_new_node(pctx,rr);
if (pctx->match_length > bestlen)
bestlen = pctx->match_length;
} else
if (dd > 0) {
rr += dd;
if ((int)pctx->match_length > dd)
pctx->match_length -= dd;
else
pctx->match_length = 0;
if ((int)pctx->len < dd) {
ntfs_log_error("compress bug : run overflows\n");
goto bug;
p1 = pctx->inbuf;
node = pctx->head[p1[i] & 255];
if (node >= 0) {
/* search the best match at current position */
bestnode = node;
bufsize = pctx->bufsize;
/* restrict matches to the longest allowed sequence */
maxpos = bufsize;
if ((i + pctx->mxsz) < maxpos)
maxpos = i + pctx->mxsz;
startj = i + 1 - maxpos;
bestj = startj;
/* make indexes relative to end of allowed position */
p1 = &p1[maxpos];
if (startj < 0) {
do {
/* indexes are negative */
p2 = &p1[node - i];
/* no need to compare the first byte */
j = startj;
/* the second byte cannot lead to useful compression */
if (p1[j] == p2[j]) {
j++;
if (j < 0) {
do {
} while ((p1[j] == p2[j])
&& (++j < 0));
}
/* remember the match, if better */
if (j > bestj) {
bestj = j;
bestnode = node;
}
pctx->len -= dd;
dd = 0;
}
/* walk in the tree in the right direction */
if ((j < 0) && (p1[j] < p2[j]))
prev = &pctx->lson[node];
else
prev = &pctx->rson[node];
node = *prev;
/* stop if reaching a leaf or maximum length */
} while ((node >= 0) && (j < 0));
/* put the node into the tree if we reached a leaf */
if (node < 0)
*prev = i;
}
} while (dd-- > 0);
return (rr);
bug :
return (0);
/* done, return the best match */
pctx->size = bestj + maxpos - i;
pctx->rel = bestnode - i;
} else {
pctx->head[p1[i] & 255] = i;
pctx->size = 0;
pctx->rel = 0;
}
return (pctx->size);
}
/*
* Compress an input block
* Compress a 4096-byte block
*
* Returns the size of the compressed block (including header)
* or zero if there was an error
* Returns a header of two bytes followed by the compressed data.
* If compression is not effective, the header and an uncompressed
* block is returned.
*
* Note : two bytes may be output before output buffer overflow
* is detected, so a 4100-bytes output buffer must be reserved.
*
* Returns the size of the compressed block, including the
* header (minimal size is 2, maximum size is 4098)
* 0 if an error has been met.
*/
static unsigned int ntfs_compress_block(const char *inbuf,
unsigned int size, char *outbuf)
static unsigned int ntfs_compress_block(const char *inbuf, int bufsize,
char *outbuf)
{
struct COMPRESS_CONTEXT *pctx;
char *ptag;
int dd;
unsigned int rr;
unsigned int last_match_length;
unsigned int q;
int i; /* current position */
int j; /* end of best match from current position */
int k; /* end of best match from next position */
int offs; /* offset to best match */
int n;
int bp; /* bits to store offset */
int mxoff; /* max match offset : 1 << bp */
int mxsz2;
unsigned int xout;
unsigned int ntag;
unsigned int q; /* aggregated offset and size */
int done;
char *ptag; /* location reserved for a tag */
int tag; /* current value of tag */
int ntag; /* count of bits still undefined in tag */
pctx = (struct COMPRESS_CONTEXT*)malloc(sizeof(struct COMPRESS_CONTEXT));
pctx = (struct COMPRESS_CONTEXT*)ntfs_malloc(sizeof(struct COMPRESS_CONTEXT));
if (pctx) {
for (n=0; n<NTFS_SB_SIZE; n++)
pctx->lson[n] = pctx->rson[n] = -1;
for (n=0; n<256; n++)
pctx->head[n] = -1;
pctx->inbuf = (const unsigned char*)inbuf;
ntfs_init_compress_tree(pctx);
pctx->bufsize = bufsize;
xout = 2;
ntag = 0;
n = 0;
i = 0;
bp = 4;
mxoff = 1 << bp;
pctx->mxsz = (1 << (16 - bp)) + 2;
tag = 0;
done = -1;
ntag = 8;
ptag = &outbuf[xout++];
*ptag = 0;
rr = 0;
pctx->nbt = 4;
pctx->len = size;
pctx->match_length = 0;
ntfs_new_node(pctx,0);
do {
if (pctx->match_length > pctx->len)
pctx->match_length = pctx->len;
if (pctx->match_length < THRESHOLD) {
pctx->match_length = 1;
if (ntag >= 8) {
ntag = 0;
ptag = &outbuf[xout++];
*ptag = 0;
while ((i < bufsize) && (xout < (NTFS_SB_SIZE + 2))) {
/* adjust the longest match we can output */
while (mxoff < i) {
bp++;
mxoff <<= 1;
pctx->mxsz = (pctx->mxsz + 2) >> 1;
}
/* search the best match at current position */
if (done < i)
do {
ntfs_best_match(pctx,++done);
} while (done < i);
j = i + pctx->size;
if ((j - i) > pctx->mxsz)
j = i + pctx->mxsz;
if ((j - i) > 2) {
offs = pctx->rel;
/* check whether there is a better run at i+1 */
ntfs_best_match(pctx,i+1);
done = i+1;
k = i + 1 + pctx->size;
mxsz2 = pctx->mxsz;
if (mxoff <= i)
mxsz2 = (pctx->mxsz + 2) >> 1;
if ((k - i) > mxsz2)
k = i + mxsz2;
if (k > (j + 1)) {
/* issue a single byte */
outbuf[xout++] = inbuf[i];
i++;
} else {
q = (~offs << (16 - bp))
+ (j - i - 3);
outbuf[xout++] = q & 255;
outbuf[xout++] = (q >> 8) & 255;
tag |= (1 << (8 - ntag));
i = j;
}
outbuf[xout++] = inbuf[rr];
ntag++;
} else {
while ((unsigned int)(1 << pctx->nbt)
<= (rr - 1))
pctx->nbt++;
q = (pctx->match_position << (16 - pctx->nbt))
+ pctx->match_length - THRESHOLD;
if (ntag >= 8) {
ntag = 0;
ptag = &outbuf[xout++];
*ptag = 0;
}
*ptag |= 1 << ntag++;
outbuf[xout++] = q & 255;
outbuf[xout++] = (q >> 8) & 255;
outbuf[xout++] = inbuf[i];
i++;
}
last_match_length = pctx->match_length;
dd = last_match_length;
if (dd-- > 0) {
rr = ntfs_nextmatch(pctx,rr,dd);
if (!rr)
goto bug;
/* store the tag if fully used */
if (!--ntag) {
*ptag = tag;
ntag = 8;
ptag = &outbuf[xout++];
tag = 0;
}
/*
* stop if input is exhausted or output has exceeded
* the maximum size. Two extra bytes have to be
* reserved in output buffer, as 3 bytes may be
* output in a loop.
*/
} while ((pctx->len > 0)
&& (rr < size) && (xout < (NTFS_SB_SIZE + 2)));
/* uncompressed must be full size, so accept if better */
if (xout < (NTFS_SB_SIZE + 2)) {
}
/* store the last tag, if partially used */
if (ntag == 8)
xout--;
else
*ptag = tag;
/* uncompressed must be full size, accept if better */
if ((i >= bufsize) && (xout < (NTFS_SB_SIZE + 2))) {
outbuf[0] = (xout - 3) & 255;
outbuf[1] = 0xb0 + (((xout - 3) >> 8) & 15);
} else {
memcpy(&outbuf[2],inbuf,size);
if (size < NTFS_SB_SIZE)
memset(&outbuf[size+2],0,NTFS_SB_SIZE - size);
memcpy(&outbuf[2],inbuf,bufsize);
if (bufsize < NTFS_SB_SIZE)
memset(&outbuf[bufsize+2], 0,
NTFS_SB_SIZE - bufsize);
outbuf[0] = 0xff;
outbuf[1] = 0x3f;
xout = NTFS_SB_SIZE + 2;
@ -343,9 +299,7 @@ static unsigned int ntfs_compress_block(const char *inbuf,
xout = 0;
errno = ENOMEM;
}
return (xout); /* 0 for an error, > size if cannot compress */
bug :
return (0);
return (xout);
}
/**
@ -1512,12 +1466,12 @@ static int ntfs_read_append(ntfs_attr *na, const runlist_element *rl,
* or -1 if there were an irrecoverable error (errno set)
*/
static int ntfs_flush(ntfs_attr *na, runlist_element *rl, s64 offs,
static s32 ntfs_flush(ntfs_attr *na, runlist_element *rl, s64 offs,
const char *outbuf, s32 count, BOOL compress,
BOOL appending, VCN *update_from)
{
int rounded;
int written;
s32 rounded;
s32 written;
int clsz;
if (compress) {
@ -1655,7 +1609,7 @@ s64 ntfs_compressed_pwrite(ntfs_attr *na, runlist_element *wrl, s64 wpos,
* (we are reopening an existing file to append to it)
* Decompress the data and append
*/
compsz = compressed_part << vol->cluster_size_bits;
compsz = (s32)compressed_part << vol->cluster_size_bits;
outbuf = (char*)ntfs_malloc(na->compression_block_size);
if (outbuf) {
if (appending) {

View File

@ -226,6 +226,9 @@
/* Define to 1 if you have the <sys/byteorder.h> header file. */
#undef HAVE_SYS_BYTEORDER_H
/* Define to 1 if you have the <sys/disk.h> header file. */
#undef HAVE_SYS_DISK_H
/* Define to 1 if you have the <sys/endian.h> header file. */
#undef HAVE_SYS_ENDIAN_H
@ -309,13 +312,13 @@
#define PACKAGE_NAME "ntfs-3g"
/* Define to the full name and version of this package. */
#define PACKAGE_STRING "ntfs-3g 2011.4.12"
#define PACKAGE_STRING "ntfs-3g 2012.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 "2011.4.12"
#define PACKAGE_VERSION "2012.1.15"
/* POSIX ACL support */
#undef POSIXACLS
@ -345,7 +348,7 @@
#endif
/* Version number of package */
#define VERSION "2011.4.12"
#define VERSION "2012.1.15"
/* Define to 1 if this is a Windows OS */
#undef WINDOWS
@ -375,6 +378,9 @@
/* Required define if using POSIX threads */
#undef _REENTRANT
/* Define to empty if `const' does not conform to ANSI C. */
#undef const
/* Define to `__inline__' or `__inline' if that's what the C compiler
calls it, or to nothing if 'inline' is not supported under any name. */
#ifndef __cplusplus

View File

@ -38,10 +38,10 @@ static __inline__ void ntfs_debug_runlist_dump(const struct _runlist_element *rl
#define NTFS_BUG(msg) \
{ \
int ___i; \
int ___i = 1; \
ntfs_log_critical("Bug in %s(): %s\n", __FUNCTION__, msg); \
ntfs_log_debug("Forcing segmentation fault!"); \
___i = ((int*)NULL)[1]; \
___i = ((int*)NULL)[___i]; \
}
#endif /* defined _NTFS_DEBUG_H */

View File

@ -58,6 +58,9 @@
#ifdef HAVE_SYS_MOUNT_H
#include <sys/mount.h>
#endif
#ifdef HAVE_SYS_DISK_H
#include <sys/disk.h>
#endif
#ifdef HAVE_LINUX_FD_H
#include <linux/fd.h>
#endif
@ -556,6 +559,36 @@ s64 ntfs_device_size_get(struct ntfs_device *dev, int block_size)
return (s64)this_floppy.size * 512 / block_size;
}
}
#endif
#ifdef DIOCGMEDIASIZE
{
/* FreeBSD */
off_t size;
if (dev->d_ops->ioctl(dev, DIOCGMEDIASIZE, &size) >= 0) {
ntfs_log_debug("DIOCGMEDIASIZE nr bytes = %llu (0x%llx)\n",
(unsigned long long)size,
(unsigned long long)size);
return (s64)size / block_size;
}
}
#endif
#ifdef DKIOCGETBLOCKCOUNT
{
/* Mac OS X */
uint64_t blocks;
int sector_size;
sector_size = ntfs_device_sector_size_get(dev);
if (sector_size >= 0 && dev->d_ops->ioctl(dev,
DKIOCGETBLOCKCOUNT, &blocks) >= 0)
{
ntfs_log_debug("DKIOCGETBLOCKCOUNT nr blocks = %llu (0x%llx)\n",
(unsigned long long) blocks,
(unsigned long long) blocks);
return blocks * sector_size / block_size;
}
}
#endif
/*
* We couldn't figure it out by using a specialized ioctl,
@ -705,6 +738,28 @@ int ntfs_device_sector_size_get(struct ntfs_device *dev)
return sect_size;
}
}
#elif defined(DIOCGSECTORSIZE)
{
/* FreeBSD */
size_t sect_size = 0;
if (!dev->d_ops->ioctl(dev, DIOCGSECTORSIZE, &sect_size)) {
ntfs_log_debug("DIOCGSECTORSIZE sector size = %d bytes\n",
(int) sect_size);
return sect_size;
}
}
#elif defined(DKIOCGETBLOCKSIZE)
{
/* Mac OS X */
uint32_t sect_size = 0;
if (!dev->d_ops->ioctl(dev, DKIOCGETBLOCKSIZE, &sect_size)) {
ntfs_log_debug("DKIOCGETBLOCKSIZE sector size = %d bytes\n",
(int) sect_size);
return sect_size;
}
}
#else
errno = EOPNOTSUPP;
#endif

View File

@ -257,7 +257,7 @@ u64 ntfs_inode_lookup_by_name(ntfs_inode *dir_ni,
u8 *index_end;
ntfs_attr *ia_na;
int eo, rc;
u32 index_block_size, index_vcn_size;
u32 index_block_size;
u8 index_vcn_size_bits;
ntfs_log_trace("Entering\n");
@ -378,11 +378,9 @@ u64 ntfs_inode_lookup_by_name(ntfs_inode *dir_ni,
/* Determine the size of a vcn in the directory index. */
if (vol->cluster_size <= index_block_size) {
index_vcn_size = vol->cluster_size;
index_vcn_size_bits = vol->cluster_size_bits;
} else {
index_vcn_size = vol->sector_size;
index_vcn_size_bits = vol->sector_size_bits;
index_vcn_size_bits = NTFS_BLOCK_SIZE_BITS;
}
/* Get the starting vcn of the index_block holding the child node. */
@ -1039,7 +1037,7 @@ int ntfs_readdir(ntfs_inode *dir_ni, s64 *pos,
INDEX_ENTRY *ie;
INDEX_ALLOCATION *ia = NULL;
int rc, ir_pos, bmp_buf_size, bmp_buf_pos, eo;
u32 index_block_size, index_vcn_size;
u32 index_block_size;
u8 index_block_size_bits, index_vcn_size_bits;
ntfs_log_trace("Entering.\n");
@ -1131,11 +1129,9 @@ int ntfs_readdir(ntfs_inode *dir_ni, s64 *pos,
}
index_block_size_bits = ffs(index_block_size) - 1;
if (vol->cluster_size <= index_block_size) {
index_vcn_size = vol->cluster_size;
index_vcn_size_bits = vol->cluster_size_bits;
} else {
index_vcn_size = vol->sector_size;
index_vcn_size_bits = vol->sector_size_bits;
index_vcn_size_bits = NTFS_BLOCK_SIZE_BITS;
}
/* Are we jumping straight into the index allocation attribute? */
@ -1517,7 +1513,7 @@ static ntfs_inode *__ntfs_create(ntfs_inode *dir_ni, le32 securid,
else
ir->clusters_per_index_block =
ni->vol->indx_record_size >>
ni->vol->sector_size_bits;
NTFS_BLOCK_SIZE_BITS;
ir->index.entries_offset = cpu_to_le32(sizeof(INDEX_HEADER));
ir->index.index_length = cpu_to_le32(index_len);
ir->index.allocated_size = cpu_to_le32(index_len);
@ -2508,24 +2504,24 @@ int ntfs_set_ntfs_dos_name(ntfs_inode *ni, ntfs_inode *dir_ni,
int res = 0;
int longlen = 0;
int shortlen = 0;
char newname[MAX_DOS_NAME_LENGTH + 1];
char newname[3*MAX_DOS_NAME_LENGTH + 1];
ntfschar oldname[MAX_DOS_NAME_LENGTH];
int oldlen;
ntfs_volume *vol;
u64 fnum;
u64 dnum;
BOOL closed = FALSE;
ntfschar *shortname = NULL;
ntfschar longname[NTFS_MAX_NAME_LEN];
vol = ni->vol;
fnum = ni->mft_no;
/* convert the string to the NTFS wide chars */
if (size > MAX_DOS_NAME_LENGTH)
size = MAX_DOS_NAME_LENGTH;
/* copy the string to insert a null char, and truncate */
if (size > 3*MAX_DOS_NAME_LENGTH)
size = 3*MAX_DOS_NAME_LENGTH;
strncpy(newname, value, size);
/* a long name may be truncated badly and be untranslatable */
newname[size] = 0;
/* convert the string to the NTFS wide chars, and truncate */
shortlen = ntfs_mbstoucs(newname, &shortname);
if (shortlen > MAX_DOS_NAME_LENGTH)
shortlen = MAX_DOS_NAME_LENGTH;
/* make sure the short name has valid chars */
if ((shortlen < 0) || ntfs_forbidden_chars(shortname,shortlen)) {
ntfs_inode_close_in_dir(ni,dir_ni);

View File

@ -139,7 +139,6 @@ static int fixup_loop(ntfs_inode *ni)
ntfs_attr *na;
ATTR_RECORD *a;
BOOL restart;
BOOL first;
int cnt;
int maxcnt;
int res = 0;
@ -200,7 +199,6 @@ static int fixup_loop(ntfs_inode *ni)
if (na)
ntfs_attr_close(na);
}
first = FALSE;
} while (restart && !res);
if (ctx)
ntfs_attr_put_search_ctx(ctx);

View File

@ -701,7 +701,7 @@ int ntfs_index_lookup(const void *key, const int key_len, ntfs_index_context *ic
if (ni->vol->cluster_size <= icx->block_size)
icx->vcn_size_bits = ni->vol->cluster_size_bits;
else
icx->vcn_size_bits = ni->vol->sector_size_bits;
icx->vcn_size_bits = NTFS_BLOCK_SIZE_BITS;
/* get the appropriate collation function */
icx->collate = ntfs_get_collate_function(ir->collation_rule);
if (!icx->collate) {

View File

@ -437,13 +437,12 @@ static int idata_cache_compare(const struct CACHED_GENERIC *cached,
void ntfs_inode_invalidate(ntfs_volume *vol, const MFT_REF mref)
{
struct CACHED_NIDATA item;
int count;
item.inum = MREF(mref);
item.ni = (ntfs_inode*)NULL;
item.pathname = (const char*)NULL;
item.varsize = 0;
count = ntfs_invalidate_cache(vol->nidata_cache,
ntfs_invalidate_cache(vol->nidata_cache,
GENERIC(&item),idata_cache_compare,CACHE_FREE);
}
@ -574,6 +573,9 @@ int ntfs_inode_close(ntfs_inode *ni)
ntfs_inode *ntfs_extent_inode_open(ntfs_inode *base_ni, const MFT_REF mref)
{
u64 mft_no = MREF_LE(mref);
VCN extent_vcn;
runlist_element *rl;
ntfs_volume *vol;
ntfs_inode *ni = NULL;
ntfs_inode **extent_nis;
int i;
@ -588,6 +590,37 @@ ntfs_inode *ntfs_extent_inode_open(ntfs_inode *base_ni, const MFT_REF mref)
(unsigned long long)mft_no,
(unsigned long long)base_ni->mft_no);
if (!base_ni->mft_no) {
/*
* When getting extents of MFT, we must be sure
* they are in the MFT part which has already
* been mapped, otherwise we fall into an endless
* recursion.
* Situations have been met where extents locations
* are described in themselves.
* This is a severe error which chkdsk cannot fix.
*/
vol = base_ni->vol;
extent_vcn = mft_no << vol->mft_record_size_bits
>> vol->cluster_size_bits;
rl = vol->mft_na->rl;
if (rl) {
while (rl->length
&& ((rl->vcn + rl->length) <= extent_vcn))
rl++;
}
if (!rl || (rl->lcn < 0)) {
ntfs_log_error("MFT is corrupt, cannot read"
" its unmapped extent record %lld\n",
(long long)mft_no);
ntfs_log_error("Note : chkdsk cannot fix this,"
" try ntfsfix\n");
errno = EIO;
ni = (ntfs_inode*)NULL;
goto out;
}
}
/* Is the extent inode already open and attached to the base inode? */
if (base_ni->nr_extents > 0) {
extent_nis = base_ni->extent_nis;

View File

@ -2223,11 +2223,11 @@ typedef struct {
/* The below field is NOT present for the quota defaults entry. */
SID sid; /* The SID of the user/object associated with
this quota entry. If this field is missing
then the INDEX_ENTRY is padded with zeros
to multiply of 8 which are not counted in
then the INDEX_ENTRY is padded to a multiple
of 8 with zeros which are not counted in
the data_length field. If the sid is present
then this structure is padded with zeros to
multiply of 8 and the padding is counted in
a multiple of 8 and the padding is counted in
the INDEX_ENTRY's data_length. */
} __attribute__((__packed__)) QUOTA_CONTROL_ENTRY;

View File

@ -468,7 +468,7 @@ BOOL ntfs_check_logfile(ntfs_attr *log_na, RESTART_PAGE_HEADER **rp)
u8 *kaddr = NULL;
RESTART_PAGE_HEADER *rstr1_ph = NULL;
RESTART_PAGE_HEADER *rstr2_ph = NULL;
int log_page_size, log_page_mask, err;
int log_page_size, err;
BOOL logfile_is_empty = TRUE;
u8 log_page_bits;
@ -481,7 +481,6 @@ BOOL ntfs_check_logfile(ntfs_attr *log_na, RESTART_PAGE_HEADER **rp)
if (size > (s64)MaxLogFileSize)
size = MaxLogFileSize;
log_page_size = DefaultLogPageSize;
log_page_mask = log_page_size - 1;
/*
* Use generic_ffs() instead of ffs() to enable the compiler to
* optimize log_page_size and log_page_bits into constants.
@ -703,7 +702,7 @@ int ntfs_empty_logfile(ntfs_attr *na)
char buf[NTFS_BUF_SIZE];
ntfs_log_trace("Entering.\n");
if (NVolLogFileEmpty(na->ni->vol))
return 0;
@ -717,7 +716,7 @@ int ntfs_empty_logfile(ntfs_attr *na)
pos = 0;
while ((count = na->data_size - pos) > 0) {
if (count > NTFS_BUF_SIZE)
count = NTFS_BUF_SIZE;
@ -733,6 +732,6 @@ int ntfs_empty_logfile(ntfs_attr *na)
}
NVolSetLogFileEmpty(na->ni->vol);
return 0;
}

View File

@ -216,8 +216,10 @@ int ntfs_mft_record_check(const ntfs_volume *vol, const MFT_REF mref,
int ret = -1;
if (!ntfs_is_file_record(m->magic)) {
ntfs_log_error("Record %llu has no FILE magic (0x%x)\n",
(unsigned long long)MREF(mref), *(le32 *)m);
if (!NVolNoFixupWarn(vol))
ntfs_log_error("Record %llu has no FILE magic (0x%x)\n",
(unsigned long long)MREF(mref),
(int)le32_to_cpu(*(le32*)m));
goto err_out;
}
@ -1190,7 +1192,7 @@ undo_alloc:
static int ntfs_mft_record_init(ntfs_volume *vol, s64 size)
{
int ret = -1;
ntfs_attr *mft_na, *mftbmp_na;
ntfs_attr *mft_na;
s64 old_data_initialized, old_data_size;
ntfs_attr_search_ctx *ctx;
@ -1199,7 +1201,6 @@ static int ntfs_mft_record_init(ntfs_volume *vol, s64 size)
/* NOTE: Caller must sanity check vol, vol->mft_na and vol->mftbmp_na */
mft_na = vol->mft_na;
mftbmp_na = vol->mftbmp_na;
/*
* The mft record is outside the initialized data. Extend the mft data
@ -1295,14 +1296,13 @@ undo_data_init:
static int ntfs_mft_rec_init(ntfs_volume *vol, s64 size)
{
int ret = -1;
ntfs_attr *mft_na, *mftbmp_na;
ntfs_attr *mft_na;
s64 old_data_initialized, old_data_size;
ntfs_attr_search_ctx *ctx;
ntfs_log_enter("Entering\n");
mft_na = vol->mft_na;
mftbmp_na = vol->mftbmp_na;
if (size > mft_na->allocated_size || size > mft_na->initialized_size) {
errno = EIO;

View File

@ -47,7 +47,8 @@
* EIO Multi sector transfer error was detected. Magic of the NTFS
* record in @b will have been set to "BAAD".
*/
int ntfs_mst_post_read_fixup(NTFS_RECORD *b, const u32 size)
int ntfs_mst_post_read_fixup_warn(NTFS_RECORD *b, const u32 size,
BOOL warn)
{
u16 usa_ofs, usa_count, usn;
u16 *usa_pos, *data_pos;
@ -63,9 +64,14 @@ int ntfs_mst_post_read_fixup(NTFS_RECORD *b, const u32 size)
(u32)(usa_ofs + (usa_count * 2)) > size ||
(size >> NTFS_BLOCK_SIZE_BITS) != usa_count) {
errno = EINVAL;
ntfs_log_perror("%s: magic: 0x%08x size: %d usa_ofs: %d "
"usa_count: %d", __FUNCTION__, *(le32 *)b,
size, usa_ofs, usa_count);
if (warn) {
ntfs_log_perror("%s: magic: 0x%08lx size: %ld "
" usa_ofs: %d usa_count: %u",
__FUNCTION__,
(long)le32_to_cpu(*(le32 *)b),
(long)size, (int)usa_ofs,
(unsigned int)usa_count);
}
return -1;
}
/* Position of usn in update sequence array. */
@ -118,6 +124,16 @@ int ntfs_mst_post_read_fixup(NTFS_RECORD *b, const u32 size)
return 0;
}
/*
* Deprotect multi sector transfer protected data
* with a warning if an error is found.
*/
int ntfs_mst_post_read_fixup(NTFS_RECORD *b, const u32 size)
{
return (ntfs_mst_post_read_fixup_warn(b,size,TRUE));
}
/**
* ntfs_mst_pre_write_fixup - apply multi sector transfer protection
* @b: pointer to the data to protect

View File

@ -25,8 +25,11 @@
#include "types.h"
#include "layout.h"
#include "volume.h"
extern int ntfs_mst_post_read_fixup(NTFS_RECORD *b, const u32 size);
extern int ntfs_mst_post_read_fixup_warn(NTFS_RECORD *b, const u32 size,
BOOL warn);
extern int ntfs_mst_pre_write_fixup(NTFS_RECORD *b, const u32 size);
extern void ntfs_mst_post_write_fixup(NTFS_RECORD *b);

View File

@ -36,6 +36,18 @@
#include "types.h"
#ifndef GEKKO
/*
* assume "struct timespec" is not defined if st_mtime is not defined
*/
#if !defined(st_mtime) & !defined(__timespec_defined)
struct timespec {
time_t tv_sec;
long tv_nsec;
} ;
#endif
#endif
/*
* There are four times more conversions of internal representation
* to ntfs representation than any other conversion, so the most

View File

@ -287,7 +287,6 @@ static int remove_object_id_index(ntfs_attr *na, ntfs_index_context *xo,
if (size >= (s64)sizeof(GUID)) {
memcpy(&key.object_id,
&old_attr->object_id,sizeof(GUID));
size = sizeof(GUID);
if (!ntfs_index_lookup(&key,
sizeof(OBJECT_ID_INDEX_KEY), xo)) {
entry = (struct OBJECT_ID_INDEX*)xo->entry;
@ -300,7 +299,6 @@ static int remove_object_id_index(ntfs_attr *na, ntfs_index_context *xo,
memcpy(&old_attr->domain_id,
&entry->data.domain_id,
sizeof(GUID));
size = sizeof(OBJECT_ID_ATTR);
if (ntfs_index_rm(xo))
ret = -1;
}

View File

@ -50,6 +50,19 @@ enum {
/* maximum cluster size for allowing compression for new files */
#define MAX_COMPRESSION_CLUSTER_SIZE 4096
/*
* Use of big write buffers
*
* With small volumes, the cluster allocator may fail to allocate
* enough clusters when the volume is nearly full. At most a run
* can be allocated per bitmap chunk. So, there is a danger when the
* number of chunks (capacity/(32768*clsiz)) is less than the number
* of clusters in the biggest write buffer (131072/clsiz). Hence
* a safe minimal capacity is 4GB
*/
#define SAFE_CAPACITY_FOR_BIG_WRITES 0x100000000LL
/*
* Parameters for runlists
*/
@ -63,6 +76,11 @@ enum {
#define XATTRMAPPINGFILE ".NTFS-3G/XattrMapping" /* default mapping file */
/*
* Parameters for path canonicalization
*/
#define MAPPERNAMELTH 256
/*
* Permission checking modes for high level and low level

103
source/realpath.c Normal file
View File

@ -0,0 +1,103 @@
/*
* realpath.c - realpath() aware of device mapper
* Originated from the util-linux project.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#ifdef HAVE_LIMITS_H
#include <limits.h>
#endif
#ifdef HAVE_CTYPE_H
#include <ctype.h>
#endif
#include "param.h"
#include "realpath.h"
/* If there is no realpath() on the system, provide a dummy one. */
#ifndef HAVE_REALPATH
char *ntfs_realpath(const char *path, char *resolved_path)
{
strncpy(resolved_path, path, PATH_MAX);
resolved_path[PATH_MAX] = '\0';
return resolved_path;
}
#endif
#ifdef linux
/*
* Converts private "dm-N" names to "/dev/mapper/<name>"
*
* Since 2.6.29 (patch 784aae735d9b0bba3f8b9faef4c8b30df3bf0128) kernel sysfs
* provides the real DM device names in /sys/block/<ptname>/dm/name
*/
static char *
canonicalize_dm_name(const char *ptname, char *canonical)
{
FILE *f;
size_t sz;
char path[MAPPERNAMELTH + 24];
char name[MAPPERNAMELTH + 16];
char *res = NULL;
snprintf(path, sizeof(path), "/sys/block/%s/dm/name", ptname);
if (!(f = fopen(path, "r")))
return NULL;
/* read "<name>\n" from sysfs */
if (fgets(name, sizeof(name), f) && (sz = strlen(name)) > 1) {
name[sz - 1] = '\0';
snprintf(path, sizeof(path), "/dev/mapper/%s", name);
res = strcpy(canonical, path);
}
fclose(f);
return res;
}
/*
* Canonicalize a device path
*
* Workaround from "basinilya" for fixing device mapper paths.
*
* Background (Phillip Susi, 2011-04-09)
* - ntfs-3g canonicalizes the device name so that if you mount with
* /dev/mapper/foo, the device name listed in mtab is /dev/dm-n,
* so you can not umount /dev/mapper/foo
* - umount won't even recognize and translate /dev/dm-n to the mount
* point, apparently because of the '-' involved. Editing mtab and
* removing the '-' allows you to umount /dev/dmn successfully.
*
* This code restores the devmapper name after canonicalization,
* until a proper fix is implemented.
*/
char *ntfs_realpath_canonicalize(const char *path, char *canonical)
{
char *p;
if (path == NULL)
return NULL;
if (!ntfs_realpath(path, canonical))
return NULL;
p = strrchr(canonical, '/');
if (p && strncmp(p, "/dm-", 4) == 0 && isdigit(*(p + 4))) {
p = canonicalize_dm_name(p+1, canonical);
if (p)
return p;
}
return canonical;
}
#endif

24
source/realpath.h Normal file
View File

@ -0,0 +1,24 @@
/*
* realpath.h - realpath() aware of device mapper
*/
#ifndef REALPATH_H
#define REALPATH_H
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_REALPATH
#define ntfs_realpath realpath
#else
extern char *ntfs_realpath(const char *path, char *resolved_path);
#endif
#ifdef linux
extern char *ntfs_realpath_canonicalize(const char *path, char *resolved_path);
#else
#define ntfs_realpath_canonicalize ntfs_realpath
#endif
#endif /* REALPATH_H */

View File

@ -136,9 +136,10 @@ runlist_element *ntfs_rl_extend(ntfs_attr *na, runlist_element *rl,
if (!newrl) {
errno = ENOMEM;
rl = (runlist_element*)NULL;
} else
} else {
na->rl = newrl;
rl = &newrl[irl];
}
} else {
ntfs_log_error("Cannot extend unmapped runlist");
errno = EIO;
@ -1623,7 +1624,7 @@ errno_set:
int ntfs_rl_truncate(runlist **arl, const VCN start_vcn)
{
runlist *rl;
BOOL is_end = FALSE;
/* BOOL is_end = FALSE; */
if (!arl || !*arl) {
errno = EINVAL;
@ -1666,8 +1667,10 @@ int ntfs_rl_truncate(runlist **arl, const VCN start_vcn)
*/
if (rl->length) {
++rl;
/*
if (!rl->length)
is_end = TRUE;
*/
rl->vcn = start_vcn;
rl->length = 0;
}
@ -1675,7 +1678,7 @@ int ntfs_rl_truncate(runlist **arl, const VCN start_vcn)
/**
* Reallocate memory if necessary.
* FIXME: Below code is broken, because runlist allocations must be
* a multiply of 4096. The code caused crashes and corruptions.
* a multiple of 4096. The code caused crashes and corruptions.
*/
/*
if (!is_end) {

View File

@ -1064,7 +1064,6 @@ static int upgrade_secur_desc(ntfs_volume *vol,
na = ntfs_attr_open(ni, AT_STANDARD_INFORMATION,
AT_UNNAMED, 0);
if (na) {
res = 0;
/* expand standard information attribute to v3.x */
res = ntfs_attr_truncate(na,
(s64)sizeof(STANDARD_INFORMATION));
@ -2013,7 +2012,6 @@ int ntfs_get_posix_acl(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
const SID *gsid; /* group of file/directory */
uid_t uid;
gid_t gid;
int perm;
BOOL isdir;
size_t outsize;
@ -2048,7 +2046,6 @@ int ntfs_get_posix_acl(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
* fetch owner and group for cacheing
*/
if (pxdesc) {
perm = pxdesc->mode & 07777;
/*
* Create a security id if there were none
* and upgrade option is selected
@ -2062,11 +2059,10 @@ int ntfs_get_posix_acl(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
#if OWNERFROMACL
uid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
#else
if (!perm && ntfs_same_sid(usid, adminsid)) {
if (!(pxdesc->mode & 07777)
&& ntfs_same_sid(usid, adminsid)) {
uid = find_tenant(scx,
securattr);
if (uid)
perm = 0700;
} else
uid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
#endif
@ -2893,7 +2889,6 @@ int ntfs_set_posix_acl(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
uid_t uid;
uid_t gid;
int res;
mode_t mode;
BOOL isdir;
BOOL deflt;
BOOL exist;
@ -2919,7 +2914,6 @@ int ntfs_set_posix_acl(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
gid = cached->gid;
oldpxdesc = cached->pxdesc;
if (oldpxdesc) {
mode = oldpxdesc->mode;
newpxdesc = ntfs_replace_acl(oldpxdesc,
(const struct POSIX_ACL*)value,count,deflt);
}
@ -2946,7 +2940,6 @@ int ntfs_set_posix_acl(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
|| (!exist && (flags & XATTR_REPLACE))) {
errno = (exist ? EEXIST : ENODATA);
} else {
mode = oldpxdesc->mode;
newpxdesc = ntfs_replace_acl(oldpxdesc,
(const struct POSIX_ACL*)value,count,deflt);
}
@ -3513,16 +3506,16 @@ int ntfs_set_owner(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
int ntfs_set_ownmod(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
uid_t uid, gid_t gid, const mode_t mode)
{
const SECURITY_DESCRIPTOR_RELATIVE *phead;
const struct CACHED_PERMISSIONS *cached;
char *oldattr;
const SID *usid;
const SID *gsid;
uid_t fileuid;
uid_t filegid;
BOOL isdir;
int res;
#if POSIXACLS
const SECURITY_DESCRIPTOR_RELATIVE *phead;
const SID *usid;
const SID *gsid;
BOOL isdir;
const struct POSIX_SECURITY *oldpxdesc;
struct POSIX_SECURITY *newpxdesc = (struct POSIX_SECURITY*)NULL;
int pxsize;
@ -3555,6 +3548,7 @@ int ntfs_set_ownmod(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
filegid = 0;
oldattr = getsecurityattr(scx->vol, ni);
if (oldattr) {
#if POSIXACLS
isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)
!= const_cpu_to_le16(0);
phead = (const SECURITY_DESCRIPTOR_RELATIVE*)
@ -3567,7 +3561,6 @@ int ntfs_set_ownmod(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
usid = (const SID*)
&oldattr[le32_to_cpu(phead->owner)];
#endif
#if POSIXACLS
newpxdesc = ntfs_build_permissions_posix(scx->mapping, oldattr,
usid, gsid, isdir);
if (!newpxdesc || ntfs_merge_mode_posix(newpxdesc, mode))
@ -4784,6 +4777,7 @@ BOOL ntfs_set_file_attributes(struct SECURITY_API *scapi,
ni->flags = (ni->flags & ~settable)
| (cpu_to_le32(attrib) & settable);
NInoSetDirty(ni);
NInoFileNameSetDirty(ni);
}
if (!ntfs_inode_close(ni))
res = -1;

View File

@ -1,5 +1,5 @@
/*
* types.h - Misc type definitions not related to on-disk structure.
* types.h - Misc type definitions not related to on-disk structure.
* Originated from the Linux-NTFS project.
*
* Copyright (c) 2000-2004 Anton Altaparmakov

View File

@ -1262,7 +1262,7 @@ void ntfs_upcase_table_build(ntfschar *uc, u32 uc_len)
u32 ntfs_upcase_build_default(ntfschar **upcase)
{
u32 upcase_len;
u32 upcase_len = 0;
*upcase = (ntfschar*)ntfs_malloc(UPCASE_LEN*2);
if (*upcase) {
@ -1406,16 +1406,18 @@ BOOL ntfs_collapsible_chars(ntfs_volume *vol,
{
BOOL collapsible;
unsigned int ch;
unsigned int cs;
int i;
collapsible = shortlen == longlen;
if (collapsible)
for (i=0; i<shortlen; i++) {
ch = le16_to_cpu(longname[i]);
if ((ch >= vol->upcase_len)
|| ((shortname[i] != longname[i])
&& (shortname[i] != vol->upcase[ch])))
collapsible = FALSE;
for (i=0; collapsible && (i<shortlen); i++) {
ch = le16_to_cpu(longname[i]);
cs = le16_to_cpu(shortname[i]);
if ((cs != ch)
&& ((ch >= vol->upcase_len)
|| (cs >= vol->upcase_len)
|| (vol->upcase[cs] != vol->upcase[ch])))
collapsible = FALSE;
}
return (collapsible);
}

View File

@ -54,6 +54,7 @@
#include <locale.h>
#endif
#include "param.h"
#include "compat.h"
#include "volume.h"
#include "attrib.h"
@ -67,6 +68,7 @@
#include "dir.h"
#include "logging.h"
#include "cache.h"
#include "realpath.h"
#include "misc.h"
const char *ntfs_home =
@ -373,6 +375,12 @@ mft_has_no_attr_list:
/* Done with the $Mft mft record. */
ntfs_attr_put_search_ctx(ctx);
ctx = NULL;
/* Update the size fields in the inode. */
vol->mft_ni->data_size = vol->mft_na->data_size;
vol->mft_ni->allocated_size = vol->mft_na->allocated_size;
set_nino_flag(vol->mft_ni, KnownSize);
/*
* The volume is now setup so we can use all read access functions.
*/
@ -494,6 +502,12 @@ ntfs_volume *ntfs_volume_startup(struct ntfs_device *dev, unsigned long flags)
NVolSetShowSysFiles(vol);
NVolSetShowHidFiles(vol);
NVolClearHideDotFiles(vol);
/* set default compression */
#if DEFAULT_COMPRESSION
NVolSetCompression(vol);
#else
NVolClearCompression(vol);
#endif
if (flags & MS_RDONLY)
NVolSetReadOnly(vol);
@ -1359,18 +1373,6 @@ int ntfs_umount(ntfs_volume *vol, const BOOL force __attribute__((unused)))
#ifdef HAVE_MNTENT_H
#ifndef HAVE_REALPATH
/**
* realpath - If there is no realpath on the system
*/
static char *realpath(const char *path, char *resolved_path)
{
strncpy(resolved_path, path, PATH_MAX);
resolved_path[PATH_MAX] = '\0';
return resolved_path;
}
#endif
/**
* ntfs_mntent_check - desc
*
@ -1394,7 +1396,7 @@ static int ntfs_mntent_check(const char *file, unsigned long *mnt_flags)
err = errno;
goto exit;
}
if (!realpath(file, real_file)) {
if (!ntfs_realpath_canonicalize(file, real_file)) {
err = errno;
goto exit;
}
@ -1403,7 +1405,7 @@ static int ntfs_mntent_check(const char *file, unsigned long *mnt_flags)
goto exit;
}
while ((mnt = getmntent(f))) {
if (!realpath(mnt->mnt_fsname, real_fsname))
if (!ntfs_realpath_canonicalize(mnt->mnt_fsname, real_fsname))
continue;
if (!strcmp(real_file, real_fsname))
break;
@ -1730,3 +1732,113 @@ int ntfs_volume_get_free_space(ntfs_volume *vol)
}
return (ret);
}
/**
* ntfs_volume_rename - change the current label on a volume
* @vol: volume to change the label on
* @label: the new label
* @label_len: the length of @label in ntfschars including the terminating NULL
* character, which is mandatory (the value can not exceed 128)
*
* Change the label on the volume @vol to @label.
*/
int ntfs_volume_rename(ntfs_volume *vol, ntfschar *label, int label_len)
{
ntfs_attr *na;
char *old_vol_name;
char *new_vol_name = NULL;
int new_vol_name_len;
int err;
if (NVolReadOnly(vol)) {
ntfs_log_error("Refusing to change label on read-only mounted "
"volume.\n");
errno = EROFS;
return -1;
}
label_len *= sizeof(ntfschar);
if (label_len > 0x100) {
ntfs_log_error("New label is too long. Maximum %u characters "
"allowed.\n",
(unsigned)(0x100 / sizeof(ntfschar)));
errno = ERANGE;
return -1;
}
na = ntfs_attr_open(vol->vol_ni, AT_VOLUME_NAME, AT_UNNAMED, 0);
if (!na) {
if (errno != ENOENT) {
err = errno;
ntfs_log_perror("Lookup of $VOLUME_NAME attribute "
"failed");
goto err_out;
}
/* The volume name attribute does not exist. Need to add it. */
if (ntfs_attr_add(vol->vol_ni, AT_VOLUME_NAME, AT_UNNAMED, 0,
(u8*) label, label_len))
{
err = errno;
ntfs_log_perror("Encountered error while adding "
"$VOLUME_NAME attribute");
goto err_out;
}
}
else {
s64 written;
if (NAttrNonResident(na)) {
err = errno;
ntfs_log_error("Error: Attribute $VOLUME_NAME must be "
"resident.\n");
goto err_out;
}
if (na->data_size != label_len) {
if (ntfs_attr_truncate(na, label_len)) {
err = errno;
ntfs_log_perror("Error resizing resident "
"attribute");
goto err_out;
}
}
if (label_len) {
written = ntfs_attr_pwrite(na, 0, label_len, label);
if (written == -1) {
err = errno;
ntfs_log_perror("Error when writing "
"$VOLUME_NAME data");
goto err_out;
}
else if (written != label_len) {
err = EIO;
ntfs_log_error("Partial write when writing "
"$VOLUME_NAME data.");
goto err_out;
}
}
}
new_vol_name_len =
ntfs_ucstombs(label, label_len, &new_vol_name, 0);
if (new_vol_name_len == -1) {
err = errno;
ntfs_log_perror("Error while decoding new volume name");
goto err_out;
}
old_vol_name = vol->vol_name;
vol->vol_name = new_vol_name;
free(old_vol_name);
err = 0;
err_out:
if (na)
ntfs_attr_close(na);
if (err)
errno = err;
return err ? -1 : 0;
}

View File

@ -113,6 +113,7 @@ typedef enum {
NV_ShowHidFiles, /* 1: Show files marked hidden. */
NV_HideDotFiles, /* 1: Set hidden flag on dot files */
NV_Compression, /* 1: allow compression */
NV_NoFixupWarn, /* 1: Do not log fixup errors */
} ntfs_volume_state_bits;
#define test_nvol_flag(nv, flag) test_bit(NV_##flag, (nv)->state)
@ -147,6 +148,10 @@ typedef enum {
#define NVolSetCompression(nv) set_nvol_flag(nv, Compression)
#define NVolClearCompression(nv) clear_nvol_flag(nv, Compression)
#define NVolNoFixupWarn(nv) test_nvol_flag(nv, NoFixupWarn)
#define NVolSetNoFixupWarn(nv) set_nvol_flag(nv, NoFixupWarn)
#define NVolClearNoFixupWarn(nv) clear_nvol_flag(nv, NoFixupWarn)
/*
* NTFS version 1.1 and 1.2 are used by Windows NT4.
* NTFS version 2.x is used by Windows 2000 Beta
@ -297,6 +302,7 @@ extern int ntfs_volume_error(int err);
extern void ntfs_mount_error(const char *vol, const char *mntpoint, int err);
extern int ntfs_volume_get_free_space(ntfs_volume *vol);
extern int ntfs_volume_rename(ntfs_volume *vol, ntfschar *label, int label_len);
extern int ntfs_set_shown_files(ntfs_volume *vol,
BOOL show_sys_files, BOOL show_hid_files, BOOL hide_dot_files);