Remove vol->nr_mft_records and update all users. (Anton)
(Logical change 1.549)edge.strict_endians
parent
a5b6b89456
commit
b82469ba50
|
@ -24,6 +24,7 @@ xx/xx/2004 - 2.0.0-WIP
|
|||
all callers. This allows filling an attribute extent with mapping
|
||||
pairs and then continuing in a different extent once the first extent
|
||||
is full. (Yura)
|
||||
- Remove vol->nr_mft_records and update all users. (Anton)
|
||||
|
||||
04/09/2004 - 1.9.4 - Urgent bug fixes.
|
||||
|
||||
|
|
|
@ -140,9 +140,6 @@ struct _ntfs_volume {
|
|||
lcn 0 and so on. A set bit means that the
|
||||
cluster and vice versa. */
|
||||
|
||||
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. */
|
||||
|
|
|
@ -72,7 +72,8 @@ int ntfs_mft_records_read(const ntfs_volume *vol, const MFT_REF mref,
|
|||
}
|
||||
m = MREF(mref);
|
||||
/* Refuse to read non-allocated mft records. */
|
||||
if (m + count > vol->nr_mft_records) {
|
||||
if (m + count > vol->mft_na->initialized_size >>
|
||||
vol->mft_record_size_bits) {
|
||||
errno = ESPIPE;
|
||||
return -1;
|
||||
}
|
||||
|
@ -129,7 +130,8 @@ int ntfs_mft_records_write(const ntfs_volume *vol, const MFT_REF mref,
|
|||
}
|
||||
m = MREF(mref);
|
||||
/* Refuse to write non-allocated mft records. */
|
||||
if (m + count > vol->nr_mft_records) {
|
||||
if (m + count > vol->mft_na->initialized_size >>
|
||||
vol->mft_record_size_bits) {
|
||||
errno = ESPIPE;
|
||||
return -1;
|
||||
}
|
||||
|
@ -375,20 +377,88 @@ int ntfs_mft_record_format(const ntfs_volume *vol, const MFT_REF mref)
|
|||
* @start: starting mft record at which to allocate (or -1 if none)
|
||||
*
|
||||
* Allocate an mft record in $MFT/$DATA starting to search for a free record
|
||||
* at mft record number @start or at the current allocator position if
|
||||
* @start_mref is -1, on the mounted ntfs volume @vol.
|
||||
* at mft record number @start or at the current allocator position if @start
|
||||
* is -1, on the mounted ntfs volume @vol.
|
||||
*
|
||||
* On success return the now opened ntfs inode of the mft record.
|
||||
*
|
||||
* On error return NULL with errno set to the error code.
|
||||
*
|
||||
* To find a free mft record, we scan the mft bitmap for a zero bit. To
|
||||
* optimize this we start scanning at the place specified by @start or if
|
||||
* @start is -1 we start where we last stopped and we perform wrap around when
|
||||
* we reach the end. Note, we do not try to allocate mft records below number
|
||||
* 24 because numbers 0 to 15 are the defined system files anyway and 16 to 24
|
||||
* are special in that they are used for storing extension mft records for the
|
||||
* $DATA attribute of $MFT. This is required to avoid the possibility of
|
||||
* creating a run list with a circular dependence which once written to disk
|
||||
* can never be read in again. Windows will only use records 16 to 24 for
|
||||
* normal files if the volume is completely out of space. We never use them
|
||||
* which means that when the volume is really out of space we cannot create any
|
||||
* more files while Windows can still create up to 8 small files. We can start
|
||||
* doing this at some later time, it does not matter much for now.
|
||||
*
|
||||
* When scanning the mft bitmap, we only search up to the last allocated mft
|
||||
* record. If there are no free records left in the range 24 to number of
|
||||
* allocated mft records, then we extend the $MFT/$DATA attribute in order to
|
||||
* create free mft records. We extend the allocated size of $MFT/$DATA by 16
|
||||
* records at a time or one cluster, if cluster size is above 16kiB. If there
|
||||
* is not sufficient space to do this, we try to extend by a single mft record
|
||||
* or one cluster, if cluster size is above the mft record size, but we only do
|
||||
* this if there is enough free space, which we know from the values returned
|
||||
* by the failed cluster allocation function when we tried to do the first
|
||||
* allocation.
|
||||
*
|
||||
* No matter how many mft records we allocate, we initialize only the first
|
||||
* allocated mft record, incrementing mft data size and initialized size
|
||||
* accordingly, open an ntfs_inode for it and return it to the caller, unless
|
||||
* there are less than 24 mft records, in which case we allocate and initialize
|
||||
* mft records until we reach record 24 which we consider as the first free mft
|
||||
* record for use by normal files.
|
||||
*
|
||||
* If during any stage we overflow the initialized data in the mft bitmap, we
|
||||
* extend the initialized size (and data size) by 8 bytes, allocating another
|
||||
* cluster if required. The bitmap data size has to be at least equal to the
|
||||
* number of mft records in the mft, but it can be bigger, in which case the
|
||||
* superflous bits are padded with zeroes.
|
||||
*
|
||||
* Thus, when we return successfully (return value non-zero), we will have:
|
||||
* - initialized / extended the mft bitmap if necessary,
|
||||
* - initialized / extended the mft data if necessary,
|
||||
* - set the bit corresponding to the mft record being allocated in the
|
||||
* mft bitmap,
|
||||
* - open an ntfs_inode for the allocated mft record, and we will
|
||||
* - return the ntfs_inode.
|
||||
*
|
||||
* On error (return value zero), nothing will have changed. If we had changed
|
||||
* anything before the error occured, we will have reverted back to the
|
||||
* starting state before returning to the caller. Thus, except for bugs, we
|
||||
* should always leave the volume in a consistent state when returning from
|
||||
* this function.
|
||||
*
|
||||
* Note, this function cannot make use of most of the normal functions, like
|
||||
* for example for attribute resizing, etc, because when the run list overflows
|
||||
* the base mft record and an attribute list is used, it is very important that
|
||||
* the extension mft records used to store the $DATA attribute of $MFT can be
|
||||
* reached without having to read the information contained inside them, as
|
||||
* this would make it impossible to find them in the first place after the
|
||||
* volume is dismounted. $MFT/$BITMAP probably does not need to follow this
|
||||
* rule because the bitmap is not essential for finding the mft records, but on
|
||||
* the other hand, handling the bitmap in this special way would make life
|
||||
* easier because otherwise there might be circular invocations of functions
|
||||
* when reading the bitmap but if we are careful, we should be able to avoid
|
||||
* all problems.
|
||||
*/
|
||||
#ifndef PAGE_SIZE
|
||||
#define PAGE_SIZE 4096
|
||||
#endif
|
||||
ntfs_inode *ntfs_mft_record_alloc(ntfs_volume *vol, s64 start)
|
||||
{
|
||||
if (!vol || !vol->mftbmp_na || start < -1) {
|
||||
ntfs_debug("Entering (start 0x%llx).", (long long)start);
|
||||
if (!vol || !vol->mft_na || !vol->mftbmp_na || start < -1) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
errno = ENOTSUP;
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -217,9 +217,6 @@ mft_has_no_attr_list:
|
|||
Dperror("Failed to open ntfs attribute");
|
||||
goto error_exit;
|
||||
}
|
||||
/* 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);
|
||||
last_vcn = vol->mft_na->allocated_size >> vol->cluster_size_bits;
|
||||
|
|
|
@ -873,7 +873,8 @@ static int walk_clusters(ntfs_volume *volume, struct ntfs_walk_cluster *walk)
|
|||
|
||||
Printf("Scanning volume ...\n");
|
||||
|
||||
last_mft_rec = volume->nr_mft_records - 1;
|
||||
last_mft_rec = (volume->mft_na->initialized_size >>
|
||||
volume->mft_record_size_bits) - 1;
|
||||
progress_init(&progress, inode, last_mft_rec, 100);
|
||||
|
||||
for (; inode <= last_mft_rec; inode++) {
|
||||
|
@ -1331,7 +1332,8 @@ int main(int argc, char **argv)
|
|||
walk_clusters(vol, &backup_clusters);
|
||||
|
||||
Printf("Num of MFT records = %8lld\n",
|
||||
(long long)vol->nr_mft_records);
|
||||
(long long)vol->mft_na->initialized_size >>
|
||||
vol->mft_record_size_bits);
|
||||
Printf("Num of used MFT records = %8d\n", nr_used_mft_records);
|
||||
|
||||
Printf("Wiped unused MFT data = %8d\n", wiped_unused_mft_data);
|
||||
|
|
|
@ -311,7 +311,7 @@ static int info (ntfs_volume *vol)
|
|||
d = vol->nr_clusters << cb;
|
||||
e = vol->nr_clusters;
|
||||
f = vol->nr_clusters >> cps;
|
||||
g = vol->nr_mft_records;
|
||||
g = vol->mft_na->initialized_size >> vol->mft_record_size_bits;
|
||||
h = inuse;
|
||||
i = h * 100 / g;
|
||||
j = fc;
|
||||
|
|
|
@ -339,8 +339,6 @@ static 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 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);
|
||||
printf("\tFILE_MFTMirr Size: %d\n", vol->mftmirr_size);
|
||||
|
|
|
@ -953,7 +953,7 @@ static int inode_close(ntfs_inode *ni)
|
|||
*/
|
||||
static int build_allocation_bitmap(ntfs_volume *vol, ntfsck_t *fsck)
|
||||
{
|
||||
s64 inode = 0;
|
||||
s64 nr_mft_records, inode = 0;
|
||||
ntfs_inode *ni;
|
||||
struct progress_bar progress;
|
||||
int pb_flags = 0; /* progress bar flags */
|
||||
|
@ -964,9 +964,12 @@ static int build_allocation_bitmap(ntfs_volume *vol, ntfsck_t *fsck)
|
|||
if (fsck->flags & NTFSCK_PROGBAR)
|
||||
pb_flags |= NTFS_PROGBAR;
|
||||
|
||||
progress_init(&progress, inode, vol->nr_mft_records - 1, pb_flags);
|
||||
nr_mft_records = vol->mft_na->initialized_size >>
|
||||
vol->mft_record_size_bits;
|
||||
|
||||
for (; inode < vol->nr_mft_records; inode++) {
|
||||
progress_init(&progress, inode, nr_mft_records - 1, pb_flags);
|
||||
|
||||
for (; inode < nr_mft_records; inode++) {
|
||||
progress_update(&progress, inode);
|
||||
|
||||
if ((ni = ntfs_inode_open(vol, (MFT_REF)inode)) == NULL) {
|
||||
|
@ -1033,12 +1036,15 @@ static void resize_constrains_by_attributes(ntfs_resize_t *resize)
|
|||
|
||||
static void set_resize_constrains(ntfs_resize_t *resize)
|
||||
{
|
||||
s64 inode;
|
||||
s64 nr_mft_records, inode;
|
||||
ntfs_inode *ni;
|
||||
|
||||
printf("Collecting shrinkage constrains ...\n");
|
||||
|
||||
for (inode = 0; inode < resize->vol->nr_mft_records; inode++) {
|
||||
nr_mft_records = resize->vol->mft_na->initialized_size >>
|
||||
resize->vol->mft_record_size_bits;
|
||||
|
||||
for (inode = 0; inode < nr_mft_records; inode++) {
|
||||
|
||||
ni = ntfs_inode_open(resize->vol, (MFT_REF)inode);
|
||||
if (ni == NULL) {
|
||||
|
@ -1586,6 +1592,7 @@ static void relocate_inode(ntfs_resize_t *resize, MFT_REF mref)
|
|||
|
||||
static void relocate_inodes(ntfs_resize_t *resize)
|
||||
{
|
||||
s64 nr_mft_records;
|
||||
MFT_REF mref;
|
||||
|
||||
printf("Relocating needed data ...\n");
|
||||
|
@ -1597,7 +1604,10 @@ static void relocate_inodes(ntfs_resize_t *resize)
|
|||
if (!resize->mrec)
|
||||
perr_exit("malloc failed");
|
||||
|
||||
for (mref = 1; mref < (MFT_REF)resize->vol->nr_mft_records; mref++)
|
||||
nr_mft_records = resize->vol->mft_na->initialized_size >>
|
||||
resize->vol->mft_record_size_bits;
|
||||
|
||||
for (mref = 1; mref < (MFT_REF)nr_mft_records; mref++)
|
||||
relocate_inode(resize, mref);
|
||||
|
||||
relocate_inode(resize, 0);
|
||||
|
|
|
@ -1553,6 +1553,7 @@ static int set_date (const char *pathname, time_t date)
|
|||
*/
|
||||
static int scan_disk (ntfs_volume *vol)
|
||||
{
|
||||
s64 nr_mft_records;
|
||||
const int BUFSIZE = 8192;
|
||||
char *buffer = NULL;
|
||||
int results = 0;
|
||||
|
@ -1592,6 +1593,9 @@ static int scan_disk (ntfs_volume *vol)
|
|||
}
|
||||
}
|
||||
|
||||
nr_mft_records = vol->mft_na->initialized_size >>
|
||||
vol->mft_record_size_bits;
|
||||
|
||||
Qprintf ("Inode Flags %%age Date Size Filename\n");
|
||||
Qprintf ("---------------------------------------------------------------\n");
|
||||
for (i = 0; i < bmpsize; i += BUFSIZE) {
|
||||
|
@ -1603,7 +1607,7 @@ static int scan_disk (ntfs_volume *vol)
|
|||
for (j = 0; j < size; j++) {
|
||||
b = buffer[j];
|
||||
for (k = 0; k < 8; k++, b>>=1) {
|
||||
if (((i+j)*8+k) >= vol->nr_mft_records)
|
||||
if (((i+j)*8+k) >= nr_mft_records)
|
||||
goto done;
|
||||
if (b & 1)
|
||||
continue;
|
||||
|
@ -1907,6 +1911,7 @@ free:
|
|||
*/
|
||||
static int copy_mft (ntfs_volume *vol, long long mft_begin, long long mft_end)
|
||||
{
|
||||
s64 nr_mft_records;
|
||||
char pathname[256];
|
||||
ntfs_attr *mft;
|
||||
char *buffer;
|
||||
|
@ -1948,10 +1953,13 @@ static int copy_mft (ntfs_volume *vol, long long mft_begin, long long mft_end)
|
|||
goto attr;
|
||||
}
|
||||
|
||||
mft_end = min (mft_end, vol->nr_mft_records - 1);
|
||||
nr_mft_records = vol->mft_na->initialized_size >>
|
||||
vol->mft_record_size_bits;
|
||||
|
||||
mft_end = min (mft_end, nr_mft_records - 1);
|
||||
|
||||
Dprintf ("MFT records\n");
|
||||
Dprintf (" Total: %8lld\n", vol->nr_mft_records);
|
||||
Dprintf (" Total: %8lld\n", nr_mft_records);
|
||||
Dprintf (" Begin: %8lld\n", mft_begin);
|
||||
Dprintf (" End: %8lld\n", mft_end);
|
||||
|
||||
|
@ -1988,6 +1996,7 @@ free:
|
|||
*/
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
s64 nr_mft_records;
|
||||
ntfs_volume *vol;
|
||||
int result = 1;
|
||||
int i;
|
||||
|
@ -2028,10 +2037,13 @@ int main (int argc, char *argv[])
|
|||
}
|
||||
break;
|
||||
case MODE_COPY:
|
||||
nr_mft_records = vol->mft_na->initialized_size >>
|
||||
vol->mft_record_size_bits;
|
||||
|
||||
result = !copy_mft (vol, opts.mft_begin, opts.mft_end);
|
||||
if (result)
|
||||
Vprintf ("Failed to read MFT blocks %lld-%lld.\n",
|
||||
opts.mft_begin, min(vol->nr_mft_records, opts.mft_end));
|
||||
opts.mft_begin, min(nr_mft_records, opts.mft_end));
|
||||
break;
|
||||
default:
|
||||
; /* Cannot happen */
|
||||
|
|
|
@ -566,14 +566,17 @@ static s64 wipe_attribute (ntfs_volume *vol, int byte, enum action act,
|
|||
static s64 wipe_tails (ntfs_volume *vol, int byte, enum action act)
|
||||
{
|
||||
s64 total = 0;
|
||||
s64 inode_num;
|
||||
s64 nr_mft_records, inode_num;
|
||||
ntfs_inode *ni;
|
||||
ntfs_attr *na;
|
||||
|
||||
if (!vol || (byte < 0))
|
||||
return -1;
|
||||
|
||||
for (inode_num = 16; inode_num < vol->nr_mft_records; inode_num++) {
|
||||
nr_mft_records = vol->mft_na->initialized_size >>
|
||||
vol->mft_record_size_bits;
|
||||
|
||||
for (inode_num = 16; inode_num < nr_mft_records; inode_num++) {
|
||||
s64 wiped;
|
||||
|
||||
Vprintf ("Inode %lld - ", inode_num);
|
||||
|
@ -646,7 +649,7 @@ static s64 wipe_mft (ntfs_volume *vol, int byte, enum action act)
|
|||
{
|
||||
// by considering the individual attributes we might be able to
|
||||
// wipe a few more bytes at the attr's tail.
|
||||
s64 i;
|
||||
s64 nr_mft_records, i;
|
||||
s64 total = 0;
|
||||
s64 result = 0;
|
||||
int size = 0;
|
||||
|
@ -661,7 +664,10 @@ static s64 wipe_mft (ntfs_volume *vol, int byte, enum action act)
|
|||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < vol->nr_mft_records; i++) {
|
||||
nr_mft_records = vol->mft_na->initialized_size >>
|
||||
vol->mft_record_size_bits;
|
||||
|
||||
for (i = 0; i < nr_mft_records; i++) {
|
||||
if (utils_mftrec_in_use (vol, i)) {
|
||||
result = ntfs_attr_mst_pread (vol->mft_na, vol->mft_record_size * i,
|
||||
1, vol->mft_record_size, buffer);
|
||||
|
@ -920,7 +926,7 @@ static u32 get_indx_record_size (ntfs_attr *nar)
|
|||
static s64 wipe_directory (ntfs_volume *vol, int byte, enum action act)
|
||||
{
|
||||
s64 total = 0;
|
||||
s64 inode_num;
|
||||
s64 nr_mft_records, inode_num;
|
||||
ntfs_inode *ni;
|
||||
ntfs_attr *naa;
|
||||
ntfs_attr *nab;
|
||||
|
@ -929,7 +935,10 @@ static s64 wipe_directory (ntfs_volume *vol, int byte, enum action act)
|
|||
if (!vol || (byte < 0))
|
||||
return -1;
|
||||
|
||||
for (inode_num = 5; inode_num < vol->nr_mft_records; inode_num++) {
|
||||
nr_mft_records = vol->mft_na->initialized_size >>
|
||||
vol->mft_record_size_bits;
|
||||
|
||||
for (inode_num = 5; inode_num < nr_mft_records; inode_num++) {
|
||||
u32 indx_record_size;
|
||||
s64 wiped;
|
||||
|
||||
|
|
|
@ -963,6 +963,7 @@ void mft_put_search_ctx (struct mft_search_ctx *ctx)
|
|||
*/
|
||||
int mft_next_record (struct mft_search_ctx *ctx)
|
||||
{
|
||||
s64 nr_mft_records;
|
||||
ATTR_RECORD *attr10 = NULL;
|
||||
ATTR_RECORD *attr20 = NULL;
|
||||
ATTR_RECORD *attr80 = NULL;
|
||||
|
@ -978,7 +979,10 @@ int mft_next_record (struct mft_search_ctx *ctx)
|
|||
ctx->inode = NULL;
|
||||
}
|
||||
|
||||
for (ctx->mft_num++; (s64)ctx->mft_num < ctx->vol->nr_mft_records; ctx->mft_num++) {
|
||||
nr_mft_records = ctx->vol->mft_na->initialized_size >>
|
||||
ctx->vol->mft_record_size_bits;
|
||||
|
||||
for (ctx->mft_num++; (s64)ctx->mft_num < nr_mft_records; ctx->mft_num++) {
|
||||
int in_use;
|
||||
|
||||
ctx->flags_match = 0;
|
||||
|
|
Loading…
Reference in New Issue