diff --git a/include/ntfs/volume.h b/include/ntfs/volume.h index feeabdab..b401362b 100644 --- a/include/ntfs/volume.h +++ b/include/ntfs/volume.h @@ -136,8 +136,9 @@ struct _ntfs_volume { lcn 0 and so on. A set bit means that the cluster and vice versa. */ - s64 nr_mft_records; /* Number of records in the mft, equals the - number of bits in mft_bitmap. */ + s64 nr_mft_records; /* Number of initialized records in the mft, + equals the number of bits in mft_bitmap that + may be set. */ LCN mft_lcn; /* Logical cluster number of the data attribute for FILE_MFT. */ ntfs_inode *mft_ni; /* ntfs_inode structure for FILE_MFT. */ diff --git a/libntfs/mft.c b/libntfs/mft.c index 31785b73..1edac6bd 100644 --- a/libntfs/mft.c +++ b/libntfs/mft.c @@ -49,6 +49,10 @@ * @b. Return 0 on success or -1 on error, with errno set to the error * code. * + * If any of the records exceed the initialized size of the $MFT/$DATA + * attribute, i.e. they cannot possibly be allocated mft records, assume this + * is a bug and return error code ESPIPE. + * * The read mft records are mst deprotected and are hence ready to use. The * caller should check each record with is_baad_record() in case mst * deprotection failed. @@ -67,6 +71,7 @@ int ntfs_mft_records_read(const ntfs_volume *vol, const MFT_REF mref, return -1; } m = MREF(mref); + /* Refuse to read non-allocated mft records. */ if (m + count > vol->nr_mft_records) { errno = ESPIPE; return -1; @@ -95,6 +100,10 @@ int ntfs_mft_records_read(const ntfs_volume *vol, const MFT_REF mref, * Write @count mft records starting at @mref from data buffer @b to volume * @vol. Return 0 on success or -1 on error, with errno set to the error code. * + * If any of the records exceed the initialized size of the $MFT/$DATA + * attribute, i.e. they cannot possibly be allocated mft records, assume this + * is a bug and return error code ESPIPE. + * * Before the mft records are written, they are mst protected. After the write, * they are deprotected again, thus resulting in an increase in the update * sequence number inside the data buffer @b. @@ -119,6 +128,11 @@ int ntfs_mft_records_write(const ntfs_volume *vol, const MFT_REF mref, return -1; } m = MREF(mref); + /* Refuse to write non-allocated mft records. */ + if (m + count > vol->nr_mft_records) { + errno = ESPIPE; + return -1; + } if (m < vol->mftmirr_size) { cnt = vol->mftmirr_size - m; if (cnt > count) @@ -128,14 +142,6 @@ int ntfs_mft_records_write(const ntfs_volume *vol, const MFT_REF mref, return -1; memcpy(bmirr, b, cnt * vol->mft_record_size); } - if (m + count > vol->nr_mft_records) { - // TODO: Need to extend $MFT. This is not just normal attribute - // extension as many rules need to be observed. (AIA) - if (bmirr) - free(bmirr); - errno = ENOTSUP; - return -1; - } bw = ntfs_attr_mst_pwrite(vol->mft_na, m << vol->mft_record_size_bits, count, vol->mft_record_size, b); if (bw != count) { @@ -335,4 +341,3 @@ sync_rollback: errno = err; return -1; } - diff --git a/libntfs/volume.c b/libntfs/volume.c index eccf56d3..a6e675da 100644 --- a/libntfs/volume.c +++ b/libntfs/volume.c @@ -218,8 +218,8 @@ mft_has_no_attr_list: Dperror("Failed to open ntfs attribute"); goto error_exit; } - /* Set the number of mft records. */ - vol->nr_mft_records = vol->mft_na->data_size >> + /* Set the number of initialized mft records. */ + vol->nr_mft_records = vol->mft_na->initialized_size >> vol->mft_record_size_bits; /* Read all extents from the $DATA attribute in $MFT. */ ntfs_attr_reinit_search_ctx(ctx); diff --git a/ntfsprogs/ntfscluster.c b/ntfsprogs/ntfscluster.c index 3b278a8a..bb6dbad6 100644 --- a/ntfsprogs/ntfscluster.c +++ b/ntfsprogs/ntfscluster.c @@ -327,27 +327,27 @@ int info (ntfs_volume *vol) t = mc >> cb; u = mc * 100 / b / e; - printf ("bytes per sector : %llu\n", (unsigned long long)a); - printf ("bytes per cluster : %llu\n", (unsigned long long)b); - printf ("sectors per cluster : %llu\n", (unsigned long long)c); - printf ("bytes per volume : %llu\n", (unsigned long long)d); - printf ("sectors per volume : %llu\n", (unsigned long long)e); - printf ("clusters per volume : %llu\n", (unsigned long long)f); - printf ("mft records total : %llu\n", (unsigned long long)g); - printf ("mft records in use : %llu\n", (unsigned long long)h); - printf ("mft records percentage : %llu\n", (unsigned long long)i); - printf ("bytes of free space : %llu\n", (unsigned long long)j); - printf ("sectors of free space : %llu\n", (unsigned long long)k); - printf ("clusters of free space : %llu\n", (unsigned long long)l); - printf ("percentage free space : %llu\n", (unsigned long long)m); - printf ("bytes of user data : %llu\n", (unsigned long long)n); - printf ("sectors of user data : %llu\n", (unsigned long long)o); - printf ("clusters of user data : %llu\n", (unsigned long long)p); - printf ("percentage user data : %llu\n", (unsigned long long)q); - printf ("bytes of metadata : %llu\n", (unsigned long long)r); - printf ("sectors of metadata : %llu\n", (unsigned long long)s); - printf ("clusters of metadata : %llu\n", (unsigned long long)t); - printf ("percentage metadata : %llu\n", (unsigned long long)u); + printf ("bytes per sector : %llu\n", (unsigned long long)a); + printf ("bytes per cluster : %llu\n", (unsigned long long)b); + printf ("sectors per cluster : %llu\n", (unsigned long long)c); + printf ("bytes per volume : %llu\n", (unsigned long long)d); + printf ("sectors per volume : %llu\n", (unsigned long long)e); + printf ("clusters per volume : %llu\n", (unsigned long long)f); + printf ("initialized mft records : %llu\n", (unsigned long long)g); + printf ("mft records in use : %llu\n", (unsigned long long)h); + printf ("mft records percentage : %llu\n", (unsigned long long)i); + printf ("bytes of free space : %llu\n", (unsigned long long)j); + printf ("sectors of free space : %llu\n", (unsigned long long)k); + printf ("clusters of free space : %llu\n", (unsigned long long)l); + printf ("percentage free space : %llu\n", (unsigned long long)m); + printf ("bytes of user data : %llu\n", (unsigned long long)n); + printf ("sectors of user data : %llu\n", (unsigned long long)o); + printf ("clusters of user data : %llu\n", (unsigned long long)p); + printf ("percentage user data : %llu\n", (unsigned long long)q); + printf ("bytes of metadata : %llu\n", (unsigned long long)r); + printf ("sectors of metadata : %llu\n", (unsigned long long)s); + printf ("clusters of metadata : %llu\n", (unsigned long long)t); + printf ("percentage metadata : %llu\n", (unsigned long long)u); return 0; } diff --git a/ntfsprogs/ntfsinfo.c b/ntfsprogs/ntfsinfo.c index 37ef08bf..245adfea 100644 --- a/ntfsprogs/ntfsinfo.c +++ b/ntfsprogs/ntfsinfo.c @@ -267,7 +267,7 @@ void ntfs_dump_volume(ntfs_volume *vol) (long long)vol->data1_zone_pos); printf("\tCurrent Position in Second Data Zone: %lld\n", (long long)vol->data2_zone_pos); - printf("\tNumber of Records in MFT: %lld\n", + printf("\tNumber of Initialized Records in MFT: %lld\n", (long long)vol->nr_mft_records); printf("\tLCN of Data Attribute for FILE_MFT: %lld\n", (long long)vol->mft_lcn);