Used MFT record 15 for the first extent to MFT:DATA

When the runlist of the data attribute of MFT has to be split across
several extents, the location of each extent has to be known from the
runlist present in previous extents. So, force the first extent into
record 15 to avoid a bad layout.
edge.strict_endians
Jean-Pierre André 2014-03-11 10:16:26 +01:00
parent ea8e192613
commit e6c46d4fa0
4 changed files with 52 additions and 9 deletions

View File

@ -235,7 +235,7 @@ typedef enum {
FILE_reserved12 = 12, /* Reserved for future use (records 12-15). */
FILE_reserved13 = 13,
FILE_reserved14 = 14,
FILE_reserved15 = 15,
FILE_mft_data = 15, /* Reserved for first extent of $MFT:$DATA */
FILE_first_user = 16, /* First user file, used as test limit for
whether to allow opening a file or not. */
} NTFS_SYSTEM_FILES;

View File

@ -124,6 +124,8 @@ extern int ntfs_mft_record_format(const ntfs_volume *vol, const MFT_REF mref);
extern ntfs_inode *ntfs_mft_record_alloc(ntfs_volume *vol, ntfs_inode *base_ni);
extern ntfs_inode *ntfs_mft_rec_alloc(ntfs_volume *vol, BOOL mft_data);
extern int ntfs_mft_record_free(ntfs_volume *vol, ntfs_inode *ni);
extern int ntfs_mft_usn_dec(MFT_RECORD *mrec);

View File

@ -5869,8 +5869,12 @@ retry:
ntfs_log_perror("%s: get mp size failed", __FUNCTION__);
goto put_err_out;
}
/* Allocate new mft record. */
ni = ntfs_mft_record_alloc(na->ni->vol, base_ni);
/* Allocate new mft record, with special case for mft itself */
if (!na->ni->mft_no)
ni = ntfs_mft_rec_alloc(na->ni->vol,
na->type == AT_DATA);
else
ni = ntfs_mft_record_alloc(na->ni->vol, base_ni);
if (!ni) {
ntfs_log_perror("Could not allocate new MFT record");
goto put_err_out;

View File

@ -5,6 +5,7 @@
* Copyright (c) 2004-2005 Richard Russon
* Copyright (c) 2004-2008 Szabolcs Szakacsits
* Copyright (c) 2005 Yura Pakhuchiy
* Copyright (c) 2014 Jean-Pierre Andre
*
* This program/include file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published
@ -1354,7 +1355,7 @@ undo_data_init:
goto out;
}
static ntfs_inode *ntfs_mft_rec_alloc(ntfs_volume *vol)
ntfs_inode *ntfs_mft_rec_alloc(ntfs_volume *vol, BOOL mft_data)
{
s64 ll, bit;
ntfs_attr *mft_na, *mftbmp_na;
@ -1363,6 +1364,7 @@ static ntfs_inode *ntfs_mft_rec_alloc(ntfs_volume *vol)
ntfs_inode *base_ni;
int err;
le16 seq_no, usn;
BOOL forced_mft_data;
ntfs_log_enter("Entering\n");
@ -1371,7 +1373,38 @@ static ntfs_inode *ntfs_mft_rec_alloc(ntfs_volume *vol)
base_ni = mft_na->ni;
bit = ntfs_mft_bitmap_find_free_rec(vol, base_ni);
/*
* The first extent containing $MFT:$AT_DATA is better located
* in record 15 to make sure it can be read at mount time.
* The record 15 is prereserved as a base inode with no
* extents and no name, and it is marked in use.
*/
forced_mft_data = FALSE;
if (mft_data) {
ntfs_inode *ext_ni = ntfs_inode_open(vol, FILE_mft_data);
/*
* If record 15 cannot be opened, it is probably in
* use as an extent. Apply standard procedure for
* further extents.
*/
if (ext_ni) {
/*
* Make sure record 15 is a base extent and has
* no extents.
* Also make sure it has no name : a base inode with
* no extents and no name cannot be in use.
* Otherwise apply standard procedure.
*/
if (!ext_ni->mrec->base_mft_record
&& !ext_ni->nr_extents)
forced_mft_data = TRUE;
ntfs_inode_close(ext_ni);
}
}
if (forced_mft_data)
bit = FILE_mft_data;
else
bit = ntfs_mft_bitmap_find_free_rec(vol, base_ni);
if (bit >= 0)
goto found_free_rec;
@ -1408,7 +1441,9 @@ found_free_rec:
goto undo_mftbmp_alloc;
}
/* Sanity check that the mft record is really not in use. */
if (ntfs_is_file_record(m->magic) && (m->flags & MFT_RECORD_IN_USE)) {
if (!forced_mft_data
&& (ntfs_is_file_record(m->magic)
&& (m->flags & MFT_RECORD_IN_USE))) {
ntfs_log_error("Inode %lld is used but it wasn't marked in "
"$MFT bitmap. Fixed.\n", (long long)bit);
free(m);
@ -1524,8 +1559,9 @@ err_out:
* @base_ni is NULL 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
* to 24 are used for storing extension mft records or used by chkdsk to store
* its log. However the record number 15 is dedicated to the first extent to
* 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
@ -1584,6 +1620,7 @@ err_out:
* when reading the bitmap but if we are careful, we should be able to avoid
* all problems.
*/
//ntfs_inode *ntfs_mft_record_alloc(ntfs_volume *vol, ntfs_inode *base_ni)
ntfs_inode *ntfs_mft_record_alloc(ntfs_volume *vol, ntfs_inode *base_ni)
{
s64 ll, bit;
@ -1605,7 +1642,7 @@ ntfs_inode *ntfs_mft_record_alloc(ntfs_volume *vol, ntfs_inode *base_ni)
}
if (ntfs_is_mft(base_ni)) {
ni = ntfs_mft_rec_alloc(vol);
ni = ntfs_mft_rec_alloc(vol, FALSE);
goto out;
}