📄 super.c
字号:
long nr_blocks = NTFS_SB(sb)->nr_blocks;
/* Try to read primary boot sector. */
if ((bh_primary = sb_bread(sb, 0))) {
if (is_boot_sector_ntfs(sb, (NTFS_BOOT_SECTOR*)
bh_primary->b_data, silent))
return bh_primary;
if (!silent)
ntfs_error(sb, "Primary boot sector is invalid.");
} else if (!silent)
ntfs_error(sb, read_err_str, "primary");
if (!(NTFS_SB(sb)->on_errors & ON_ERRORS_RECOVER)) {
if (bh_primary)
brelse(bh_primary);
if (!silent)
ntfs_error(sb, "Mount option errors=recover not used. "
"Aborting without trying to recover.");
return NULL;
}
/* Try to read NT4+ backup boot sector. */
if ((bh_backup = sb_bread(sb, nr_blocks - 1))) {
if (is_boot_sector_ntfs(sb, (NTFS_BOOT_SECTOR*)
bh_backup->b_data, silent))
goto hotfix_primary_boot_sector;
brelse(bh_backup);
} else if (!silent)
ntfs_error(sb, read_err_str, "backup");
/* Try to read NT3.51- backup boot sector. */
if ((bh_backup = sb_bread(sb, nr_blocks >> 1))) {
if (is_boot_sector_ntfs(sb, (NTFS_BOOT_SECTOR*)
bh_backup->b_data, silent))
goto hotfix_primary_boot_sector;
if (!silent)
ntfs_error(sb, "Could not find a valid backup boot "
"sector.");
brelse(bh_backup);
} else if (!silent)
ntfs_error(sb, read_err_str, "backup");
/* We failed. Cleanup and return. */
if (bh_primary)
brelse(bh_primary);
return NULL;
hotfix_primary_boot_sector:
if (bh_primary) {
/*
* If we managed to read sector zero and the volume is not
* read-only, copy the found, valid backup boot sector to the
* primary boot sector.
*/
if (!(sb->s_flags & MS_RDONLY)) {
ntfs_warning(sb, "Hot-fix: Recovering invalid primary "
"boot sector from backup copy.");
memcpy(bh_primary->b_data, bh_backup->b_data,
sb->s_blocksize);
mark_buffer_dirty(bh_primary);
sync_dirty_buffer(bh_primary);
if (buffer_uptodate(bh_primary)) {
brelse(bh_backup);
return bh_primary;
}
ntfs_error(sb, "Hot-fix: Device write error while "
"recovering primary boot sector.");
} else {
ntfs_warning(sb, "Hot-fix: Recovery of primary boot "
"sector failed: Read-only mount.");
}
brelse(bh_primary);
}
ntfs_warning(sb, "Using backup boot sector.");
return bh_backup;
}
/**
* parse_ntfs_boot_sector - parse the boot sector and store the data in @vol
* @vol: volume structure to initialise with data from boot sector
* @b: boot sector to parse
*
* Parse the ntfs boot sector @b and store all imporant information therein in
* the ntfs super block @vol. Return TRUE on success and FALSE on error.
*/
static BOOL parse_ntfs_boot_sector(ntfs_volume *vol, const NTFS_BOOT_SECTOR *b)
{
unsigned int sectors_per_cluster_bits, nr_hidden_sects;
int clusters_per_mft_record, clusters_per_index_record;
s64 ll;
vol->sector_size = le16_to_cpu(b->bpb.bytes_per_sector);
vol->sector_size_bits = ffs(vol->sector_size) - 1;
ntfs_debug("vol->sector_size = %i (0x%x)", vol->sector_size,
vol->sector_size);
ntfs_debug("vol->sector_size_bits = %i (0x%x)", vol->sector_size_bits,
vol->sector_size_bits);
if (vol->sector_size != vol->sb->s_blocksize)
ntfs_warning(vol->sb, "The boot sector indicates a sector size "
"different from the device sector size.");
ntfs_debug("sectors_per_cluster = 0x%x", b->bpb.sectors_per_cluster);
sectors_per_cluster_bits = ffs(b->bpb.sectors_per_cluster) - 1;
ntfs_debug("sectors_per_cluster_bits = 0x%x",
sectors_per_cluster_bits);
nr_hidden_sects = le32_to_cpu(b->bpb.hidden_sectors);
ntfs_debug("number of hidden sectors = 0x%x", nr_hidden_sects);
vol->cluster_size = vol->sector_size << sectors_per_cluster_bits;
vol->cluster_size_mask = vol->cluster_size - 1;
vol->cluster_size_bits = ffs(vol->cluster_size) - 1;
ntfs_debug("vol->cluster_size = %i (0x%x)", vol->cluster_size,
vol->cluster_size);
ntfs_debug("vol->cluster_size_mask = 0x%x", vol->cluster_size_mask);
ntfs_debug("vol->cluster_size_bits = %i (0x%x)",
vol->cluster_size_bits, vol->cluster_size_bits);
if (vol->sector_size > vol->cluster_size) {
ntfs_error(vol->sb, "Sector sizes above the cluster size are "
"not supported. Sorry.");
return FALSE;
}
if (vol->sb->s_blocksize > vol->cluster_size) {
ntfs_error(vol->sb, "Cluster sizes smaller than the device "
"sector size are not supported. Sorry.");
return FALSE;
}
clusters_per_mft_record = b->clusters_per_mft_record;
ntfs_debug("clusters_per_mft_record = %i (0x%x)",
clusters_per_mft_record, clusters_per_mft_record);
if (clusters_per_mft_record > 0)
vol->mft_record_size = vol->cluster_size <<
(ffs(clusters_per_mft_record) - 1);
else
/*
* When mft_record_size < cluster_size, clusters_per_mft_record
* = -log2(mft_record_size) bytes. mft_record_size normaly is
* 1024 bytes, which is encoded as 0xF6 (-10 in decimal).
*/
vol->mft_record_size = 1 << -clusters_per_mft_record;
vol->mft_record_size_mask = vol->mft_record_size - 1;
vol->mft_record_size_bits = ffs(vol->mft_record_size) - 1;
ntfs_debug("vol->mft_record_size = %i (0x%x)", vol->mft_record_size,
vol->mft_record_size);
ntfs_debug("vol->mft_record_size_mask = 0x%x",
vol->mft_record_size_mask);
ntfs_debug("vol->mft_record_size_bits = %i (0x%x)",
vol->mft_record_size_bits, vol->mft_record_size_bits);
clusters_per_index_record = b->clusters_per_index_record;
ntfs_debug("clusters_per_index_record = %i (0x%x)",
clusters_per_index_record, clusters_per_index_record);
if (clusters_per_index_record > 0)
vol->index_record_size = vol->cluster_size <<
(ffs(clusters_per_index_record) - 1);
else
/*
* When index_record_size < cluster_size,
* clusters_per_index_record = -log2(index_record_size) bytes.
* index_record_size normaly equals 4096 bytes, which is
* encoded as 0xF4 (-12 in decimal).
*/
vol->index_record_size = 1 << -clusters_per_index_record;
vol->index_record_size_mask = vol->index_record_size - 1;
vol->index_record_size_bits = ffs(vol->index_record_size) - 1;
ntfs_debug("vol->index_record_size = %i (0x%x)",
vol->index_record_size, vol->index_record_size);
ntfs_debug("vol->index_record_size_mask = 0x%x",
vol->index_record_size_mask);
ntfs_debug("vol->index_record_size_bits = %i (0x%x)",
vol->index_record_size_bits,
vol->index_record_size_bits);
/*
* Get the size of the volume in clusters and check for 64-bit-ness.
* Windows currently only uses 32 bits to save the clusters so we do
* the same as it is much faster on 32-bit CPUs.
*/
ll = sle64_to_cpu(b->number_of_sectors) >> sectors_per_cluster_bits;
if ((u64)ll >= 1ULL << 32) {
ntfs_error(vol->sb, "Cannot handle 64-bit clusters. Sorry.");
return FALSE;
}
vol->nr_clusters = ll;
ntfs_debug("vol->nr_clusters = 0x%Lx", (long long)vol->nr_clusters);
/*
* On an architecture where unsigned long is 32-bits, we restrict the
* volume size to 2TiB (2^41). On a 64-bit architecture, the compiler
* will hopefully optimize the whole check away.
*/
if (sizeof(unsigned long) < 8) {
if ((ll << vol->cluster_size_bits) >= (1ULL << 41)) {
ntfs_error(vol->sb, "Volume size (%LuTiB) is too large "
"for this architecture. Maximim "
"supported is 2TiB. Sorry.",
ll >> (40 - vol->cluster_size_bits));
return FALSE;
}
}
ll = sle64_to_cpu(b->mft_lcn);
if (ll >= vol->nr_clusters) {
ntfs_error(vol->sb, "MFT LCN is beyond end of volume. Weird.");
return FALSE;
}
vol->mft_lcn = ll;
ntfs_debug("vol->mft_lcn = 0x%Lx", (long long)vol->mft_lcn);
ll = sle64_to_cpu(b->mftmirr_lcn);
if (ll >= vol->nr_clusters) {
ntfs_error(vol->sb, "MFTMirr LCN is beyond end of volume. "
"Weird.");
return FALSE;
}
vol->mftmirr_lcn = ll;
ntfs_debug("vol->mftmirr_lcn = 0x%Lx", (long long)vol->mftmirr_lcn);
vol->serial_no = le64_to_cpu(b->volume_serial_number);
ntfs_debug("vol->serial_no = 0x%Lx",
(unsigned long long)vol->serial_no);
/*
* Determine MFT zone size. This is not strictly the right place to do
* this, but I am too lazy to create a function especially for it...
*/
vol->mft_zone_end = vol->nr_clusters;
switch (vol->mft_zone_multiplier) { /* % of volume size in clusters */
case 4:
vol->mft_zone_end = vol->mft_zone_end >> 1; /* 50% */
break;
case 3:
vol->mft_zone_end = (vol->mft_zone_end +
(vol->mft_zone_end >> 1)) >> 2; /* 37.5% */
break;
case 2:
vol->mft_zone_end = vol->mft_zone_end >> 2; /* 25% */
break;
default:
vol->mft_zone_multiplier = 1;
/* Fall through into case 1. */
case 1:
vol->mft_zone_end = vol->mft_zone_end >> 3; /* 12.5% */
break;
}
ntfs_debug("vol->mft_zone_multiplier = 0x%x",
vol->mft_zone_multiplier);
vol->mft_zone_start = vol->mft_lcn;
vol->mft_zone_end += vol->mft_lcn;
ntfs_debug("vol->mft_zone_start = 0x%Lx",
(long long)vol->mft_zone_start);
ntfs_debug("vol->mft_zone_end = 0x%Lx", (long long)vol->mft_zone_end);
/* And another misplaced defaults setting. */
if (!vol->on_errors)
vol->on_errors = ON_ERRORS_PANIC;
return TRUE;
}
/**
* load_and_init_upcase - load the upcase table for an ntfs volume
* @vol: ntfs super block describing device whose upcase to load
*
* Return TRUE on success or FALSE on error.
*/
static BOOL load_and_init_upcase(ntfs_volume *vol)
{
struct super_block *sb = vol->sb;
struct inode *ino;
struct page *page;
unsigned long index, max_index;
unsigned int size;
int i, max;
ntfs_debug("Entering.");
/* Read upcase table and setup vol->upcase and vol->upcase_len. */
ino = ntfs_iget(sb, FILE_UpCase);
if (IS_ERR(ino) || is_bad_inode(ino)) {
if (!IS_ERR(ino))
iput(ino);
goto upcase_failed;
}
/*
* The upcase size must not be above 64k Unicode characters, must not
* be zero and must be a multiple of sizeof(uchar_t).
*/
if (!ino->i_size || ino->i_size & (sizeof(uchar_t) - 1) ||
ino->i_size > 64ULL * 1024 * sizeof(uchar_t))
goto iput_upcase_failed;
vol->upcase = (uchar_t*)ntfs_malloc_nofs(ino->i_size);
if (!vol->upcase)
goto iput_upcase_failed;
index = 0;
max_index = ino->i_size >> PAGE_CACHE_SHIFT;
size = PAGE_CACHE_SIZE;
while (index < max_index) {
/* Read the upcase table and copy it into the linear buffer. */
read_partial_upcase_page:
page = ntfs_map_page(ino->i_mapping, index);
if (IS_ERR(page))
goto iput_upcase_failed;
memcpy((char*)vol->upcase + (index++ << PAGE_CACHE_SHIFT),
page_address(page), size);
ntfs_unmap_page(page);
};
if (size == PAGE_CACHE_SIZE) {
size = ino->i_size & ~PAGE_CACHE_MASK;
if (size)
goto read_partial_upcase_page;
}
vol->upcase_len = ino->i_size >> UCHAR_T_SIZE_BITS;
ntfs_debug("Read %Lu bytes from $UpCase (expected %u bytes).",
ino->i_size, 64 * 1024 * sizeof(uchar_t));
iput(ino);
down(&ntfs_lock);
if (!default_upcase) {
ntfs_debug("Using volume specified $UpCase since default is "
"not present.");
up(&ntfs_lock);
return TRUE;
}
max = default_upcase_len;
if (max > vol->upcase_len)
max = vol->upcase_len;
for (i = 0; i < max; i++)
if (vol->upcase[i] != default_upcase[i])
break;
if (i == max) {
ntfs_free(vol->upcase);
vol->upcase = default_upcase;
vol->upcase_len = max;
ntfs_nr_upcase_users++;
up(&ntfs_lock);
ntfs_debug("Volume specified $UpCase matches default. Using "
"default.");
return TRUE;
}
up(&ntfs_lock);
ntfs_debug("Using volume specified $UpCase since it does not match "
"the default.");
return TRUE;
iput_upcase_failed:
iput(ino);
ntfs_free(vol->upcase);
vol->upcase = NULL;
upcase_failed:
down(&ntfs_lock);
if (default_upcase) {
vol->upcase = default_upcase;
vol->upcase_len = default_upcase_len;
ntfs_nr_upcase_users++;
up(&ntfs_lock);
ntfs_error(sb, "Failed to load $UpCase from the volume. Using "
"default.");
return TRUE;
}
up(&ntfs_lock);
ntfs_error(sb, "Failed to initialized upcase table.");
return FALSE;
}
/**
* load_system_files - open the system files using normal functions
* @vol: ntfs super block describing device whose system files to load
*
* Open the system files with normal access functions and complete setting up
* the ntfs super block @vol.
*
* Return TRUE on success or FALSE on error.
*/
static BOOL load_system_files(ntfs_volume *vol)
{
struct super_block *sb = vol->sb;
struct inode *tmp_ino;
MFT_RECORD *m;
VOLUME_INFORMATION *vi;
attr_search_context *ctx;
ntfs_debug("Entering.");
/* Get mft bitmap attribute inode. */
vol->mftbmp_ino = ntfs_attr_iget(vol->mft_ino, AT_BITMAP, NULL, 0);
if (IS_ERR(vol->mftbmp_ino)) {
ntfs_error(sb, "Failed to load $MFT/$BITMAP attribute.");
return FALSE;
}
/* Get mft mirror inode. */
vol->mftmirr_ino = ntfs_iget(sb, FILE_MFTMirr);
if (IS_ERR(vol->mftmirr_ino) || is_bad_inode(vol->mftmirr_ino)) {
if (!IS_ERR(vol->mftmirr_ino))
iput(vol->mftmirr_ino);
ntfs_error(sb, "Failed to load $MFTMirr.");
goto iput_mftbmp_err_out;
}
// FIXME: Compare mftmirr with mft and repair if appropriate and not
// a read-only mount.
/* Read upcase table and setup vol->upcase and vol->upcase_len. */
if (!load_and_init_upcase(vol))
goto iput_mirr_err_out;
/*
* Get the cluster allocation bitmap inode and verify the size, no
* need for any locking at this stage as we are already running
* exclusively as we are mount in progress task.
*/
vol->lcnbmp_ino = ntfs_iget(sb, FILE_Bitmap);
if (IS_ERR(vol->lcnbmp_ino) || is_bad_inode(vol->lcnbmp_ino)) {
if (!IS_ERR(vol->lcnbmp_ino))
iput(vol->lcnbmp_ino);
goto bitmap_failed;
}
if ((vol->nr_clusters + 7) >> 3 > vol->lcnbmp_ino->i_size) {
iput(vol->lcnbmp_ino);
bitmap_failed:
ntfs_error(sb, "Failed to load $Bitmap.");
goto iput_mirr_err_out;
}
/*
* Get the volume inode and setup our cache of the volume flags and
* version.
*/
vol->vol_ino = ntfs_iget(sb, FILE_Volume);
if (IS_ERR(vol->vol_ino) || is_bad_inode(vol->vol_ino)) {
if (!IS_ERR(vol->vol_ino))
iput(vol->vol_ino);
volume_failed:
ntfs_error(sb, "Failed to load $Volume.");
goto iput_lcnbmp_err_out;
}
m = map_mft_record(NTFS_I(vol->vol_ino));
if (IS_ERR(m)) {
iput_volume_failed:
iput(vol->vol_ino);
goto volume_failed;
}
if (!(ctx = get_attr_search_ctx(NTFS_I(vol->vol_ino), m))) {
ntfs_error(sb, "Failed to get attribute search context.");
goto get_ctx_vol_failed;
}
if (!lookup_attr(AT_VOLUME_INFORMATION, NULL, 0, 0, 0, NULL, 0, ctx) ||
ctx->attr->non_resident || ctx->attr->flags) {
err_put_vol:
put_attr_search_ctx(ctx);
get_ctx_vol_failed:
unmap_mft_record(NTFS_I(vol->vol_ino));
goto iput_volume_failed;
}
vi = (VOLUME_INFORMATION*)((char*)ctx->attr +
le16_to_cpu(ctx->attr->data.resident.value_offset));
/* Some bounds checks. */
if ((u8*)vi < (u8*)ctx->attr || (u8*)vi +
le32_to_cpu(ctx->attr->data.resident.value_length) >
(u8*)ctx->attr + le32_to_cpu(ctx->attr->length))
goto err_put_vol;
/* Setup volume flags and version. */
vol->vol_flags = vi->flags;
vol->major_ver = vi->major_ver;
vol->minor_ver = vi->minor_ver;
put_attr_search_ctx(ctx);
unmap_mft_record(NTFS_I(vol->vol_ino));
printk(KERN_INFO "NTFS volume version %i.%i.\n", vol->major_ver,
vol->minor_ver);
/*
* Get the inode for the logfile and empty it if this is a read-write
* mount.
*/
tmp_ino = ntfs_iget(sb, FILE_LogFile);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -