📄 super.c
字号:
ntfs_error(vol->sb, "Mft record size (%i) is smaller than the " "sector size (%i). This is not supported. " "Sorry.", vol->mft_record_size, vol->sector_size); return false; } 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); /* We cannot support index record sizes below the sector size. */ if (vol->index_record_size < vol->sector_size) { ntfs_error(vol->sb, "Index record size (%i) is smaller than " "the sector size (%i). This is not " "supported. Sorry.", vol->index_record_size, vol->sector_size); return false; } /* * 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%llx", (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 (%lluTiB) is too " "large for this architecture. " "Maximum supported is 2TiB. Sorry.", (unsigned long long)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 (%lli, 0x%llx) is beyond end of " "volume. Weird.", (unsigned long long)ll, (unsigned long long)ll); return false; } vol->mft_lcn = ll; ntfs_debug("vol->mft_lcn = 0x%llx", (long long)vol->mft_lcn); ll = sle64_to_cpu(b->mftmirr_lcn); if (ll >= vol->nr_clusters) { ntfs_error(vol->sb, "MFTMirr LCN (%lli, 0x%llx) is beyond end " "of volume. Weird.", (unsigned long long)ll, (unsigned long long)ll); return false; } vol->mftmirr_lcn = ll; ntfs_debug("vol->mftmirr_lcn = 0x%llx", (long long)vol->mftmirr_lcn);#ifdef NTFS_RW /* * Work out the size of the mft mirror in number of mft records. If the * cluster size is less than or equal to the size taken by four mft * records, the mft mirror stores the first four mft records. If the * cluster size is bigger than the size taken by four mft records, the * mft mirror contains as many mft records as will fit into one * cluster. */ if (vol->cluster_size <= (4 << vol->mft_record_size_bits)) vol->mftmirr_size = 4; else vol->mftmirr_size = vol->cluster_size >> vol->mft_record_size_bits; ntfs_debug("vol->mftmirr_size = %i", vol->mftmirr_size);#endif /* NTFS_RW */ vol->serial_no = le64_to_cpu(b->volume_serial_number); ntfs_debug("vol->serial_no = 0x%llx", (unsigned long long)vol->serial_no); return true;}/** * ntfs_setup_allocators - initialize the cluster and mft allocators * @vol: volume structure for which to setup the allocators * * Setup the cluster (lcn) and mft allocators to the starting values. */static void ntfs_setup_allocators(ntfs_volume *vol){#ifdef NTFS_RW LCN mft_zone_size, mft_lcn;#endif /* NTFS_RW */ ntfs_debug("vol->mft_zone_multiplier = 0x%x", vol->mft_zone_multiplier);#ifdef NTFS_RW /* Determine the size of the MFT zone. */ mft_zone_size = vol->nr_clusters; switch (vol->mft_zone_multiplier) { /* % of volume size in clusters */ case 4: mft_zone_size >>= 1; /* 50% */ break; case 3: mft_zone_size = (mft_zone_size + (mft_zone_size >> 1)) >> 2; /* 37.5% */ break; case 2: mft_zone_size >>= 2; /* 25% */ break; /* case 1: */ default: mft_zone_size >>= 3; /* 12.5% */ break; } /* Setup the mft zone. */ vol->mft_zone_start = vol->mft_zone_pos = vol->mft_lcn; ntfs_debug("vol->mft_zone_pos = 0x%llx", (unsigned long long)vol->mft_zone_pos); /* * Calculate the mft_lcn for an unmodified NTFS volume (see mkntfs * source) and if the actual mft_lcn is in the expected place or even * further to the front of the volume, extend the mft_zone to cover the * beginning of the volume as well. This is in order to protect the * area reserved for the mft bitmap as well within the mft_zone itself. * On non-standard volumes we do not protect it as the overhead would * be higher than the speed increase we would get by doing it. */ mft_lcn = (8192 + 2 * vol->cluster_size - 1) / vol->cluster_size; if (mft_lcn * vol->cluster_size < 16 * 1024) mft_lcn = (16 * 1024 + vol->cluster_size - 1) / vol->cluster_size; if (vol->mft_zone_start <= mft_lcn) vol->mft_zone_start = 0; ntfs_debug("vol->mft_zone_start = 0x%llx", (unsigned long long)vol->mft_zone_start); /* * Need to cap the mft zone on non-standard volumes so that it does * not point outside the boundaries of the volume. We do this by * halving the zone size until we are inside the volume. */ vol->mft_zone_end = vol->mft_lcn + mft_zone_size; while (vol->mft_zone_end >= vol->nr_clusters) { mft_zone_size >>= 1; vol->mft_zone_end = vol->mft_lcn + mft_zone_size; } ntfs_debug("vol->mft_zone_end = 0x%llx", (unsigned long long)vol->mft_zone_end); /* * Set the current position within each data zone to the start of the * respective zone. */ vol->data1_zone_pos = vol->mft_zone_end; ntfs_debug("vol->data1_zone_pos = 0x%llx", (unsigned long long)vol->data1_zone_pos); vol->data2_zone_pos = 0; ntfs_debug("vol->data2_zone_pos = 0x%llx", (unsigned long long)vol->data2_zone_pos); /* Set the mft data allocation position to mft record 24. */ vol->mft_data_pos = 24; ntfs_debug("vol->mft_data_pos = 0x%llx", (unsigned long long)vol->mft_data_pos);#endif /* NTFS_RW */}#ifdef NTFS_RW/** * load_and_init_mft_mirror - load and setup the mft mirror inode for a volume * @vol: ntfs super block describing device whose mft mirror to load * * Return 'true' on success or 'false' on error. */static bool load_and_init_mft_mirror(ntfs_volume *vol){ struct inode *tmp_ino; ntfs_inode *tmp_ni; ntfs_debug("Entering."); /* Get mft mirror inode. */ tmp_ino = ntfs_iget(vol->sb, FILE_MFTMirr); if (IS_ERR(tmp_ino) || is_bad_inode(tmp_ino)) { if (!IS_ERR(tmp_ino)) iput(tmp_ino); /* Caller will display error message. */ return false; } /* * Re-initialize some specifics about $MFTMirr's inode as * ntfs_read_inode() will have set up the default ones. */ /* Set uid and gid to root. */ tmp_ino->i_uid = tmp_ino->i_gid = 0; /* Regular file. No access for anyone. */ tmp_ino->i_mode = S_IFREG; /* No VFS initiated operations allowed for $MFTMirr. */ tmp_ino->i_op = &ntfs_empty_inode_ops; tmp_ino->i_fop = &ntfs_empty_file_ops; /* Put in our special address space operations. */ tmp_ino->i_mapping->a_ops = &ntfs_mst_aops; tmp_ni = NTFS_I(tmp_ino); /* The $MFTMirr, like the $MFT is multi sector transfer protected. */ NInoSetMstProtected(tmp_ni); NInoSetSparseDisabled(tmp_ni); /* * Set up our little cheat allowing us to reuse the async read io * completion handler for directories. */ tmp_ni->itype.index.block_size = vol->mft_record_size; tmp_ni->itype.index.block_size_bits = vol->mft_record_size_bits; vol->mftmirr_ino = tmp_ino; ntfs_debug("Done."); return true;}/** * check_mft_mirror - compare contents of the mft mirror with the mft * @vol: ntfs super block describing device whose mft mirror to check * * Return 'true' on success or 'false' on error. * * Note, this function also results in the mft mirror runlist being completely * mapped into memory. The mft mirror write code requires this and will BUG() * should it find an unmapped runlist element. */static bool check_mft_mirror(ntfs_volume *vol){ struct super_block *sb = vol->sb; ntfs_inode *mirr_ni; struct page *mft_page, *mirr_page; u8 *kmft, *kmirr; runlist_element *rl, rl2[2]; pgoff_t index; int mrecs_per_page, i; ntfs_debug("Entering."); /* Compare contents of $MFT and $MFTMirr. */ mrecs_per_page = PAGE_CACHE_SIZE / vol->mft_record_size; BUG_ON(!mrecs_per_page); BUG_ON(!vol->mftmirr_size); mft_page = mirr_page = NULL; kmft = kmirr = NULL; index = i = 0; do { u32 bytes; /* Switch pages if necessary. */ if (!(i % mrecs_per_page)) { if (index) { ntfs_unmap_page(mft_page); ntfs_unmap_page(mirr_page); } /* Get the $MFT page. */ mft_page = ntfs_map_page(vol->mft_ino->i_mapping, index); if (IS_ERR(mft_page)) { ntfs_error(sb, "Failed to read $MFT."); return false; } kmft = page_address(mft_page); /* Get the $MFTMirr page. */ mirr_page = ntfs_map_page(vol->mftmirr_ino->i_mapping, index); if (IS_ERR(mirr_page)) { ntfs_error(sb, "Failed to read $MFTMirr."); goto mft_unmap_out; } kmirr = page_address(mirr_page); ++index; } /* Do not check the record if it is not in use. */ if (((MFT_RECORD*)kmft)->flags & MFT_RECORD_IN_USE) { /* Make sure the record is ok. */ if (ntfs_is_baad_recordp((le32*)kmft)) { ntfs_error(sb, "Incomplete multi sector " "transfer detected in mft " "record %i.", i);mm_unmap_out: ntfs_unmap_page(mirr_page);mft_unmap_out: ntfs_unmap_page(mft_page); return false; } } /* Do not check the mirror record if it is not in use. */ if (((MFT_RECORD*)kmirr)->flags & MFT_RECORD_IN_USE) { if (ntfs_is_baad_recordp((le32*)kmirr)) { ntfs_error(sb, "Incomplete multi sector " "transfer detected in mft " "mirror record %i.", i); goto mm_unmap_out; } } /* Get the amount of data in the current record. */ bytes = le32_to_cpu(((MFT_RECORD*)kmft)->bytes_in_use); if (bytes < sizeof(MFT_RECORD_OLD) || bytes > vol->mft_record_size || ntfs_is_baad_recordp((le32*)kmft)) { bytes = le32_to_cpu(((MFT_RECORD*)kmirr)->bytes_in_use); if (bytes < sizeof(MFT_RECORD_OLD) || bytes > vol->mft_record_size || ntfs_is_baad_recordp((le32*)kmirr)) bytes = vol->mft_record_size; } /* Compare the two records. */ if (memcmp(kmft, kmirr, bytes)) { ntfs_error(sb, "$MFT and $MFTMirr (record %i) do not " "match. Run ntfsfix or chkdsk.", i); goto mm_unmap_out; } kmft += vol->mft_record_size; kmirr += vol->mft_record_size; } while (++i < vol->mftmirr_size); /* Release the last pages. */ ntfs_unmap_page(mft_page); ntfs_unmap_page(mirr_page); /* Construct the mft mirror runlist by hand. */ rl2[0].vcn = 0; rl2[0].lcn = vol->mftmirr_lcn; rl2[0].length = (vol->mftmirr_size * vol->mft_record_size + vol->cluster_size - 1) / vol->cluster_size; rl2[1].vcn = rl2[0].length; rl2[1].lcn = LCN_ENOENT; rl2[1].length = 0; /* * Because we have just read all of the mft mirror, we know we have * mapped the full runlist for it. */ mirr_ni = NTFS_I(vol->mftmirr_ino); down_read(&mirr_ni->runlist.lock); rl = mirr_ni->runlist.rl; /* Compare the two runlists. They must be identical. */ i = 0; do { if (rl2[i].vcn != rl[i].vcn || rl2[i].lcn != rl[i].lcn || rl2[i].length != rl[i].length) { ntfs_error(sb, "$MFTMirr location mismatch. " "Run chkdsk."); up_read(&mirr_ni->runlist.lock); return false; } } while (rl2[i++].length); up_read(&mirr_ni->runlist.lock); ntfs_debug("Done."); return true;}/** * load_and_check_logfile - load and check the logfile inode for a volume * @vol: ntfs super block describing device whose logfile to load * * Return 'true' on success or 'false' on error. */static bool load_and_check_logfile(ntfs_volume *vol, RESTART_PAGE_HEADER **rp){ struct inode *tmp_ino; ntfs_debug("Entering."); tmp_ino = ntfs_iget(vol->sb, FILE_LogFile); if (IS_ERR(tmp_ino) || is_bad_inode(tmp_ino)) { if (!IS_ERR(tmp_ino)) iput(tmp_ino); /* Caller will display error message. */ return false; } if (!ntfs_check_logfile(tmp_ino, rp)) { iput(tmp_ino); /* ntfs_check_logfile() will have displayed error output. */ return false; } NInoSetSparseDisabled(NTFS_I(tmp_ino)); vol->logfile_ino = tmp_ino; ntfs_debug("Done."); return true;}#define NTFS_HIBERFIL_HEADER_SIZE 4096/**
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -