📄 mft.c
字号:
*/static int ntfs_mft_bitmap_extend_initialized(ntfs_volume *vol){ s64 old_data_size, old_initialized_size, ll; ntfs_attr *mftbmp_na; ntfs_attr_search_ctx *ctx; ATTR_RECORD *a; int err; int ret = -1; ntfs_log_enter("Entering\n"); mftbmp_na = vol->mftbmp_na; ctx = ntfs_attr_get_search_ctx(mftbmp_na->ni, NULL); if (!ctx) goto out; if (ntfs_attr_lookup(mftbmp_na->type, mftbmp_na->name, mftbmp_na->name_len, 0, 0, NULL, 0, ctx)) { ntfs_log_error("Failed to find first attribute extent of " "mft bitmap attribute.\n"); err = errno; goto put_err_out; } a = ctx->attr; old_data_size = mftbmp_na->data_size; old_initialized_size = mftbmp_na->initialized_size; mftbmp_na->initialized_size += 8; a->initialized_size = cpu_to_sle64(mftbmp_na->initialized_size); if (mftbmp_na->initialized_size > mftbmp_na->data_size) { mftbmp_na->data_size = mftbmp_na->initialized_size; a->data_size = cpu_to_sle64(mftbmp_na->data_size); } /* Ensure the changes make it to disk. */ ntfs_inode_mark_dirty(ctx->ntfs_ino); ntfs_attr_put_search_ctx(ctx); /* Initialize the mft bitmap attribute value with zeroes. */ ll = 0; ll = ntfs_attr_pwrite(mftbmp_na, old_initialized_size, 8, &ll); if (ll == 8) { ntfs_log_debug("Wrote eight initialized bytes to mft bitmap.\n"); vol->free_mft_records += (8 * 8); ret = 0; goto out; } ntfs_log_error("Failed to write to mft bitmap.\n"); err = errno; if (ll >= 0) err = EIO; /* Try to recover from the error. */ ctx = ntfs_attr_get_search_ctx(mftbmp_na->ni, NULL); if (!ctx) goto err_out; if (ntfs_attr_lookup(mftbmp_na->type, mftbmp_na->name, mftbmp_na->name_len, 0, 0, NULL, 0, ctx)) { ntfs_log_error("Failed to find first attribute extent of " "mft bitmap attribute.%s\n", es);put_err_out: ntfs_attr_put_search_ctx(ctx); goto err_out; } a = ctx->attr; mftbmp_na->initialized_size = old_initialized_size; a->initialized_size = cpu_to_sle64(old_initialized_size); if (mftbmp_na->data_size != old_data_size) { mftbmp_na->data_size = old_data_size; a->data_size = cpu_to_sle64(old_data_size); } ntfs_inode_mark_dirty(ctx->ntfs_ino); ntfs_attr_put_search_ctx(ctx); ntfs_log_debug("Restored status of mftbmp: allocated_size 0x%llx, " "data_size 0x%llx, initialized_size 0x%llx.\n", (long long)mftbmp_na->allocated_size, (long long)mftbmp_na->data_size, (long long)mftbmp_na->initialized_size);err_out: errno = err;out: ntfs_log_leave("\n"); return ret;}/** * ntfs_mft_data_extend_allocation - extend mft data attribute * @vol: volume on which to extend the mft data attribute * * Extend the mft data attribute on the ntfs volume @vol by 16 mft records * worth of clusters or if not enough space for this by one mft record worth * of clusters. * * Note: Only changes allocated_size, i.e. does not touch initialized_size or * data_size. * * Return 0 on success and -1 on error with errno set to the error code. */static int ntfs_mft_data_extend_allocation(ntfs_volume *vol){ LCN lcn; VCN old_last_vcn; s64 min_nr, nr, ll = 0; /* silence compiler warning */ ntfs_attr *mft_na; runlist_element *rl, *rl2; ntfs_attr_search_ctx *ctx; MFT_RECORD *m = NULL; /* silence compiler warning */ ATTR_RECORD *a = NULL; /* silence compiler warning */ int err, mp_size; int ret = -1; u32 old_alen = 0; /* silence compiler warning */ BOOL mp_rebuilt = FALSE; ntfs_log_enter("Extending mft data allocation.\n"); mft_na = vol->mft_na; /* * Determine the preferred allocation location, i.e. the last lcn of * the mft data attribute. The allocated size of the mft data * attribute cannot be zero so we are ok to do this. */ rl = ntfs_attr_find_vcn(mft_na, (mft_na->allocated_size - 1) >> vol->cluster_size_bits); if (!rl || !rl->length || rl->lcn < 0) { ntfs_log_error("Failed to determine last allocated " "cluster of mft data attribute.\n"); if (rl) errno = EIO; goto out; } lcn = rl->lcn + rl->length; ntfs_log_debug("Last lcn of mft data attribute is 0x%llx.\n", (long long)lcn); /* Minimum allocation is one mft record worth of clusters. */ min_nr = vol->mft_record_size >> vol->cluster_size_bits; if (!min_nr) min_nr = 1; /* Want to allocate 16 mft records worth of clusters. */ nr = vol->mft_record_size << 4 >> vol->cluster_size_bits; if (!nr) nr = min_nr; old_last_vcn = rl[1].vcn; do { rl2 = ntfs_cluster_alloc(vol, old_last_vcn, nr, lcn, MFT_ZONE); if (rl2) break; if (errno != ENOSPC || nr == min_nr) { ntfs_log_perror("Failed to allocate (%lld) clusters " "for $MFT", (long long)nr); goto out; } /* * There is not enough space to do the allocation, but there * might be enough space to do a minimal allocation so try that * before failing. */ nr = min_nr; ntfs_log_debug("Retrying mft data allocation with minimal cluster " "count %lli.\n", (long long)nr); } while (1); ntfs_log_debug("Allocated %lli clusters.\n", nr); rl = ntfs_runlists_merge(mft_na->rl, rl2); if (!rl) { err = errno; ntfs_log_error("Failed to merge runlists for mft data " "attribute.\n"); if (ntfs_cluster_free_from_rl(vol, rl2)) ntfs_log_error("Failed to deallocate clusters " "from the mft data attribute.%s\n", es); free(rl2); errno = err; goto out; } mft_na->rl = rl; /* Find the last run in the new runlist. */ for (; rl[1].length; rl++) ; /* Update the attribute record as well. */ ctx = ntfs_attr_get_search_ctx(mft_na->ni, NULL); if (!ctx) goto undo_alloc; if (ntfs_attr_lookup(mft_na->type, mft_na->name, mft_na->name_len, 0, rl[1].vcn, NULL, 0, ctx)) { ntfs_log_error("Failed to find last attribute extent of " "mft data attribute.\n"); goto undo_alloc; } m = ctx->mrec; a = ctx->attr; ll = sle64_to_cpu(a->lowest_vcn); rl2 = ntfs_attr_find_vcn(mft_na, ll); if (!rl2 || !rl2->length) { ntfs_log_error("Failed to determine previous last " "allocated cluster of mft data attribute.\n"); if (rl2) errno = EIO; goto undo_alloc; } /* Get the size for the new mapping pairs array for this extent. */ mp_size = ntfs_get_size_for_mapping_pairs(vol, rl2, ll); if (mp_size <= 0) { ntfs_log_error("Get size for mapping pairs failed for " "mft data attribute extent.\n"); goto undo_alloc; } /* Expand the attribute record if necessary. */ old_alen = le32_to_cpu(a->length); if (ntfs_attr_record_resize(m, a, mp_size + le16_to_cpu(a->mapping_pairs_offset))) { // TODO: Deal with this by moving this extent to a new mft // record or by starting a new extent in a new mft record. // Note: Use the special reserved mft records and ensure that // this extent is not required to find the mft record in // question. errno = EOPNOTSUPP; ntfs_log_perror("Not enough space to extended mft data"); goto undo_alloc; } mp_rebuilt = TRUE; /* * Generate the mapping pairs array directly into the attribute record. */ if (ntfs_mapping_pairs_build(vol, (u8*)a + le16_to_cpu(a->mapping_pairs_offset), mp_size, rl2, ll, NULL)) { ntfs_log_error("Failed to build mapping pairs array of " "mft data attribute.\n"); errno = EIO; goto undo_alloc; } /* Update the highest_vcn. */ a->highest_vcn = cpu_to_sle64(rl[1].vcn - 1); /* * We now have extended the mft data allocated_size by nr clusters. * Reflect this in the ntfs_attr structure and the attribute record. * @rl is the last (non-terminator) runlist element of mft data * attribute. */ if (a->lowest_vcn) { /* * We are not in the first attribute extent, switch to it, but * first ensure the changes will make it to disk later. */ ntfs_inode_mark_dirty(ctx->ntfs_ino); ntfs_attr_reinit_search_ctx(ctx); if (ntfs_attr_lookup(mft_na->type, mft_na->name, mft_na->name_len, 0, 0, NULL, 0, ctx)) { ntfs_log_error("Failed to find first attribute " "extent of mft data attribute.\n"); goto restore_undo_alloc; } a = ctx->attr; } mft_na->allocated_size += nr << vol->cluster_size_bits; a->allocated_size = cpu_to_sle64(mft_na->allocated_size); /* Ensure the changes make it to disk. */ ntfs_inode_mark_dirty(ctx->ntfs_ino); ntfs_attr_put_search_ctx(ctx); ret = 0;out: ntfs_log_leave("\n"); return ret;restore_undo_alloc: err = errno; ntfs_attr_reinit_search_ctx(ctx); if (ntfs_attr_lookup(mft_na->type, mft_na->name, mft_na->name_len, 0, rl[1].vcn, NULL, 0, ctx)) { ntfs_log_error("Failed to find last attribute extent of " "mft data attribute.%s\n", es); ntfs_attr_put_search_ctx(ctx); mft_na->allocated_size += nr << vol->cluster_size_bits; /* * The only thing that is now wrong is ->allocated_size of the * base attribute extent which chkdsk should be able to fix. */ errno = err; goto out; } m = ctx->mrec; a = ctx->attr; a->highest_vcn = cpu_to_sle64(old_last_vcn - 1); errno = err;undo_alloc: err = errno; if (ntfs_cluster_free(vol, mft_na, old_last_vcn, -1) < 0) ntfs_log_error("Failed to free clusters from mft data " "attribute.%s\n", es); if (ntfs_rl_truncate(&mft_na->rl, old_last_vcn)) ntfs_log_error("Failed to truncate mft data attribute " "runlist.%s\n", es); if (mp_rebuilt) { if (ntfs_mapping_pairs_build(vol, (u8*)a + le16_to_cpu(a->mapping_pairs_offset), old_alen - le16_to_cpu(a->mapping_pairs_offset), rl2, ll, NULL)) ntfs_log_error("Failed to restore mapping pairs " "array.%s\n", es); if (ntfs_attr_record_resize(m, a, old_alen)) ntfs_log_error("Failed to restore attribute " "record.%s\n", es); ntfs_inode_mark_dirty(ctx->ntfs_ino); } if (ctx) ntfs_attr_put_search_ctx(ctx); errno = err; goto out;}static int ntfs_mft_record_init(ntfs_volume *vol, s64 size){ int ret = -1; ntfs_attr *mft_na, *mftbmp_na; s64 old_data_initialized, old_data_size; ntfs_attr_search_ctx *ctx; ntfs_log_enter("Entering\n"); /* NOTE: Caller must sanity check vol, vol->mft_na and vol->mftbmp_na */ mft_na = vol->mft_na; mftbmp_na = vol->mftbmp_na; /* * The mft record is outside the initialized data. Extend the mft data * attribute until it covers the allocated record. The loop is only * actually traversed more than once when a freshly formatted volume * is first written to so it optimizes away nicely in the common case. */ ntfs_log_debug("Status of mft data before extension: " "allocated_size 0x%llx, data_size 0x%llx, " "initialized_size 0x%llx.\n", (long long)mft_na->allocated_size, (long long)mft_na->data_size, (long long)mft_na->initialized_size); while (size > mft_na->allocated_size) { if (ntfs_mft_data_extend_allocation(vol)) goto out; ntfs_log_debug("Status of mft data after allocation extension: " "allocated_size 0x%llx, data_size 0x%llx, " "initialized_size 0x%llx.\n", (long long)mft_na->allocated_size, (long long)mft_na->data_size, (long long)mft_na->initialized_size); } old_data_initialized = mft_na->initialized_size; old_data_size = mft_na->data_size; /* * Extend mft data initialized size (and data size of course) to reach * the allocated mft record, formatting the mft records along the way. * Note: We only modify the ntfs_attr structure as that is all that is * needed by ntfs_mft_record_format(). We will update the attribute * record itself in one fell swoop later on. */ while (size > mft_na->initialized_size) { s64 ll2 = mft_na->initialized_size >> vol->mft_record_size_bits; mft_na->initialized_size += vol->mft_record_size; if (mft_na->initialized_size > mft_na->data_size) mft_na->data_size = mft_na->initialized_size; ntfs_log_debug("Initializing mft record 0x%llx.\n", (long long)ll2); if (ntfs_mft_record_format(vol, ll2) < 0) { ntfs_log_perror("Failed to format mft record"); goto undo_data_init; } } /* Update the mft data attribute record to reflect the new sizes. */ ctx = ntfs_attr_get_search_ctx(mft_na->ni, NULL); if (!ctx) goto undo_data_init; if (ntfs_attr_lookup(mft_na->type, mft_na->name, mft_na->name_len, 0, 0, NULL, 0, ctx)) { ntfs_log_error("Failed to find first attribute extent of " "mft data attribute.\n"); ntfs_attr_put_search_ctx(ctx); goto undo_data_init; } ctx->attr->initialized_size = cpu_to_sle64(mft_na->initialized_size); ctx->attr->data_size = cpu_to_sle64(mft_na->data_size); /* Ensure the changes make it to disk. */ ntfs_inode_mark_dirty(ctx->ntfs_ino); ntfs_attr_put_search_ctx(ctx); ntfs_log_debug("Status of mft data after mft record initialization: " "allocated_size 0x%llx, data_size 0x%llx, " "initialized_size 0x%llx.\n", (long long)mft_na->allocated_size, (long long)mft_na->data_size, (long long)mft_na->initialized_size); /* Sanity checks. */ if (mft_na->data_size > mft_na->allocated_size || mft_na->initialized_size > mft_na->data_size) NTFS_BUG("mft_na sanity checks failed"); // BUG_ON(mft_na->initialized_size > mft_na->data_size); // BUG_ON(mft_na->data_size > mft_na->allocated_size);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -