diff --git a/configure.ac b/configure.ac index 7e85411b..9bf58d94 100644 --- a/configure.ac +++ b/configure.ac @@ -23,8 +23,8 @@ # Autoconf AC_PREREQ(2.59) -AC_INIT([ntfs-3g],[2009.2.1],[ntfs-3g-devel@lists.sf.net]) -LIBNTFS_3G_VERSION="49" +AC_INIT([ntfs-3g],[2009.3.8],[ntfs-3g-devel@lists.sf.net]) +LIBNTFS_3G_VERSION="52" AC_CONFIG_SRCDIR([src/ntfs-3g.c]) # Environment diff --git a/include/ntfs-3g/attrib.h b/include/ntfs-3g/attrib.h index 7425d12c..6a9d31f3 100644 --- a/include/ntfs-3g/attrib.h +++ b/include/ntfs-3g/attrib.h @@ -93,6 +93,8 @@ extern int ntfs_attr_lookup(const ATTR_TYPES type, const ntfschar *name, const VCN lowest_vcn, const u8 *val, const u32 val_len, ntfs_attr_search_ctx *ctx); +extern int ntfs_attr_position(const ATTR_TYPES type, ntfs_attr_search_ctx *ctx); + extern ATTR_DEF *ntfs_attr_find_in_attrdef(const ntfs_volume *vol, const ATTR_TYPES type); diff --git a/include/ntfs-3g/mft.h b/include/ntfs-3g/mft.h index 089a195d..bb15f0f3 100644 --- a/include/ntfs-3g/mft.h +++ b/include/ntfs-3g/mft.h @@ -52,7 +52,7 @@ static __inline__ int ntfs_mft_record_read(const ntfs_volume *vol, { int ret; - ntfs_log_enter("Entering for inode %lld\n", MREF(mref)); + ntfs_log_enter("Entering for inode %lld\n", (long long)MREF(mref)); ret = ntfs_mft_records_read(vol, mref, 1, b); ntfs_log_leave("\n"); return ret; @@ -87,7 +87,7 @@ static __inline__ int ntfs_mft_record_write(const ntfs_volume *vol, { int ret; - ntfs_log_enter("Entering for inode %lld\n", MREF(mref)); + ntfs_log_enter("Entering for inode %lld\n", (long long)MREF(mref)); ret = ntfs_mft_records_write(vol, mref, 1, b); ntfs_log_leave("\n"); return ret; diff --git a/libntfs-3g/attrib.c b/libntfs-3g/attrib.c index b8b464bb..54b644bc 100644 --- a/libntfs-3g/attrib.c +++ b/libntfs-3g/attrib.c @@ -567,14 +567,14 @@ int ntfs_attr_map_whole_runlist(ntfs_attr *na) ntfs_attr_search_ctx *ctx; ntfs_volume *vol = na->ni->vol; ATTR_RECORD *a; - int err; + int ret = -1; - ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x.\n", - (unsigned long long)na->ni->mft_no, na->type); + ntfs_log_enter("Entering for inode %llu, attr 0x%x.\n", + (unsigned long long)na->ni->mft_no, na->type); ctx = ntfs_attr_get_search_ctx(na->ni, NULL); if (!ctx) - return -1; + goto out; /* Map all attribute extents one by one. */ next_vcn = last_vcn = highest_vcn = 0; @@ -645,17 +645,13 @@ int ntfs_attr_map_whole_runlist(ntfs_attr *na) (long long)highest_vcn, (long long)last_vcn); goto err_out; } - err = errno; + if (errno == ENOENT) + ret = 0; +err_out: ntfs_attr_put_search_ctx(ctx); - if (err == ENOENT) - return 0; -out_now: - errno = err; - return -1; -err_out: - err = errno; - ntfs_attr_put_search_ctx(ctx); - goto out_now; +out: + ntfs_log_leave("\n"); + return ret; } /** @@ -915,8 +911,9 @@ res_err_out: to_read = min(count, (rl->length << vol->cluster_size_bits) - ofs); retry: - ntfs_log_trace("Reading 0x%llx bytes from vcn 0x%llx, lcn 0x%llx, " - "ofs 0x%llx.\n", to_read, rl->vcn, rl->lcn, ofs); + ntfs_log_trace("Reading %lld bytes from vcn %lld, lcn %lld, ofs" + " %lld.\n", (long long)to_read, (long long)rl->vcn, + (long long )rl->lcn, (long long)ofs); br = ntfs_pread(vol->dev, (rl->lcn << vol->cluster_size_bits) + ofs, to_read, b); /* If everything ok, update progress counters and continue. */ @@ -967,7 +964,7 @@ rl_err_out: */ s64 ntfs_attr_pread(ntfs_attr *na, const s64 pos, s64 count, void *b) { - int ret; + s64 ret; if (!na || !na->ni || !na->ni->vol || !b || pos < 0 || count < 0) { errno = EINVAL; @@ -1049,7 +1046,8 @@ static int ntfs_attr_fill_hole(ntfs_attr *na, s64 count, s64 *ofs, from_vcn = (*rl)->vcn + (*ofs >> vol->cluster_size_bits); ntfs_log_trace("count: %lld, cur_vcn: %lld, from: %lld, to: %lld, ofs: " - "%lld\n", count, cur_vcn, from_vcn, to_write, *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. */ if (ntfs_attr_map_whole_runlist(na)) @@ -1181,15 +1179,16 @@ s64 ntfs_attr_pwrite(ntfs_attr *na, const s64 pos, s64 count, const void *b) ntfs_volume *vol; ntfs_attr_search_ctx *ctx = NULL; runlist_element *rl; - s64 eo, hole; + s64 hole_end; + int eo; struct { unsigned int undo_initialized_size : 1; unsigned int undo_data_size : 1; } need_to = { 0, 0 }; - ntfs_log_enter("Entering for inode 0x%llx, attr 0x%x, pos 0x%llx, count " - "0x%llx.\n", na->ni->mft_no, na->type, (long long)pos, - (long long)count); + ntfs_log_enter("Entering for inode %lld, attr 0x%x, pos 0x%llx, count " + "0x%llx.\n", (long long)na->ni->mft_no, na->type, + (long long)pos, (long long)count); if (!na || !na->ni || !na->ni->vol || !b || pos < 0 || count < 0) { errno = EINVAL; @@ -1326,7 +1325,7 @@ s64 ntfs_attr_pwrite(ntfs_attr *na, const s64 pos, s64 count, const void *b) * length. */ ofs = pos - (rl->vcn << vol->cluster_size_bits); - for (hole = 0; count; rl++, ofs = 0, hole = 0) { + for (hole_end = 0; count; rl++, ofs = 0, hole_end = 0) { if (rl->lcn == LCN_RL_NOT_MAPPED) { rl = ntfs_attr_find_vcn(na, rl->vcn); if (!rl) { @@ -1347,7 +1346,7 @@ s64 ntfs_attr_pwrite(ntfs_attr *na, const s64 pos, s64 count, const void *b) } if (rl->lcn < (LCN)0) { - hole = rl->vcn + rl->length; + hole_end = rl->vcn + rl->length; if (rl->lcn != (LCN)LCN_HOLE) { errno = EIO; @@ -1364,38 +1363,38 @@ s64 ntfs_attr_pwrite(ntfs_attr *na, const s64 pos, s64 count, const void *b) to_write = min(count, (rl->length << vol->cluster_size_bits) - ofs); retry: ntfs_log_trace("Writing %lld bytes to vcn %lld, lcn %lld, ofs " - "%lld.\n", to_write, rl->vcn, rl->lcn, ofs); + "%lld.\n", (long long)to_write, (long long)rl->vcn, + (long long)rl->lcn, (long long)ofs); if (!NVolReadOnly(vol)) { s64 wpos = (rl->lcn << vol->cluster_size_bits) + ofs; s64 wend = (rl->vcn << vol->cluster_size_bits) + ofs + to_write; u32 bsize = vol->cluster_size; - s64 rounded = ((wend + bsize - 1) & ~(s64)(bsize - 1)) - wend; - - /* - * Zero fill to cluster boundary if we're writing to an - * ex-sparse cluster or we're at the end of the attribute. + /* Byte size needed to zero fill a cluster */ + s64 rounding = ((wend + bsize - 1) & ~(s64)(bsize - 1)) - wend; + /** + * Zero fill to cluster boundary if we're writing at the + * end of the attribute or into an ex-sparse cluster. * This will cause the kernel not to seek and read disk * blocks during write(2) to fill the end of the buffer * which increases write speed by 2-10 fold typically. */ - if ((rounded && (wend < (hole << vol->cluster_size_bits))) || - (((to_write % bsize) && - (ofs + to_write == na->initialized_size)))) { + if (rounding && ((wend == na->initialized_size) || + (wend < (hole_end << vol->cluster_size_bits)))){ char *cb; - rounded += to_write; + rounding += to_write; - cb = ntfs_malloc(rounded); + cb = ntfs_malloc(rounding); if (!cb) goto err_out; memcpy(cb, b, to_write); - memset(cb + to_write, 0, rounded - to_write); + memset(cb + to_write, 0, rounding - to_write); - written = ntfs_pwrite(vol->dev, wpos, rounded, cb); - if (written == rounded) + written = ntfs_pwrite(vol->dev, wpos, rounding, cb); + if (written == rounding) written = to_write; free(cb); @@ -1443,7 +1442,6 @@ rl_err_out: * TODO: Need to try to change initialized_size. If it * succeeds goto done, otherwise goto err_out. (AIA) */ - errno = EOPNOTSUPP; goto err_out; } goto done; @@ -2368,6 +2366,36 @@ out: return ret; } +/** + * ntfs_attr_position - find given or next attribute type in an ntfs inode + * @type: attribute type to start lookup + * @ctx: search context with mft record and attribute to search from + * + * Find an attribute type in an ntfs inode or the next attribute which is not + * the AT_END attribute. Please see more details at ntfs_attr_lookup. + * + * Return 0 if the search was successful and -1 if not, with errno set to the + * error code. + * + * The following error codes are defined: + * EINVAL Invalid arguments. + * EIO I/O error or corrupt data structures found. + * ENOMEM Not enough memory to allocate necessary buffers. + * ENOSPC No attribute was found after 'type', only AT_END. + */ +int ntfs_attr_position(const ATTR_TYPES type, ntfs_attr_search_ctx *ctx) +{ + if (ntfs_attr_lookup(type, NULL, 0, CASE_SENSITIVE, 0, NULL, 0, ctx)) { + if (errno != ENOENT) + return -1; + if (ctx->attr->type == AT_END) { + errno = ENOSPC; + return -1; + } + } + return 0; +} + /** * ntfs_attr_init_search_ctx - initialize an attribute search context * @ctx: attribute search context to initialize @@ -3124,8 +3152,8 @@ int ntfs_attr_add(ntfs_inode *ni, ATTR_TYPES type, return -1; } - ntfs_log_trace("Entering for inode 0x%llx, attr %x, size %lld.\n", - (long long) ni->mft_no, type, size); + ntfs_log_trace("Entering for inode %lld, attr %x, size %lld.\n", + (long long)ni->mft_no, type, (long long)size); if (ni->nr_extents == -1) ni = ni->base_ni; @@ -3390,6 +3418,14 @@ int ntfs_attr_record_resize(MFT_RECORD *m, ATTR_RECORD *a, u32 new_size) "(%u > %u)\n", new_muse, alloc_size); return -1; } + + if (a->type == AT_INDEX_ROOT && new_size > attr_size && + new_muse + 120 > alloc_size && old_size + 120 <= alloc_size) { + errno = ENOSPC; + ntfs_log_trace("Too big INDEX_ROOT (%u > %u)\n", + new_muse, alloc_size); + return STATUS_RESIDENT_ATTRIBUTE_FILLED_MFT; + } /* Move attributes following @a to their new location. */ memmove((u8 *)a + new_size, (u8 *)a + attr_size, @@ -3422,12 +3458,14 @@ int ntfs_attr_record_resize(MFT_RECORD *m, ATTR_RECORD *a, u32 new_size) int ntfs_resident_attr_value_resize(MFT_RECORD *m, ATTR_RECORD *a, const u32 new_size) { + int ret; + ntfs_log_trace("Entering for new size %u.\n", (unsigned)new_size); /* Resize the resident part of the attribute record. */ - if (ntfs_attr_record_resize(m, a, (le16_to_cpu(a->value_offset) + - new_size + 7) & ~7) < 0) - return -1; + if ((ret = ntfs_attr_record_resize(m, a, (le16_to_cpu(a->value_offset) + + new_size + 7) & ~7)) < 0) + return ret; /* * If we made the attribute value bigger, clear the area between the * old size and @new_size. @@ -3783,6 +3821,9 @@ cluster_free_err_out: return -1; } + +static int ntfs_resident_attr_resize(ntfs_attr *na, const s64 newsize); + /** * ntfs_resident_attr_resize - resize a resident, open ntfs attribute * @na: resident ntfs attribute to resize @@ -3799,7 +3840,7 @@ cluster_free_err_out: * ERANGE - @newsize is not valid for the attribute type of @na. * ENOSPC - There is no enough space in base mft to resize $ATTRIBUTE_LIST. */ -static int ntfs_resident_attr_resize(ntfs_attr *na, const s64 newsize) +static int ntfs_resident_attr_resize_i(ntfs_attr *na, const s64 newsize) { ntfs_attr_search_ctx *ctx; ntfs_volume *vol; @@ -3839,8 +3880,8 @@ static int ntfs_resident_attr_resize(ntfs_attr *na, const s64 newsize) */ if (newsize < vol->mft_record_size) { /* Perform the resize of the attribute record. */ - if (!ntfs_resident_attr_value_resize(ctx->mrec, ctx->attr, - newsize)) { + if (!(ret = ntfs_resident_attr_value_resize(ctx->mrec, ctx->attr, + newsize))) { /* Update attribute size everywhere. */ na->data_size = na->initialized_size = newsize; na->allocated_size = (newsize + 7) & ~7; @@ -3853,6 +3894,11 @@ static int ntfs_resident_attr_resize(ntfs_attr *na, const s64 newsize) } goto resize_done; } + /* Prefer AT_INDEX_ALLOCATION instead of AT_ATTRIBUTE_LIST */ + if (ret == STATUS_RESIDENT_ATTRIBUTE_FILLED_MFT) { + err = errno; + goto put_err_out; + } } /* There is not enough space in the mft record to perform the resize. */ @@ -3909,6 +3955,7 @@ static int ntfs_resident_attr_resize(ntfs_attr *na, const s64 newsize) ntfs_log_perror("%s: Attribute lookup failed 1", __FUNCTION__); goto put_err_out; } + /* * The standard information and attribute list attributes can't be * moved out from the base MFT record, so try to move out others. @@ -3996,6 +4043,16 @@ put_err_out: return ret; } +static int ntfs_resident_attr_resize(ntfs_attr *na, const s64 newsize) +{ + int ret; + + ntfs_log_enter("Entering\n"); + ret = ntfs_resident_attr_resize_i(na, newsize); + ntfs_log_leave("\n"); + return ret; +} + /** * ntfs_attr_make_resident - convert a non-resident to a resident attribute * @na: open ntfs attribute to make resident @@ -4365,8 +4422,8 @@ retry: */ if (finished_build) { ntfs_log_trace("Mark attr 0x%x for delete in inode " - "0x%llx.\n", (unsigned)le32_to_cpu( - a->type), ctx->ntfs_ino->mft_no); + "%lld.\n", (unsigned)le32_to_cpu(a->type), + (long long)ctx->ntfs_ino->mft_no); a->highest_vcn = cpu_to_sle64(NTFS_VCN_DELETE_MARK); ntfs_inode_mark_dirty(ctx->ntfs_ino); continue; @@ -4761,7 +4818,7 @@ put_err_out: * ERANGE - @newsize is not valid for the attribute type of @na. * ENOSPC - There is no enough space in base mft to resize $ATTRIBUTE_LIST. */ -static int ntfs_non_resident_attr_expand(ntfs_attr *na, const s64 newsize) +static int ntfs_non_resident_attr_expand_i(ntfs_attr *na, const s64 newsize) { LCN lcn_seek_from; VCN first_free_vcn; @@ -4771,7 +4828,7 @@ static int ntfs_non_resident_attr_expand(ntfs_attr *na, const s64 newsize) s64 org_alloc_size; int err; - ntfs_log_trace("Inode 0x%llx, attr 0x%x, new size %lld old size %lld\n", + ntfs_log_trace("Inode %lld, attr 0x%x, new size %lld old size %lld\n", (unsigned long long)na->ni->mft_no, na->type, (long long)newsize, (long long)na->data_size); @@ -4955,6 +5012,17 @@ put_err_out: return -1; } + +static int ntfs_non_resident_attr_expand(ntfs_attr *na, const s64 newsize) +{ + int ret; + + ntfs_log_enter("Entering\n"); + ret = ntfs_non_resident_attr_expand_i(na, newsize); + ntfs_log_leave("\n"); + return ret; +} + /** * ntfs_attr_truncate - resize an ntfs attribute * @na: open ntfs attribute to resize @@ -4977,7 +5045,7 @@ put_err_out: */ int ntfs_attr_truncate(ntfs_attr *na, const s64 newsize) { - int ret; + int ret = STATUS_ERROR; if (!na || newsize < 0 || (na->ni->mft_no == FILE_MFT && na->type == AT_DATA)) { @@ -4986,12 +5054,14 @@ int ntfs_attr_truncate(ntfs_attr *na, const s64 newsize) return STATUS_ERROR; } - ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x, size %lld\n", - (unsigned long long)na->ni->mft_no, na->type, newsize); + ntfs_log_enter("Entering for inode %lld, attr 0x%x, size %lld\n", + (unsigned long long)na->ni->mft_no, na->type, + (long long)newsize); if (na->data_size == newsize) { ntfs_log_trace("Size is already ok\n"); - return STATUS_OK; + ret = STATUS_OK; + goto out; } /* * Encrypted attributes are not supported. We return access denied, @@ -5000,7 +5070,7 @@ int ntfs_attr_truncate(ntfs_attr *na, const s64 newsize) if (NAttrEncrypted(na)) { errno = EACCES; ntfs_log_perror("Failed to truncate encrypted attribute"); - return STATUS_ERROR; + goto out; } /* * TODO: Implement making handling of compressed attributes. @@ -5008,7 +5078,7 @@ int ntfs_attr_truncate(ntfs_attr *na, const s64 newsize) if (NAttrCompressed(na)) { errno = EOPNOTSUPP; ntfs_log_perror("Failed to truncate compressed attribute"); - return STATUS_ERROR; + goto out; } if (NAttrNonResident(na)) { if (newsize > na->data_size) @@ -5017,8 +5087,8 @@ int ntfs_attr_truncate(ntfs_attr *na, const s64 newsize) ret = ntfs_non_resident_attr_shrink(na, newsize); } else ret = ntfs_resident_attr_resize(na, newsize); - - ntfs_log_trace("Return status %d\n", ret); +out: + ntfs_log_leave("Return status %d\n", ret); return ret; } @@ -5130,41 +5200,61 @@ int ntfs_attr_remove(ntfs_inode *ni, const ATTR_TYPES type, ntfschar *name, return ret; } +/* Below macros are 32-bit ready. */ +#define BCX(x) ((x) - (((x) >> 1) & 0x77777777) - \ + (((x) >> 2) & 0x33333333) - \ + (((x) >> 3) & 0x11111111)) +#define BITCOUNT(x) (((BCX(x) + (BCX(x) >> 4)) & 0x0F0F0F0F) % 255) + +static u8 *ntfs_init_lut256(void) +{ + int i; + u8 *lut; + + lut = ntfs_malloc(256); + if (lut) + for(i = 0; i < 256; i++) + *(lut + i) = 8 - BITCOUNT(i); + return lut; +} + s64 ntfs_attr_get_free_bits(ntfs_attr *na) { - u8 *buf; + u8 *buf, *lut; + s64 br = 0; + s64 total = 0; s64 nr_free = 0; - s64 br, total = 0; - buf = ntfs_malloc(na->ni->vol->cluster_size); - if (!buf) + lut = ntfs_init_lut256(); + if (!lut) return -1; - while (1) { - int i, j; + + buf = ntfs_malloc(65536); + if (!buf) + goto out; - br = ntfs_attr_pread(na, total, na->ni->vol->cluster_size, buf); + while (1) { + u32 *p; + br = ntfs_attr_pread(na, total, 65536, buf); if (br <= 0) break; total += br; - for (i = 0; i < br; ) - switch (buf[i]) { - case 0 : - do { - nr_free += 8; - } while ((++i < br) && (!buf[i])); - break; - case 255 : - do { - } while ((++i < br) && (buf[i] == 255)); - break; - default : - for (j = 0; j < 8; j++) - if (!((buf[i] >> j) & 1)) - nr_free++; - i++; - } + p = (u32 *)buf + br / 4 - 1; + for (; (u8 *)p >= buf; p--) { + nr_free += lut[ *p & 255] + + lut[(*p >> 8) & 255] + + lut[(*p >> 16) & 255] + + lut[(*p >> 24) ]; + } + switch (br % 4) { + case 3: nr_free += lut[*(buf + br - 3)]; + case 2: nr_free += lut[*(buf + br - 2)]; + case 1: nr_free += lut[*(buf + br - 1)]; + } } free(buf); +out: + free(lut); if (!total || br < 0) return -1; return nr_free; diff --git a/libntfs-3g/bootsect.c b/libntfs-3g/bootsect.c index ae5d60a9..e9bea370 100644 --- a/libntfs-3g/bootsect.c +++ b/libntfs-3g/bootsect.c @@ -195,7 +195,7 @@ int ntfs_boot_sector_parse(ntfs_volume *vol, const NTFS_BOOT_SECTOR *bs) } sectors = sle64_to_cpu(bs->number_of_sectors); - ntfs_log_debug("NumberOfSectors = %lld\n", sectors); + ntfs_log_debug("NumberOfSectors = %lld\n", (long long)sectors); if (!sectors) { ntfs_log_error("Volume size is set to zero.\n"); return -1; @@ -213,8 +213,8 @@ int ntfs_boot_sector_parse(ntfs_volume *vol, const NTFS_BOOT_SECTOR *bs) vol->mft_lcn = sle64_to_cpu(bs->mft_lcn); vol->mftmirr_lcn = sle64_to_cpu(bs->mftmirr_lcn); - ntfs_log_debug("MFT LCN = 0x%llx\n", vol->mft_lcn); - ntfs_log_debug("MFTMirr LCN = 0x%llx\n", vol->mftmirr_lcn); + ntfs_log_debug("MFT LCN = %lld\n", (long long)vol->mft_lcn); + ntfs_log_debug("MFTMirr LCN = %lld\n", (long long)vol->mftmirr_lcn); if (vol->mft_lcn > vol->nr_clusters || vol->mftmirr_lcn > vol->nr_clusters) { ntfs_log_error("$MFT LCN (%lld) or $MFTMirr LCN (%lld) is " diff --git a/libntfs-3g/compress.c b/libntfs-3g/compress.c index a6be8275..09f874bb 100644 --- a/libntfs-3g/compress.c +++ b/libntfs-3g/compress.c @@ -100,8 +100,8 @@ static int ntfs_decompress(u8 *dest, const u32 dest_size, ntfs_log_trace("Entering, cb_size = 0x%x.\n", (unsigned)cb_size); do_next_sb: - ntfs_log_debug("Beginning sub-block at offset = 0x%x in the cb.\n", - cb - cb_start); + ntfs_log_debug("Beginning sub-block at offset = %d in the cb.\n", + (int)(cb - cb_start)); /* * Have we reached the end of the compression block or the end of the * decompressed data? The latter can happen for example if the current diff --git a/libntfs-3g/debug.c b/libntfs-3g/debug.c index d154fb0e..f1934833 100644 --- a/libntfs-3g/debug.c +++ b/libntfs-3g/debug.c @@ -63,9 +63,15 @@ void ntfs_debug_runlist_dump(const runlist_element *rl) if (idx > -LCN_EINVAL - 1) idx = 4; - ntfs_log_debug("%-16llx %s %-16llx%s\n", rl[i].vcn, lcn_str[idx], rl[i].length, rl[i].length ? "" : " (runlist end)"); + ntfs_log_debug("%-16lld %s %-16lld%s\n", + (long long)rl[i].vcn, lcn_str[idx], + (long long)rl[i].length, + rl[i].length ? "" : " (runlist end)"); } else - ntfs_log_debug("%-16llx %-16llx %-16llx%s\n", rl[i].vcn, rl[i].lcn, rl[i].length, rl[i].length ? "" : " (runlist end)"); + ntfs_log_debug("%-16lld %-16lld %-16lld%s\n", + (long long)rl[i].vcn, (long long)rl[i].lcn, + (long long)rl[i].length, + rl[i].length ? "" : " (runlist end)"); } while (rl[i++].length); } diff --git a/libntfs-3g/device.c b/libntfs-3g/device.c index cf4969c3..c77d8f95 100644 --- a/libntfs-3g/device.c +++ b/libntfs-3g/device.c @@ -178,7 +178,7 @@ s64 ntfs_pread(struct ntfs_device *dev, const s64 pos, s64 count, void *b) s64 br, total; struct ntfs_device_operations *dops; - ntfs_log_trace("Entering for pos 0x%llx, count 0x%llx.\n", pos, count); + ntfs_log_trace("pos %lld, count %lld\n",(long long)pos,(long long)count); if (!b || count < 0 || pos < 0) { errno = EINVAL; @@ -229,7 +229,8 @@ s64 ntfs_pwrite(struct ntfs_device *dev, const s64 pos, s64 count, s64 written, total, ret = -1; struct ntfs_device_operations *dops; - ntfs_log_trace("Entering for pos 0x%llx, count 0x%llx.\n", pos, count); + ntfs_log_trace("pos %lld, count %lld\n",(long long)pos,(long long)count); + if (!b || count < 0 || pos < 0) { errno = EINVAL; goto out; diff --git a/libntfs-3g/dir.c b/libntfs-3g/dir.c index cb57e443..e20b44de 100644 --- a/libntfs-3g/dir.c +++ b/libntfs-3g/dir.c @@ -557,8 +557,8 @@ ntfs_inode *ntfs_pathname_to_inode(ntfs_volume *vol, ntfs_inode *parent, len = ntfs_mbstoucs(p, &unicode); if (len < 0) { - ntfs_log_perror("Couldn't convert filename to Unicode: " - "'%s'.\n", p); + ntfs_log_perror("Could not convert filename to Unicode:" + " '%s'", p); err = errno; goto close; } else if (len > NTFS_MAX_NAME_LEN) { @@ -916,7 +916,7 @@ int ntfs_readdir(ntfs_inode *dir_ni, s64 *pos, * or signals an error (both covered by the rc test). */ for (;; ie = (INDEX_ENTRY*)((u8*)ie + le16_to_cpu(ie->length))) { - ntfs_log_debug("In index root, offset 0x%x.\n", (u8*)ie - (u8*)ir); + ntfs_log_debug("In index root, offset %d.\n", (int)((u8*)ie - (u8*)ir)); /* Bounds checks. */ if ((u8*)ie < (u8*)ctx->mrec || (u8*)ie + sizeof(INDEX_ENTRY_HEADER) > index_end || @@ -1565,8 +1565,9 @@ search: /* Ignore hard links from other directories */ if (dir_ni->mft_no != MREF_LE(fn->parent_directory)) { ntfs_log_debug("MFT record numbers don't match " - "(%llu != %llu)\n", dir_ni->mft_no, - MREF_LE(fn->parent_directory)); + "(%llu != %llu)\n", + (long long unsigned)dir_ni->mft_no, + (long long unsigned)MREF_LE(fn->parent_directory)); continue; } diff --git a/libntfs-3g/index.c b/libntfs-3g/index.c index 3ffc17c1..cfcbe6c3 100644 --- a/libntfs-3g/index.c +++ b/libntfs-3g/index.c @@ -84,7 +84,7 @@ static int ntfs_ib_write(ntfs_index_context *icx, INDEX_BLOCK *ib) { s64 ret, vcn = sle64_to_cpu(ib->index_block_vcn); - ntfs_log_trace("vcn: %lld\n", vcn); + ntfs_log_trace("vcn: %lld\n", (long long)vcn); ret = ntfs_attr_mst_pwrite(icx->ia_na, ntfs_ib_vcn_to_pos(icx, vcn), 1, icx->block_size, ib); @@ -587,7 +587,7 @@ static int ntfs_ib_read(ntfs_index_context *icx, VCN vcn, INDEX_BLOCK *dst) { s64 pos, ret; - ntfs_log_trace("vcn: %lld\n", vcn); + ntfs_log_trace("vcn: %lld\n", (long long)vcn); pos = ntfs_ib_vcn_to_pos(icx, vcn); @@ -748,7 +748,7 @@ descend_into_child_node: } old_vcn = vcn; - ntfs_log_debug("Descend into node with VCN %lld.\n", vcn); + ntfs_log_debug("Descend into node with VCN %lld\n", (long long)vcn); if (ntfs_ib_read(icx, vcn, ib)) goto err_out; @@ -799,7 +799,7 @@ static INDEX_BLOCK *ntfs_ib_alloc(VCN ib_vcn, u32 ib_size, INDEX_BLOCK *ib; int ih_size = sizeof(INDEX_HEADER); - ntfs_log_trace("Entering ib_vcn = %lld ib_size = %u\n", ib_vcn, ib_size); + ntfs_log_trace("ib_vcn: %lld ib_size: %u\n", (long long)ib_vcn, ib_size); ib = ntfs_calloc(ib_size); if (!ib) @@ -895,7 +895,7 @@ static int ntfs_ibm_modify(ntfs_index_context *icx, VCN vcn, int set) ntfs_attr *na; int ret = STATUS_ERROR; - ntfs_log_trace("%s vcn: %lld\n", set ? "set" : "clear", vcn); + ntfs_log_trace("%s vcn: %lld\n", set ? "set" : "clear", (long long)vcn); na = ntfs_attr_open(icx->ni, AT_BITMAP, icx->name, icx->name_len); if (!na) { @@ -972,7 +972,7 @@ static VCN ntfs_ibm_get_free(ntfs_index_context *icx) vcn = ntfs_ibm_pos_to_vcn(icx, size * 8); out: - ntfs_log_trace("allocated vcn: %lld\n", vcn); + ntfs_log_trace("allocated vcn: %lld\n", (long long)vcn); if (ntfs_ibm_set(icx, vcn)) vcn = (VCN)-1; @@ -1230,16 +1230,16 @@ static int ntfs_ir_make_space(ntfs_index_context *icx, int data_size) int ret; ntfs_log_trace("Entering\n"); - + ret = ntfs_ir_truncate(icx, data_size); if (ret == STATUS_RESIDENT_ATTRIBUTE_FILLED_MFT) { - + ret = ntfs_ir_reparent(icx); if (ret == STATUS_OK) ret = STATUS_KEEP_SEARCHING; else ntfs_log_perror("Failed to nodify INDEX_ROOT"); - } + } return ret; } diff --git a/libntfs-3g/inode.c b/libntfs-3g/inode.c index ed522026..4f03121d 100644 --- a/libntfs-3g/inode.c +++ b/libntfs-3g/inode.c @@ -158,7 +158,7 @@ ntfs_inode *ntfs_inode_open(ntfs_volume *vol, const MFT_REF mref) le32 lthle; int olderrno; - ntfs_log_enter("Entering for inode %lld\n", MREF(mref)); + ntfs_log_enter("Entering for inode %lld\n", (long long)MREF(mref)); if (!vol) { errno = EINVAL; goto out; @@ -179,8 +179,7 @@ ntfs_inode *ntfs_inode_open(ntfs_volume *vol, const MFT_REF mref) /* Receive some basic information about inode. */ if (ntfs_attr_lookup(AT_STANDARD_INFORMATION, AT_UNNAMED, 0, CASE_SENSITIVE, 0, NULL, 0, ctx)) { - ntfs_log_trace("Failed to receive STANDARD_INFORMATION " - "attribute.\n"); + ntfs_log_perror("No STANDARD_INFORMATION in base record\n"); goto put_err_out; } std_info = (STANDARD_INFORMATION *)((u8 *)ctx->attr + @@ -221,6 +220,7 @@ ntfs_inode *ntfs_inode_open(ntfs_volume *vol, const MFT_REF mref) goto put_err_out; if (l > 0x40000) { errno = EIO; + ntfs_log_perror("Too large attrlist (%lld)\n", (long long)l); goto put_err_out; } ni->attr_list_size = l; @@ -232,6 +232,8 @@ ntfs_inode *ntfs_inode_open(ntfs_volume *vol, const MFT_REF mref) goto put_err_out; if (l != ni->attr_list_size) { errno = EIO; + ntfs_log_perror("Unexpected attrlist size (%lld <> %u)\n", + (long long)l, ni->attr_list_size); goto put_err_out; } get_size: @@ -536,20 +538,17 @@ static int ntfs_inode_sync_standard_information(ntfs_inode *ni) STANDARD_INFORMATION *std_info; u32 lth; le32 lthle; - int err; - ntfs_log_trace("Entering for inode 0x%llx.\n", (long long) ni->mft_no); + ntfs_log_trace("Entering for inode %lld\n", (long long)ni->mft_no); ctx = ntfs_attr_get_search_ctx(ni, NULL); if (!ctx) return -1; if (ntfs_attr_lookup(AT_STANDARD_INFORMATION, AT_UNNAMED, - 0, CASE_SENSITIVE, 0, NULL, 0, ctx)) { - err = errno; - ntfs_log_trace("Failed to receive STANDARD_INFORMATION " - "attribute.\n"); + 0, CASE_SENSITIVE, 0, NULL, 0, ctx)) { + ntfs_log_perror("Failed to sync standard info (inode %lld)", + (long long)ni->mft_no); ntfs_attr_put_search_ctx(ctx); - errno = err; return -1; } std_info = (STANDARD_INFORMATION *)((u8 *)ctx->attr + @@ -725,8 +724,6 @@ int ntfs_inode_sync(ntfs_inode *ni) if (err != EIO) err = EBUSY; } - ntfs_log_perror("Failed to sync standard info (inode %lld)", - (long long)ni->mft_no); } /* Update FILE_NAME's in the index. */ @@ -1025,8 +1022,8 @@ err_out: } /** - * ntfs_inode_free_space - free space in the MFT record of inode - * @ni: ntfs inode in which MFT record free space + * ntfs_inode_free_space - free space in the MFT record of an inode + * @ni: ntfs inode in which MFT record needs more free space * @size: amount of space needed to free * * Return 0 on success or -1 on error with errno set to the error code. @@ -1034,7 +1031,7 @@ err_out: int ntfs_inode_free_space(ntfs_inode *ni, int size) { ntfs_attr_search_ctx *ctx; - int freed, err; + int freed; if (!ni || size < 0) { errno = EINVAL; @@ -1054,97 +1051,60 @@ int ntfs_inode_free_space(ntfs_inode *ni, int size) ctx = ntfs_attr_get_search_ctx(ni, NULL); if (!ctx) return -1; - /* - * Chkdsk complain if $STANDARD_INFORMATION is not in the base MFT - * record. FIXME: I'm not sure in this, need to recheck. For now simply - * do not move $STANDARD_INFORMATION at all. - * - * Also we can't move $ATTRIBUTE_LIST from base MFT_RECORD, so position - * search context on first attribute after $STANDARD_INFORMATION and - * $ATTRIBUTE_LIST. - * - * Why we reposition instead of simply skip this attributes during - * enumeration? Because in case we have got only in-memory attribute - * list ntfs_attr_lookup will fail when it will try to find - * $ATTRIBUTE_LIST. + * $STANDARD_INFORMATION and $ATTRIBUTE_LIST must stay in the base MFT + * record, so position search context on the first attribute after them. */ - if (ntfs_attr_lookup(AT_FILE_NAME, NULL, 0, CASE_SENSITIVE, 0, NULL, - 0, ctx)) { - if (errno != ENOENT) { - err = errno; - ntfs_log_perror("%s: attr lookup failed #2", __FUNCTION__); - goto put_err_out; - } - if (ctx->attr->type == AT_END) { - err = ENOSPC; - goto put_err_out; - } - } + if (ntfs_attr_position(AT_FILE_NAME, ctx)) + goto put_err_out; while (1) { int record_size; - /* * Check whether attribute is from different MFT record. If so, * find next, because we don't need such. */ while (ctx->ntfs_ino->mft_no != ni->mft_no) { retry: - if (ntfs_attr_lookup(AT_UNUSED, NULL, 0, CASE_SENSITIVE, - 0, NULL, 0, ctx)) { - err = errno; - if (errno != ENOENT) { - ntfs_log_perror("Attr lookup failed #2"); - } else - err = ENOSPC; + if (ntfs_attr_position(AT_UNUSED, ctx)) goto put_err_out; - } } if (ntfs_inode_base(ctx->ntfs_ino)->mft_no == FILE_MFT && ctx->attr->type == AT_DATA) goto retry; + if (ctx->attr->type == AT_INDEX_ROOT) + goto retry; + record_size = le32_to_cpu(ctx->attr->length); - /* Move away attribute. */ if (ntfs_attr_record_move_away(ctx, 0)) { - err = errno; ntfs_log_perror("Failed to move out attribute #2"); break; } freed += record_size; - /* Check whether we done. */ + /* Check whether we are done. */ if (size <= freed) { ntfs_attr_put_search_ctx(ctx); return 0; } - /* - * Reposition to first attribute after $STANDARD_INFORMATION and - * $ATTRIBUTE_LIST (see comments upwards). + * Reposition to first attribute after $STANDARD_INFORMATION + * and $ATTRIBUTE_LIST instead of simply skipping this attribute + * because in the case when we have got only in-memory attribute + * list then ntfs_attr_lookup will fail when it tries to find + * $ATTRIBUTE_LIST. */ ntfs_attr_reinit_search_ctx(ctx); - if (ntfs_attr_lookup(AT_FILE_NAME, NULL, 0, CASE_SENSITIVE, 0, - NULL, 0, ctx)) { - if (errno != ENOENT) { - err = errno; - ntfs_log_perror("Attr lookup #2 failed"); - break; - } - if (ctx->attr->type == AT_END) { - err = ENOSPC; - break; - } - } + if (ntfs_attr_position(AT_FILE_NAME, ctx)) + break; } put_err_out: ntfs_attr_put_search_ctx(ctx); - if (err == ENOSPC) - ntfs_log_trace("No attributes left that can be moved out.\n"); - errno = err; + if (errno == ENOSPC) + ntfs_log_trace("No attributes left that could be moved out.\n"); return -1; } diff --git a/libntfs-3g/lcnalloc.c b/libntfs-3g/lcnalloc.c index 5ba7af2f..1c10cdc3 100644 --- a/libntfs-3g/lcnalloc.c +++ b/libntfs-3g/lcnalloc.c @@ -57,7 +57,7 @@ static void ntfs_cluster_set_zone_pos(LCN start, LCN end, LCN *pos, LCN tc) { - ntfs_log_trace("pos: %lld tc: %lld\n", (long long)*pos, tc); + ntfs_log_trace("pos: %lld tc: %lld\n", (long long)*pos, (long long)tc); if (tc >= end) *pos = start; @@ -346,8 +346,10 @@ runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count, if (prev_lcn == lcn + bmp_pos - prev_run_len && rlpos) { ntfs_log_debug("Cluster coalesce: prev_lcn: " "%lld lcn: %lld bmp_pos: %lld " - "prev_run_len: %lld\n", prev_lcn, - lcn, bmp_pos, prev_run_len); + "prev_run_len: %lld\n", + (long long)prev_lcn, + (long long)lcn, (long long)bmp_pos, + (long long)prev_run_len); rl[rlpos - 1].length = ++prev_run_len; } else { if (rlpos) @@ -356,7 +358,7 @@ runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count, else { rl[rlpos].vcn = start_vcn; ntfs_log_debug("Start_vcn: %lld\n", - start_vcn); + (long long)start_vcn); } rl[rlpos].lcn = prev_lcn = lcn + bmp_pos; @@ -365,8 +367,9 @@ runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count, } ntfs_log_debug("RUN: %-16lld %-16lld %-16lld\n", - rl[rlpos - 1].vcn, rl[rlpos - 1].lcn, - rl[rlpos - 1].length); + (long long)rl[rlpos - 1].vcn, + (long long)rl[rlpos - 1].lcn, + (long long)rl[rlpos - 1].length); /* Done? */ if (!--clusters) { if (used_zone_pos) @@ -468,7 +471,7 @@ switch_to_data1_zone: search_zone = 2; search_zone = 1; zone_start = vol->mft_zone_pos; zone_end = vol->mft_zone_end; - if (!zone_start == vol->mft_zone_start) + if (zone_start == vol->mft_zone_start) pass = 2; break; } diff --git a/libntfs-3g/mft.c b/libntfs-3g/mft.c index ce267a37..8c539e03 100644 --- a/libntfs-3g/mft.c +++ b/libntfs-3g/mft.c @@ -1025,7 +1025,7 @@ static int ntfs_mft_data_extend_allocation(ntfs_volume *vol) "count %lli.\n", (long long)nr); } while (1); - ntfs_log_debug("Allocated %lli clusters.\n", nr); + ntfs_log_debug("Allocated %lld clusters.\n", (long long)nr); rl = ntfs_runlists_merge(mft_na->rl, rl2); if (!rl) { diff --git a/libntfs-3g/mst.c b/libntfs-3g/mst.c index b6beb39d..470942d6 100644 --- a/libntfs-3g/mst.c +++ b/libntfs-3g/mst.c @@ -63,7 +63,9 @@ 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", __FUNCTION__); + ntfs_log_perror("%s: magic: 0x%08x size: %d usa_ofs: %d " + "usa_count: %d", __FUNCTION__, *(le32 *)b, + size, usa_ofs, usa_count); return -1; } /* Position of usn in update sequence array. */ @@ -90,9 +92,12 @@ int ntfs_mst_post_read_fixup(NTFS_RECORD *b, const u32 size) * Set the magic to "BAAD" and return failure. * Note that magic_BAAD is already converted to le32. */ - b->magic = magic_BAAD; errno = EIO; - ntfs_log_perror("Incomplete multi-sector transfer"); + ntfs_log_perror("Incomplete multi-sector transfer: " + "magic: 0x%08x size: %d usa_ofs: %d usa_count:" + " %d data: %d usn: %d", *(le32 *)b, size, + usa_ofs, usa_count, *data_pos, usn); + b->magic = magic_BAAD; return -1; } data_pos += NTFS_BLOCK_SIZE/sizeof(u16); diff --git a/libntfs-3g/runlist.c b/libntfs-3g/runlist.c index de6b4f1c..0312e0cc 100644 --- a/libntfs-3g/runlist.c +++ b/libntfs-3g/runlist.c @@ -743,7 +743,7 @@ runlist_element *ntfs_runlists_merge(runlist_element *drl, * two into one, if that is possible (we check for overlap and discard the new * runlist if overlap present before returning NULL, with errno = ERANGE). */ -runlist_element *ntfs_mapping_pairs_decompress(const ntfs_volume *vol, +runlist_element *ntfs_mapping_pairs_decompress_i(const ntfs_volume *vol, const ATTR_RECORD *attr, runlist_element *old_rl) { VCN vcn; /* Current vcn. */ @@ -967,6 +967,17 @@ err_out: return NULL; } +runlist_element *ntfs_mapping_pairs_decompress(const ntfs_volume *vol, + const ATTR_RECORD *attr, runlist_element *old_rl) +{ + runlist_element *rle; + + ntfs_log_enter("Entering\n"); + rle = ntfs_mapping_pairs_decompress_i(vol, attr, old_rl); + ntfs_log_leave("\n"); + return rle; +} + /** * ntfs_rl_vcn_to_lcn - convert a vcn into a lcn given a runlist * @rl: runlist to use for conversion diff --git a/src/ntfs-3g.c b/src/ntfs-3g.c index 56321b7b..204341e3 100644 --- a/src/ntfs-3g.c +++ b/src/ntfs-3g.c @@ -3154,11 +3154,12 @@ static int parse_options(int argc, char *argv[]) { int c; - static const char *sopt = "-o:hv"; + static const char *sopt = "-o:hvV"; static const struct option lopt[] = { { "options", required_argument, NULL, 'o' }, { "help", no_argument, NULL, 'h' }, { "verbose", no_argument, NULL, 'v' }, + { "version", no_argument, NULL, 'V' }, { NULL, 0, NULL, 0 } }; @@ -3205,6 +3206,10 @@ static int parse_options(int argc, char *argv[]) * we don't use it because mount(8) passes it. */ break; + case 'V': + ntfs_log_info("%s %s %s %d\n", EXEC_NAME, VERSION, + FUSE_TYPE, fuse_version()); + exit(0); default: ntfs_log_error("%s: Unknown option '%s'.\n", EXEC_NAME, argv[optind - 1]); @@ -3466,8 +3471,7 @@ int main(int argc, char *argv[]) ntfs_log_set_handler(ntfs_log_handler_stderr); if (parse_options(argc, argv)) { - ntfs_log_error("Please type '%s --help' for more " - "information.\n", argv[0]); + usage(); return NTFS_VOLUME_SYNTAX_ERROR; }