📄 mft.c
字号:
mft_na->data_size = old_data_size;undo_mftbmp_alloc: err = errno; if (ntfs_bitmap_clear_bit(mftbmp_na, bit)) ntfs_log_error("Failed to clear bit in mft bitmap.%s\n", es); errno = err;err_out: if (!errno) errno = EIO; return NULL;}/** * ntfs_mft_record_free - free an mft record on an ntfs volume * @vol: volume on which to free the mft record * @ni: open ntfs inode of the mft record to free * * Free the mft record of the open inode @ni on the mounted ntfs volume @vol. * Note that this function calls ntfs_inode_close() internally and hence you * cannot use the pointer @ni any more after this function returns success. * * On success return 0 and on error return -1 with errno set to the error code. */int ntfs_mft_record_free(ntfs_volume *vol, ntfs_inode *ni){ u64 mft_no; int err; u16 seq_no, old_seq_no; ntfs_log_trace("Entering for inode 0x%llx.\n", (long long) ni->mft_no); if (!vol || !vol->mftbmp_na || !ni) { errno = EINVAL; return -1; } /* Cache the mft reference for later. */ mft_no = ni->mft_no; /* Mark the mft record as not in use. */ ni->mrec->flags &= ~MFT_RECORD_IN_USE; /* Increment the sequence number, skipping zero, if it is not zero. */ old_seq_no = ni->mrec->sequence_number; seq_no = le16_to_cpu(old_seq_no); if (seq_no == 0xffff) seq_no = 1; else if (seq_no) seq_no++; ni->mrec->sequence_number = cpu_to_le16(seq_no); /* Set the inode dirty and write it out. */ ntfs_inode_mark_dirty(ni); if (ntfs_inode_sync(ni)) { err = errno; goto sync_rollback; } /* Clear the bit in the $MFT/$BITMAP corresponding to this record. */ if (ntfs_bitmap_clear_bit(vol->mftbmp_na, mft_no)) { err = errno; // FIXME: If ntfs_bitmap_clear_run() guarantees rollback on // error, this could be changed to goto sync_rollback; goto bitmap_rollback; } /* Throw away the now freed inode. */ if (!ntfs_inode_close(ni)) return 0; err = errno; /* Rollback what we did... */bitmap_rollback: if (ntfs_bitmap_set_bit(vol->mftbmp_na, mft_no)) ntfs_log_debug("Eeek! Rollback failed in ntfs_mft_record_free(). " "Leaving inconsistent metadata!\n");sync_rollback: ni->mrec->flags |= MFT_RECORD_IN_USE; ni->mrec->sequence_number = old_seq_no; ntfs_inode_mark_dirty(ni); errno = err; return -1;}#ifndef __VISOPSYS__#ifdef NTFS_RICH#include "bitmap.h"#include "dir.h"#include "tree.h"#include "index.h"#include "rich.h"/** * ntfs_mft_remove_attr - Remove an attribute from an MFT record * @bmp: * @inode: * @type: * * Description... * * Returns: */int ntfs_mft_remove_attr(struct ntfs_bmp *bmp, ntfs_inode *inode, ATTR_TYPES type){ ATTR_RECORD *attr20, *attrXX; MFT_RECORD *mft; u8 *src, *dst; int len; if (!inode) return 1; ntfs_log_trace ("\n"); attr20 = find_first_attribute(AT_ATTRIBUTE_LIST, inode->mrec); if (attr20) return 1; ntfs_log_debug("remove inode %lld, attr 0x%02X\n", inode->mft_no, type); attrXX = find_first_attribute(type, inode->mrec); if (!attrXX) return 1; if (utils_free_non_residents3(bmp, inode, attrXX)) return 1; // remove entry // inode->mrec mft = inode->mrec; //utils_dump_mem(mft, 0, mft->bytes_in_use, DM_DEFAULTS); ntfs_log_debug("\n"); //utils_dump_mem(attrXX, 0, attrXX->length, DM_DEFAULTS); ntfs_log_debug("\n"); //ntfs_log_debug("mrec = %p, attr = %p, diff = %d (0x%02X)\n", mft, attrXX, (u8*)attrXX - (u8*)mft, (u8*)attrXX - (u8*)mft); // memmove dst = (u8*) attrXX; src = dst + attrXX->length; len = (((u8*) mft + mft->bytes_in_use) - src); // fix mft header mft->bytes_in_use -= attrXX->length;#if 0 ntfs_log_debug("dst = 0x%02X, src = 0x%02X, len = 0x%02X\n", (dst - (u8*)mft), (src - (u8*)mft), len); ntfs_log_debug("attr %02X, len = 0x%02X\n", attrXX->type, attrXX->length); ntfs_log_debug("bytes in use = 0x%02X\n", mft->bytes_in_use); ntfs_log_debug("\n");#endif memmove(dst, src, len); //utils_dump_mem(mft, 0, mft->bytes_in_use, DM_DEFAULTS); ntfs_log_debug("\n"); NInoSetDirty(inode); return 0;}/** * ntfs_mft_add_attr - Add an attribute to an MFT record * @inode: * @type: * @data: * @data_len: * * Description... * * Returns: */ATTR_RECORD * ntfs_mft_add_attr(ntfs_inode *inode, ATTR_TYPES type, u8 *data, int data_len){ MFT_RECORD *mrec; ATTR_RECORD *attr; u8 *ptr; u8 *src; u8 *dst; int len; int attr_size; if (!inode) return NULL; if (!data) return NULL; ntfs_log_trace ("inode %p, mft %lld, attr 0x%02x, len %d\n", inode, inode->mft_no, type, data_len); attr_size = ATTR_SIZE(data_len); mrec = inode->mrec; if (!mrec) return NULL; if ((mrec->bytes_in_use + attr_size + 0x18) > mrec->bytes_allocated) { ntfs_log_debug("attribute is too big to fit in the record\n"); return NULL; } ptr = (u8*) inode->mrec + mrec->attrs_offset; while (1) { attr = (ATTR_RECORD*) ptr; if (type < attr->type) break; ptr += attr->length; } //ntfs_log_debug("insert before attr 0x%02X\n", attr->type); len = ((u8*) mrec + mrec->bytes_in_use) - ((u8*) attr); src = (u8*) attr; dst = src + attr_size + 0x18; memmove(dst, src, len); src = data; dst = (u8*) attr + 0x18; len = data_len; // XXX wipe slack space after attr? memcpy(dst, src, len); mrec->bytes_in_use += attr_size + 0x18; memset(attr, 0, 0x18); *(u32*)((u8*) attr + 0x00) = type; *(u32*)((u8*) attr + 0x04) = attr_size + 0x18; *(u16*)((u8*) attr + 0x0E) = mrec->next_attr_instance; *(u32*)((u8*) attr + 0x10) = data_len; *(u32*)((u8*) attr + 0x14) = 0x18; mrec->next_attr_instance++; return attr;}/** * ntfs_mft_resize_resident - Resize a resident attribute in an MFT record * @inode: * @type: * @name: * @name_len: * @data: * @data_len: * * Description... * * Returns: */int ntfs_mft_resize_resident(ntfs_inode *inode, ATTR_TYPES type, ntfschar *name, int name_len, u8 *data, int data_len){ int mft_size; int mft_usage; int mft_free; int attr_orig; int attr_new; u8 *src; u8 *dst; u8 *end; int len; ntfs_attr_search_ctx *ctx = NULL; ATTR_RECORD *arec = NULL; MFT_RECORD *mrec = NULL; int res = -1; ntfs_log_trace ("\n"); // XXX only works when attr is in base inode if ((!inode) || (!inode->mrec)) return -1; if ((!data) || (data_len < 0)) return -1; mrec = inode->mrec; ntfs_log_debug("inode = %lld\n", MREF(inode->mft_no)); //utils_dump_mem(mrec, 0, 1024, DM_DEFAULTS); mft_size = mrec->bytes_allocated; mft_usage = mrec->bytes_in_use; mft_free = mft_size - mft_usage; //ntfs_log_debug("mft_size = %d\n", mft_size); //ntfs_log_debug("mft_usage = %d\n", mft_usage); //ntfs_log_debug("mft_free = %d\n", mft_free); //ntfs_log_debug("\n"); ctx = ntfs_attr_get_search_ctx(inode, NULL); if (!ctx) goto done; ntfs_name_print(name, name_len); ntfs_log_debug(" type = 0x%02x\n", type); if (ntfs_attr_lookup(type, name, name_len, CASE_SENSITIVE, 0, NULL, 0, ctx) != 0) goto done; arec = ctx->attr; if (arec->non_resident) { ntfs_log_debug("attribute isn't resident\n"); goto done; } attr_orig = arec->value_length; attr_new = data_len; ntfs_log_debug("attr orig = %d\n", attr_orig); ntfs_log_debug("attr new = %d\n", attr_new); //ntfs_log_debug("\n"); if ((attr_new - attr_orig + mft_usage) > mft_size) { ntfs_log_debug("attribute won't fit into mft record\n"); goto done; } //ntfs_log_debug("new free space = %d\n", mft_size - (attr_new - attr_orig + mft_usage)); src = (u8*)arec + arec->length; dst = src + (attr_new - attr_orig); end = (u8*)mrec + mft_usage; len = end - src; //ntfs_log_debug("src = %d\n", src - (u8*)mrec); //ntfs_log_debug("dst = %d\n", dst - (u8*)mrec); //ntfs_log_debug("end = %d\n", end - (u8*)mrec); //ntfs_log_debug("len = %d\n", len); if (src != dst) memmove(dst, src, len); memcpy((u8*)arec + arec->value_offset, data, data_len); mrec->bytes_in_use += (attr_new - attr_orig); arec->length += (attr_new - attr_orig); arec->value_length += (attr_new - attr_orig); memset((u8*)mrec + mrec->bytes_in_use, 0, mft_size - mrec->bytes_in_use); mft_usage += (attr_new - attr_orig); //utils_dump_mem(mrec, 0, mft_size, DM_DEFAULTS); res = 0;done: ntfs_attr_put_search_ctx(ctx); return res;}/** * ntfs_mft_free_space - Calculate the free space (bytes) in an MFT record * @dir: * * Description... * * Returns: */int ntfs_mft_free_space(struct ntfs_dir *dir){ int res = 0; MFT_RECORD *mft; if ((!dir) || (!dir->inode)) return -1; ntfs_log_trace ("\n"); mft = (MFT_RECORD*) dir->inode->mrec; res = mft->bytes_allocated - mft->bytes_in_use; return res;}/** * ntfs_mft_add_index - Add an index (directory) to an MFT record * @dir: * * Description... * * Returns: */int ntfs_mft_add_index(struct ntfs_dir *dir){ ntfs_volume *vol; u8 *buffer = NULL; ATTR_RECORD *attr = NULL; struct ntfs_dt *dt = NULL; INDEX_ENTRY *ie = NULL; if (!dir) return 1; if (dir->bitmap && dir->ialloc) return 0; if (dir->bitmap || dir->ialloc) return 1; if (dir->index_size < 512) return 1; ntfs_log_trace ("\n"); vol = dir->vol; ntfs_log_debug("add two attrs to "); ntfs_name_print(dir->name, dir->name_len); ntfs_log_debug("\n"); ntfs_log_debug("index size = %d\n", dir->index_size); buffer = malloc(dir->index_size); if (!buffer) return 1; dt = ntfs_dt_create(dir, dir->index, -1); if (!dt) return 1; dt->vcn = 0; // New alloc record ie = ntfs_ie_copy(dir->index->children[dir->index->child_count-1]); ie = ntfs_ie_set_vcn(ie, dt->vcn); // can't replace ie yet, there may not be room ntfs_ie_free(ie); ntfs_dt_transfer2(dir->index, dt, 0, dir->index->child_count - 1); ntfs_log_debug("root has %d children\n", dir->index->child_count); ntfs_log_debug("node has %d children\n", dt->child_count); ntfs_dt_free(dt); // create a new dt // attach dt to dir // move entries into alloc // shrink root // transfer keys to new node // hook up root & alloc dts // need disk allocation before here // Index Allocation memset(buffer, 0, 128); attr = ntfs_mft_add_attr(dir->inode, AT_INDEX_ALLOCATION, buffer, 0x48); // Bitmap memset(buffer, 0, 8); buffer[0] = 0x01; //ntfs_log_debug("inode = %p\n", dir->inode); attr = ntfs_mft_add_attr(dir->inode, AT_BITMAP, buffer, 8); // attach alloc and bitmap to dir // need to create ntfs_attr's for them // one indx record // 8 bits of bitmap if (0) ntfs_bmp_find_space(NULL, 0, 0); //ntfs_log_debug("m1 = %lld\n", vol->mft_zone_start); //ntfs_log_debug("m2 = %lld\n", vol->mft_zone_end); //ntfs_log_debug("m3 = %lld\n", vol->mft_zone_pos); //ntfs_log_debug("z1 = %lld\n", vol->data1_zone_pos); //ntfs_log_debug("z2 = %lld\n", vol->data2_zone_pos); free(buffer); return 0;}#endif /* NTFS_RICH *//** * ntfs_mft_usn_dec - Decrement USN by one * @mrec: pointer to an mft record * * On success return 0 and on error return -1 with errno set. */int ntfs_mft_usn_dec(MFT_RECORD *mrec){ u16 usn, *usnp; if (!mrec) { errno = EINVAL; return -1; } usnp = (u16 *)((char *)mrec + le16_to_cpu(mrec->usa_ofs)); usn = le16_to_cpup(usnp); if (usn-- <= 1) usn = 0xfffe; *usnp = cpu_to_le16(usn); return 0;}#endif /* __VISOPSYS__ */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -