📄 mft.c
字号:
*/int ntfs_mft_record_format(const ntfs_volume *vol, const MFT_REF mref){ MFT_RECORD *m; int ret = -1; ntfs_log_enter("Entering\n"); m = ntfs_calloc(vol->mft_record_size); if (!m) goto out; if (ntfs_mft_record_layout(vol, mref, m)) goto free_m; if (ntfs_mft_record_write(vol, mref, m)) goto free_m; ret = 0;free_m: free(m);out: ntfs_log_leave("\n"); return ret;}static const char *es = " Leaving inconsistent metadata. Run chkdsk.";/** * ntfs_ffz - Find the first unset (zero) bit in a word * @word: * * Description... * * Returns: */static inline unsigned int ntfs_ffz(unsigned int word){ return ffs(~word) - 1;}#ifndef PAGE_SIZE#define PAGE_SIZE 4096#endif/** * ntfs_mft_bitmap_find_free_rec - find a free mft record in the mft bitmap * @vol: volume on which to search for a free mft record * @base_ni: open base inode if allocating an extent mft record or NULL * * Search for a free mft record in the mft bitmap attribute on the ntfs volume * @vol. * * If @base_ni is NULL start the search at the default allocator position. * * If @base_ni is not NULL start the search at the mft record after the base * mft record @base_ni. * * Return the free mft record on success and -1 on error with errno set to the * error code. An error code of ENOSPC means that there are no free mft * records in the currently initialized mft bitmap. */static int ntfs_mft_bitmap_find_free_rec(ntfs_volume *vol, ntfs_inode *base_ni){ s64 pass_end, ll, data_pos, pass_start, ofs, bit; ntfs_attr *mftbmp_na; u8 *buf, *byte; unsigned int size; u8 pass, b; int ret = -1; ntfs_log_enter("Entering\n"); mftbmp_na = vol->mftbmp_na; /* * Set the end of the pass making sure we do not overflow the mft * bitmap. */ size = PAGE_SIZE; pass_end = vol->mft_na->allocated_size >> vol->mft_record_size_bits; ll = mftbmp_na->initialized_size << 3; if (pass_end > ll) pass_end = ll; pass = 1; if (!base_ni) data_pos = vol->mft_data_pos; else data_pos = base_ni->mft_no + 1; if (data_pos < 24) data_pos = 24; if (data_pos >= pass_end) { data_pos = 24; pass = 2; /* This happens on a freshly formatted volume. */ if (data_pos >= pass_end) { errno = ENOSPC; goto leave; } } pass_start = data_pos; buf = ntfs_malloc(PAGE_SIZE); if (!buf) goto leave; ntfs_log_debug("Starting bitmap search: pass %u, pass_start 0x%llx, " "pass_end 0x%llx, data_pos 0x%llx.\n", pass, (long long)pass_start, (long long)pass_end, (long long)data_pos);#ifdef DEBUG byte = NULL; b = 0;#endif /* Loop until a free mft record is found. */ for (; pass <= 2; size = PAGE_SIZE) { /* Cap size to pass_end. */ ofs = data_pos >> 3; ll = ((pass_end + 7) >> 3) - ofs; if (size > ll) size = ll; ll = ntfs_attr_pread(mftbmp_na, ofs, size, buf); if (ll < 0) { ntfs_log_perror("Failed to read $MFT bitmap"); free(buf); goto leave; } ntfs_log_debug("Read 0x%llx bytes.\n", (long long)ll); /* If we read at least one byte, search @buf for a zero bit. */ if (ll) { size = ll << 3; bit = data_pos & 7; data_pos &= ~7ull; ntfs_log_debug("Before inner for loop: size 0x%x, " "data_pos 0x%llx, bit 0x%llx, " "*byte 0x%hhx, b %u.\n", size, (long long)data_pos, (long long)bit, byte ? *byte : -1, b); for (; bit < size && data_pos + bit < pass_end; bit &= ~7ull, bit += 8) { byte = buf + (bit >> 3); if (*byte == 0xff) continue; /* Note: ffz() result must be zero based. */ b = ntfs_ffz((unsigned long)*byte); if (b < 8 && b >= (bit & 7)) { free(buf); ret = data_pos + (bit & ~7ull) + b; goto leave; } } ntfs_log_debug("After inner for loop: size 0x%x, " "data_pos 0x%llx, bit 0x%llx, " "*byte 0x%hhx, b %u.\n", size, (long long)data_pos, (long long)bit, byte ? *byte : -1, b); data_pos += size; /* * If the end of the pass has not been reached yet, * continue searching the mft bitmap for a zero bit. */ if (data_pos < pass_end) continue; } /* Do the next pass. */ pass++; if (pass == 2) { /* * Starting the second pass, in which we scan the first * part of the zone which we omitted earlier. */ pass_end = pass_start; data_pos = pass_start = 24; ntfs_log_debug("pass %i, pass_start 0x%llx, pass_end " "0x%llx.\n", pass, (long long)pass_start, (long long)pass_end); if (data_pos >= pass_end) break; } } /* No free mft records in currently initialized mft bitmap. */ free(buf); errno = ENOSPC;leave: ntfs_log_leave("\n"); return ret;}/** * ntfs_mft_bitmap_extend_allocation_i - see ntfs_mft_bitmap_extend_allocation */static int ntfs_mft_bitmap_extend_allocation_i(ntfs_volume *vol){ LCN lcn; s64 ll = 0; /* silence compiler warning */ ntfs_attr *mftbmp_na; runlist_element *rl, *rl2 = NULL; /* silence compiler warning */ ntfs_attr_search_ctx *ctx; MFT_RECORD *m = NULL; /* silence compiler warning */ ATTR_RECORD *a = NULL; /* silence compiler warning */ int err, mp_size; u32 old_alen = 0; /* silence compiler warning */ BOOL mp_rebuilt = FALSE; mftbmp_na = vol->mftbmp_na; /* * Determine the last lcn of the mft bitmap. The allocated size of the * mft bitmap cannot be zero so we are ok to do this. */ rl = ntfs_attr_find_vcn(mftbmp_na, (mftbmp_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 bitmap attribute.\n"); if (rl) errno = EIO; return -1; } lcn = rl->lcn + rl->length; rl2 = ntfs_cluster_alloc(vol, rl[1].vcn, 1, lcn, DATA_ZONE); if (!rl2) { ntfs_log_error("Failed to allocate a cluster for " "the mft bitmap.\n"); return -1; } rl = ntfs_runlists_merge(mftbmp_na->rl, rl2); if (!rl) { err = errno; ntfs_log_error("Failed to merge runlists for mft " "bitmap.\n"); if (ntfs_cluster_free_from_rl(vol, rl2)) ntfs_log_error("Failed to deallocate " "cluster.%s\n", es); free(rl2); errno = err; return -1; } mftbmp_na->rl = rl; ntfs_log_debug("Adding one run to mft bitmap.\n"); /* Find the last run in the new runlist. */ for (; rl[1].length; rl++) ; /* * Update the attribute record as well. Note: @rl is the last * (non-terminator) runlist element of mft bitmap. */ ctx = ntfs_attr_get_search_ctx(mftbmp_na->ni, NULL); if (!ctx) goto undo_alloc; if (ntfs_attr_lookup(mftbmp_na->type, mftbmp_na->name, mftbmp_na->name_len, 0, rl[1].vcn, NULL, 0, ctx)) { ntfs_log_error("Failed to find last attribute extent of " "mft bitmap attribute.\n"); goto undo_alloc; } m = ctx->mrec; a = ctx->attr; ll = sle64_to_cpu(a->lowest_vcn); rl2 = ntfs_attr_find_vcn(mftbmp_na, ll); if (!rl2 || !rl2->length) { ntfs_log_error("Failed to determine previous last " "allocated cluster of mft bitmap 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 bitmap 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. ntfs_log_error("Not enough space in this mft record to " "accommodate extended mft bitmap attribute " "extent. Cannot handle this yet.\n"); errno = EOPNOTSUPP; goto undo_alloc; } mp_rebuilt = TRUE; /* Generate the mapping pairs array directly into the attr 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 for " "mft bitmap 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 bitmap allocated_size by one cluster. * Reflect this in the ntfs_attr structure and the attribute record. */ 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(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"); goto restore_undo_alloc; } a = ctx->attr; } mftbmp_na->allocated_size += vol->cluster_size; a->allocated_size = cpu_to_sle64(mftbmp_na->allocated_size); /* Ensure the changes make it to disk. */ ntfs_inode_mark_dirty(ctx->ntfs_ino); ntfs_attr_put_search_ctx(ctx); return 0;restore_undo_alloc: err = errno; ntfs_attr_reinit_search_ctx(ctx); if (ntfs_attr_lookup(mftbmp_na->type, mftbmp_na->name, mftbmp_na->name_len, 0, rl[1].vcn, NULL, 0, ctx)) { ntfs_log_error("Failed to find last attribute extent of " "mft bitmap attribute.%s\n", es); ntfs_attr_put_search_ctx(ctx); mftbmp_na->allocated_size += vol->cluster_size; /* * The only thing that is now wrong is ->allocated_size of the * base attribute extent which chkdsk should be able to fix. */ errno = err; return -1; } m = ctx->mrec; a = ctx->attr; a->highest_vcn = cpu_to_sle64(rl[1].vcn - 2); errno = err;undo_alloc: err = errno; /* Remove the last run from the runlist. */ lcn = rl->lcn; rl->lcn = rl[1].lcn; rl->length = 0; /* FIXME: use an ntfs_cluster_free_* function */ if (ntfs_bitmap_clear_bit(vol->lcnbmp_na, lcn)) ntfs_log_error("Failed to free cluster.%s\n", es); else vol->free_clusters++; 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; return -1;}/** * ntfs_mft_bitmap_extend_allocation - extend mft bitmap attribute by a cluster * @vol: volume on which to extend the mft bitmap attribute * * Extend the mft bitmap attribute on the ntfs volume @vol by one cluster. * * 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_bitmap_extend_allocation(ntfs_volume *vol){ int ret; ntfs_log_enter("Entering\n"); ret = ntfs_mft_bitmap_extend_allocation_i(vol); ntfs_log_leave("\n"); return ret;}/** * ntfs_mft_bitmap_extend_initialized - extend mft bitmap initialized data * @vol: volume on which to extend the mft bitmap attribute * * Extend the initialized portion of the mft bitmap attribute on the ntfs * volume @vol by 8 bytes. * * Note: Only changes initialized_size and data_size, i.e. requires that * allocated_size is big enough to fit the new initialized_size. * * Return 0 on success and -1 on error with errno set to the error code.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -