📄 dir.c
字号:
* @name: unicode name of the new link * @name_len: length of the name in unicode characters * * NOTE: At present we allow creating hardlinks to directories, we use them * in a temporary state during rename. But it's defenitely bad idea to have * hard links to directories as a result of operation. * FIXME: Create internal __ntfs_link that allows hard links to a directories * and external ntfs_link that do not. Write ntfs_rename that uses __ntfs_link. * * Return 0 on success or -1 on error with errno set to the error code. */int ntfs_link(ntfs_inode *ni, ntfs_inode *dir_ni, ntfschar *name, u8 name_len){ FILE_NAME_ATTR *fn = NULL; int fn_len, err; ntfs_log_trace("Entering.\n"); if (!ni || !dir_ni || !name || !name_len || ni->mft_no == dir_ni->mft_no) { err = errno; ntfs_log_error("Invalid arguments.\n"); goto err_out; } /* Create FILE_NAME attribute. */ fn_len = sizeof(FILE_NAME_ATTR) + name_len * sizeof(ntfschar); fn = calloc(1, fn_len); if (!fn) { err = errno; ntfs_log_error("Not enough memory.\n"); goto err_out; } fn->parent_directory = MK_LE_MREF(dir_ni->mft_no, le16_to_cpu(dir_ni->mrec->sequence_number)); fn->file_name_length = name_len; fn->file_name_type = FILE_NAME_POSIX; fn->file_attributes = ni->flags; if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) fn->file_attributes |= FILE_ATTR_I30_INDEX_PRESENT; fn->allocated_size = cpu_to_sle64(ni->allocated_size); fn->data_size = cpu_to_sle64(ni->data_size); fn->creation_time = utc2ntfs(ni->creation_time); fn->last_data_change_time = utc2ntfs(ni->last_data_change_time); fn->last_mft_change_time = utc2ntfs(ni->last_mft_change_time); fn->last_access_time = utc2ntfs(ni->last_access_time); memcpy(fn->file_name, name, name_len * sizeof(ntfschar)); /* Add FILE_NAME attribute to index. */ if (ntfs_index_add_filename(dir_ni, fn, MK_MREF(ni->mft_no, le16_to_cpu(ni->mrec->sequence_number)))) { err = errno; ntfs_log_error("Failed to add entry to the index.\n"); goto err_out; } /* Add FILE_NAME attribute to inode. */ if (ntfs_attr_add(ni, AT_FILE_NAME, AT_UNNAMED, 0, (u8*)fn, fn_len)) { ntfs_index_context *ictx; err = errno; ntfs_log_error("Failed to add FILE_NAME attribute.\n"); /* Try to remove just added attribute from index. */ ictx = ntfs_index_ctx_get(dir_ni, NTFS_INDEX_I30, 4); if (!ictx) goto rollback_failed; if (ntfs_index_lookup(fn, fn_len, ictx)) { ntfs_index_ctx_put(ictx); goto rollback_failed; } if (ntfs_index_rm(ictx)) { ntfs_index_ctx_put(ictx); goto rollback_failed; } goto err_out; } /* Increment hard links count. */ ni->mrec->link_count = cpu_to_le16(le16_to_cpu( ni->mrec->link_count) + 1); /* Done! */ ntfs_inode_mark_dirty(ni); free(fn); ntfs_log_trace("Done.\n"); return 0;rollback_failed: ntfs_log_error("Rollback failed. Leaving inconsistent metadata.\n");err_out: ntfs_log_error("Failed.\n"); free(fn); errno = err; return -1;}#ifdef NTFS_RICH#include "layout.h"#include "tree.h"#include "bitmap.h"#include "rich.h"/** * ntfs_dir_rollback - Discard the in-memory directory changes * @dir: * * Description... * * Returns: */int ntfs_dir_rollback(struct ntfs_dir *dir){ int i; if (!dir) return -1; ntfs_log_trace ("dir %p, inode %lld, children %d\n", dir, dir ? MREF(dir->mft_num) : 0, dir ? dir->child_count : 0); if (ntfs_dt_rollback(dir->index) < 0) return -1; if (ntfs_bmp_rollback(dir->bitmap) < 0) return -1; for (i = 0; i < dir->child_count; i++) { if (ntfs_dir_rollback(dir->children[i]) < 0) return -1; } return 0;}/** * ntfs_dir_truncate - Shrink an index allocation * @vol: * @dir: * * Description... * * Returns: */int ntfs_dir_truncate(ntfs_volume *vol, struct ntfs_dir *dir){ //int i; //u8 *buffer; //int buf_count; s64 last_bit; INDEX_ENTRY *ie; if (!vol || !dir) return -1; ntfs_log_trace ("dir %p, inode %lld, children %d\n", dir, dir ? MREF(dir->mft_num) : 0, dir ? dir->child_count : 0); if ((dir->ialloc == NULL) || (dir->bitmap == NULL)) return 0;#if 0 buf_count = ROUND_UP(dir->bitmap->attr->allocated_size, vol->cluster_size) >> vol->cluster_size_bits; ntfs_log_debug("alloc = %lld bytes\n", dir->ialloc->allocated_size); ntfs_log_debug("alloc = %lld clusters\n", dir->ialloc->allocated_size >> vol->cluster_size_bits); ntfs_log_debug("bitmap bytes 0 to %lld\n", ((dir->ialloc->allocated_size >> vol->cluster_size_bits)-1)>>3); ntfs_log_debug("bitmap = %p\n", dir->bitmap); ntfs_log_debug("bitmap = %lld bytes\n", dir->bitmap->attr->allocated_size); ntfs_log_debug("bitmap = %d buffers\n", buf_count);#endif last_bit = ntfs_bmp_find_last_set(dir->bitmap); if (dir->ialloc->allocated_size == (dir->index_size * (last_bit + 1))) { //ntfs_log_debug("nothing to do\n"); return 0; } ntfs_log_debug("Truncation needed\n");#if 0 ntfs_log_debug("\tlast bit = %lld\n", last_bit); ntfs_log_debug("\tactual IALLOC size = %lld\n", dir->ialloc->allocated_size); ntfs_log_debug("\tshould IALLOC size = %lld\n", dir->index_size * (last_bit + 1));#endif if ((dir->index_size * (last_bit + 1)) == 0) { ntfs_log_debug("root dt %d, vcn = %lld\n", dir->index->changed, dir->index->vcn); //rollback all dts //ntfs_dt_rollback(dir->index); //dir->index = NULL; // What about the ROOT dt? ie = ntfs_ie_copy(dir->index->children[0]); if (!ie) { ntfs_log_warning("IE copy failed\n"); return -1; } ie = ntfs_ie_remove_vcn(ie); if (!ie) { ntfs_log_warning("IE remove vcn failed\n"); return -1; } //utils_dump_mem(dir->index->data, 0, dir->index->data_len, DM_DEFAULTS); ntfs_log_debug("\n"); //utils_dump_mem(ie, 0, ie->length, DM_DEFAULTS); ntfs_log_debug("\n"); ntfs_dt_root_replace(dir->index, 0, dir->index->children[0], ie); //utils_dump_mem(dir->index->data, 0, dir->index->data_len, DM_DEFAULTS); ntfs_log_debug("\n"); //ntfs_log_debug("root dt %d, vcn = %lld\n", dir->index->changed, dir->index->vcn); ntfs_ie_free(ie); ie = NULL; //index flags remove LARGE_INDEX dir->index->header->flags = 0; //rollback dir's bmp ntfs_bmp_free(dir->bitmap); dir->bitmap = NULL; /* for (i = 0; i < dir->index->child_count; i++) { ntfs_dt_rollback(dir->index->sub_nodes[i]); dir->index->sub_nodes[i] = NULL; } */ //ntfs_log_debug("dir->index->inodes[0] = %p\n", dir->index->inodes[0]); //remove 0xA0 attribute ntfs_mft_remove_attr(vol->private_bmp2, dir->inode, AT_INDEX_ALLOCATION); //remove 0xB0 attribute ntfs_mft_remove_attr(vol->private_bmp2, dir->inode, AT_BITMAP); } else { ntfs_log_warning("Cannot shrink directory\n"); //ntfs_dir_shrink_alloc //ntfs_dir_shrink_bitmap //make bitmap resident? } /* * Remove * dt -> dead * bitmap updated * rollback dead dts * commit bitmap * commit dts * commit dir */ /* * Reuse * search for lowest dead * update bitmap * init dt * remove from dead * insert into tree * init INDX */#if 0 buffer = ntfs_bmp_get_data(dir->bitmap, 0); if (!buffer) return -1; utils_dump_mem(buffer, 0, 8, DM_NO_ASCII); for (i = buf_count-1; i >= 0; i--) { if (buffer[i]) { ntfs_log_debug("alloc in use\n"); return 0; } }#endif // <dir>/$BITMAP($I30) // <dir>/$INDEX_ALLOCATION($I30) // $Bitmap // Find the highest set bit in the directory bitmap // can we free any clusters of the alloc? // if yes, resize attribute // Are *any* bits set? // If not remove ialloc return 0;}/** * ntfs_dir_commit - Write to disk the in-memory directory changes * @dir: * * Description... * * Returns: */int ntfs_dir_commit(struct ntfs_dir *dir){ int i; if (!dir) return 0; ntfs_log_trace ("dir %p, inode %lld, children %d\n", dir, dir ? MREF(dir->mft_num) : 0, dir ? dir->child_count : 0); if (NInoDirty(dir->inode)) { ntfs_inode_sync(dir->inode); ntfs_log_warning("\tntfs_inode_sync %llu\n", dir->inode->mft_no); } if (ntfs_dt_commit(dir->index) < 0) return -1; if (ntfs_bmp_commit(dir->bitmap) < 0) return -1; for (i = 0; i < dir->child_count; i++) { if (ntfs_dir_commit(dir->children[i]) < 0) return -1; } return 0;}/** * ntfs_dir_free - Destroy a directory object * @dir: * * Description... * * Returns: */void ntfs_dir_free(struct ntfs_dir *dir){ struct ntfs_dir *parent; int i; if (!dir) return; ntfs_log_trace ("dir %p, inode %lld, children %d\n", dir, dir ? MREF(dir->mft_num) : 0, dir ? dir->child_count : 0); ntfs_dir_rollback(dir); parent = dir->parent; if (parent) { for (i = 0; i < parent->child_count; i++) { if (parent->children[i] == dir) { parent->children[i] = NULL; } } } ntfs_attr_close(dir->iroot); ntfs_attr_close(dir->ialloc); ntfs_inode_close2(dir->inode); ntfs_dt_free (dir->index); ntfs_bmp_free(dir->bitmap); for (i = 0; i < dir->child_count; i++) ntfs_dir_free(dir->children[i]); free(dir->name); free(dir->children); free(dir);}/** * ntfs_dir_create - Create a representation of a directory * @vol: * @mft_num: * * Description... * * Returns: */struct ntfs_dir * ntfs_dir_create(ntfs_volume *vol, MFT_REF mft_num){ struct ntfs_dir *dir = NULL; ntfs_inode *inode = NULL; ATTR_RECORD *rec = NULL; INDEX_ROOT *ir = NULL; FILE_NAME_ATTR *name = NULL; if (!vol) return NULL; ntfs_log_trace ("inode %lld\n", MREF(mft_num)); inode = ntfs_inode_open2(vol, mft_num); if (!inode) return NULL; dir = calloc(1, sizeof(*dir)); if (!dir) { ntfs_inode_close2(inode); return NULL; } dir->inode = inode; dir->iroot = ntfs_attr_open(inode, AT_INDEX_ROOT, NTFS_INDEX_I30, 4); dir->ialloc = ntfs_attr_open(inode, AT_INDEX_ALLOCATION, NTFS_INDEX_I30, 4); if (!dir->iroot) { ntfs_dir_free(dir); return NULL; } dir->vol = vol; dir->parent = NULL; dir->name = NULL; dir->name_len = 0; dir->index = NULL; dir->children = NULL; dir->child_count = 0; dir->mft_num = mft_num; // This may not exist dir->bitmap = ntfs_bmp_create(inode, AT_BITMAP, NTFS_INDEX_I30, 4); if (dir->iroot) { rec = find_first_attribute(AT_INDEX_ROOT, inode->mrec); ir = (INDEX_ROOT*) ((u8*)rec + rec->value_offset); dir->index_size = ir->index_block_size; ntfs_log_debug("dir size = %d\n", dir->index_size); } else { // XXX !iroot? dir->index_size = 0; } // Finally, find the dir's name rec = find_first_attribute(AT_FILE_NAME, inode->mrec); name = (FILE_NAME_ATTR*) ((u8*)rec + rec->value_offset); dir->name_len = name->file_name_length; dir->name = malloc(sizeof(ntfschar) * dir->name_len); memcpy(dir->name, name->file_name, sizeof(ntfschar) * dir->name_len); return dir;}/** * ntfs_dir_add - Add a directory to another as a child * @parent: * @child: * * Description... * * Returns: */void ntfs_dir_add(struct ntfs_dir *parent, struct ntfs_dir *child){ if (!parent || !child) return; ntfs_log_trace ("parent %p, inode %lld, children %d\n", parent, parent ? MREF(parent->mft_num) : 0, parent ? parent->child_count : 0); ntfs_log_trace ("child %p, inode %lld, children %d\n", child, child ? MREF(child->mft_num) : 0, child ? child->child_count : 0); parent->child_count++; //ntfs_log_debug("child count = %d\n", parent->child_count); parent->children = realloc(parent->children, parent->child_count * sizeof(struct ntfs_dir*)); child->parent = parent; parent->children[parent->child_count-1] = child;}/** * ntfs_dir_find2 - Find a directory by name * @dir: * @name: * @name_len: * * Description... * * Returns: */struct ntfs_dir * ntfs_dir_find2(struct ntfs_dir *dir, ntfschar *name, int name_len){ int i; struct ntfs_dir *child = NULL; struct ntfs_dt *dt = NULL; int dt_num = 0; INDEX_ENTRY *ie; MFT_REF mft_num; if (!dir || !name) return NULL; ntfs_log_trace ("dir %p, inode %lld, children %d\n", dir, dir ? MREF(dir->mft_num) : 0, dir ? dir->child_count : 0); if (!dir->index) { // XXX when will this happen? ntfs_log_debug("ntfs_dir_find2 - directory has no index\n"); return NULL; } for (i = 0; i < dir->child_count; i++) { if (0 == ntfs_names_collate(name, name_len, dir->children[i]->name, dir->children[i]->name_len, 2, IGNORE_CASE, dir->vol->upcase, dir->vol->upcase_len)) return dir->children[i]; } dt = ntfs_dt_find2(dir->index, name, name_len, &dt_num); if (!dt) { ntfs_log_debug("can't find name in dir\n"); return NULL; } ie = dt->children[dt_num]; mft_num = ie->indexed_file; child = ntfs_dir_create(dir->vol, mft_num); if (!child) return NULL; child->index = ntfs_dt_create(child, NULL, -1); ntfs_dir_add(dir, child); return child;}#endif /* NTFS_RICH */#endif /* __VISOPSYS__ */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -