📄 dir.c
字号:
ntfs_inode_mark_dirty(ni); /* Done! */ free(fn); free(si); ntfs_log_trace("Done.\n"); return ni;err_out: ntfs_log_trace("Failed.\n"); if (rollback_sd) ntfs_attr_remove(ni, AT_SECURITY_DESCRIPTOR, AT_UNNAMED, 0); if (rollback_data) ntfs_attr_remove(ni, AT_DATA, AT_UNNAMED, 0); /* * Free extent MFT records (should not exist any with current * ntfs_create implementation, but for any case if something will be * changed in the future). */ while (ni->nr_extents) if (ntfs_mft_record_free(ni->vol, *(ni->extent_nis))) { err = errno; ntfs_log_error("Failed to free extent MFT record. " "Leaving inconsistent metadata.\n"); } if (ntfs_mft_record_free(ni->vol, ni)) ntfs_log_error("Failed to free MFT record. " "Leaving inconsistent metadata. Run chkdsk.\n"); free(fn); free(si); errno = err; return NULL;}/** * Some wrappers around __ntfs_create() ... */ntfs_inode *ntfs_create(ntfs_inode *dir_ni, ntfschar *name, u8 name_len, dev_t type){ if (type != S_IFREG && type != S_IFDIR && type != S_IFIFO && type != S_IFSOCK) { ntfs_log_error("Invalid arguments.\n"); return NULL; } return __ntfs_create(dir_ni, name, name_len, type, 0, NULL, 0);}ntfs_inode *ntfs_create_device(ntfs_inode *dir_ni, ntfschar *name, u8 name_len, dev_t type, dev_t dev){ if (type != S_IFCHR && type != S_IFBLK) { ntfs_log_error("Invalid arguments.\n"); return NULL; } return __ntfs_create(dir_ni, name, name_len, type, dev, NULL, 0);}ntfs_inode *ntfs_create_symlink(ntfs_inode *dir_ni, ntfschar *name, u8 name_len, ntfschar *target, int target_len){ if (!target || !target_len) { ntfs_log_error("%s: Invalid argument (%p, %d)\n", __FUNCTION__, target, target_len); return NULL; } return __ntfs_create(dir_ni, name, name_len, S_IFLNK, 0, target, target_len);}int ntfs_check_empty_dir(ntfs_inode *ni){ ntfs_attr *na; int ret = 0; if (!(ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)) return 0; na = ntfs_attr_open(ni, AT_INDEX_ROOT, NTFS_INDEX_I30, 4); if (!na) { errno = EIO; ntfs_log_perror("Failed to open directory"); return -1; } /* Non-empty directory? */ if ((na->data_size != sizeof(INDEX_ROOT) + sizeof(INDEX_ENTRY_HEADER))){ /* Both ENOTEMPTY and EEXIST are ok. We use the more common. */ errno = ENOTEMPTY; ntfs_log_debug("Directory is not empty\n"); ret = -1; } ntfs_attr_close(na); return ret;}static int ntfs_check_unlinkable_dir(ntfs_inode *ni, FILE_NAME_ATTR *fn){ int link_count = le16_to_cpu(ni->mrec->link_count); int ret; ret = ntfs_check_empty_dir(ni); if (!ret || errno != ENOTEMPTY) return ret; /* * Directory is non-empty, so we can unlink only if there is more than * one "real" hard link, i.e. links aren't different DOS and WIN32 names */ if ((link_count == 1) || (link_count == 2 && fn->file_name_type == FILE_NAME_DOS)) { errno = ENOTEMPTY; ntfs_log_debug("Non-empty directory without hard links\n"); goto no_hardlink; } ret = 0;no_hardlink: return ret;}/** * ntfs_delete - delete file or directory from ntfs volume * @ni: ntfs inode for object to delte * @dir_ni: ntfs inode for directory in which delete object * @name: unicode name of the object to delete * @name_len: length of the name in unicode characters * * @ni is always closed after the call to this function (even if it failed), * user does not need to call ntfs_inode_close himself. * * Return 0 on success or -1 on error with errno set to the error code. */int ntfs_delete(ntfs_inode *ni, ntfs_inode *dir_ni, ntfschar *name, u8 name_len){ ntfs_attr_search_ctx *actx = NULL; FILE_NAME_ATTR *fn = NULL; BOOL looking_for_dos_name = FALSE, looking_for_win32_name = FALSE; BOOL case_sensitive_match = TRUE; int err = 0; ntfs_log_trace("Entering.\n"); if (!ni || !dir_ni || !name || !name_len) { ntfs_log_error("Invalid arguments.\n"); errno = EINVAL; goto err_out; } if (ni->nr_extents == -1) ni = ni->base_ni; if (dir_ni->nr_extents == -1) dir_ni = dir_ni->base_ni; /* * Search for FILE_NAME attribute with such name. If it's in POSIX or * WIN32_AND_DOS namespace, then simply remove it from index and inode. * If filename in DOS or in WIN32 namespace, then remove DOS name first, * only then remove WIN32 name. */ actx = ntfs_attr_get_search_ctx(ni, NULL); if (!actx) goto err_out;search: while (!ntfs_attr_lookup(AT_FILE_NAME, AT_UNNAMED, 0, CASE_SENSITIVE, 0, NULL, 0, actx)) { char *s; BOOL case_sensitive = IGNORE_CASE; errno = 0; fn = (FILE_NAME_ATTR*)((u8*)actx->attr + le16_to_cpu(actx->attr->value_offset)); s = ntfs_attr_name_get(fn->file_name, fn->file_name_length); ntfs_log_trace("name: '%s' type: %d dos: %d win32: %d " "case: %d\n", s, fn->file_name_type, looking_for_dos_name, looking_for_win32_name, case_sensitive_match); ntfs_attr_name_free(&s); if (looking_for_dos_name) { if (fn->file_name_type == FILE_NAME_DOS) break; else continue; } if (looking_for_win32_name) { if (fn->file_name_type == FILE_NAME_WIN32) break; else continue; } /* Ignore hard links from other directories */ if (dir_ni->mft_no != MREF_LE(fn->parent_directory)) { ntfs_log_debug("MFT record numbers don't match " "(%llu != %llu)\n", dir_ni->mft_no, MREF_LE(fn->parent_directory)); continue; } if (fn->file_name_type == FILE_NAME_POSIX || case_sensitive_match) case_sensitive = CASE_SENSITIVE; if (ntfs_names_are_equal(fn->file_name, fn->file_name_length, name, name_len, case_sensitive, ni->vol->upcase, ni->vol->upcase_len)){ if (fn->file_name_type == FILE_NAME_WIN32) { looking_for_dos_name = TRUE; ntfs_attr_reinit_search_ctx(actx); continue; } if (fn->file_name_type == FILE_NAME_DOS) looking_for_dos_name = TRUE; break; } } if (errno) { /* * If case sensitive search failed, then try once again * ignoring case. */ if (errno == ENOENT && case_sensitive_match) { case_sensitive_match = FALSE; ntfs_attr_reinit_search_ctx(actx); goto search; } goto err_out; } if (ntfs_check_unlinkable_dir(ni, fn) < 0) goto err_out; if (ntfs_index_remove(dir_ni, fn, le32_to_cpu(actx->attr->value_length))) goto err_out; if (ntfs_attr_record_rm(actx)) goto err_out; ni->mrec->link_count = cpu_to_le16(le16_to_cpu( ni->mrec->link_count) - 1); ntfs_inode_mark_dirty(ni); if (looking_for_dos_name) { looking_for_dos_name = FALSE; looking_for_win32_name = TRUE; ntfs_attr_reinit_search_ctx(actx); goto search; } /* TODO: Update object id, quota and securiry indexes if required. */ /* * If hard link count is not equal to zero then we are done. In other * case there are no reference to this inode left, so we should free all * non-resident attributes and mark all MFT record as not in use. */ if (ni->mrec->link_count) { ntfs_inode_update_times(ni, NTFS_UPDATE_CTIME); goto ok; } ntfs_attr_reinit_search_ctx(actx); while (!ntfs_attrs_walk(actx)) { if (actx->attr->non_resident) { runlist *rl; rl = ntfs_mapping_pairs_decompress(ni->vol, actx->attr, NULL); if (!rl) { err = errno; ntfs_log_error("Failed to decompress runlist. " "Leaving inconsistent metadata.\n"); continue; } if (ntfs_cluster_free_from_rl(ni->vol, rl)) { err = errno; ntfs_log_error("Failed to free clusters. " "Leaving inconsistent metadata.\n"); continue; } free(rl); } } if (errno != ENOENT) { err = errno; ntfs_log_error("Attribute enumeration failed. " "Probably leaving inconsistent metadata.\n"); } /* All extents should be attached after attribute walk. */ while (ni->nr_extents) if (ntfs_mft_record_free(ni->vol, *(ni->extent_nis))) { err = errno; ntfs_log_error("Failed to free extent MFT record. " "Leaving inconsistent metadata.\n"); } if (ntfs_mft_record_free(ni->vol, ni)) { err = errno; ntfs_log_error("Failed to free base MFT record. " "Leaving inconsistent metadata.\n"); } ni = NULL;ok: ntfs_inode_update_times(dir_ni, NTFS_UPDATE_MCTIME);out: if (actx) ntfs_attr_put_search_ctx(actx); if (ntfs_inode_close(dir_ni) && !err) err = errno; if (ntfs_inode_close(ni) && !err) err = errno; if (err) { errno = err; ntfs_log_debug("Could not delete file: %s\n", strerror(errno)); return -1; } ntfs_log_trace("Done.\n"); return 0;err_out: err = errno; goto out;}/** * ntfs_link - create hard link for file or directory * @ni: ntfs inode for object to create hard link * @dir_ni: ntfs inode for directory in which new link should be placed * @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 = EINVAL; ntfs_log_perror("ntfs_link wrong arguments"); goto err_out; } if (ni->flags & FILE_ATTR_REPARSE_POINT) { err = EOPNOTSUPP; goto err_out; } /* Create FILE_NAME attribute. */ fn_len = sizeof(FILE_NAME_ATTR) + name_len * sizeof(ntfschar); fn = ntfs_calloc(fn_len); if (!fn) { err = errno; 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_perror("Failed to add filename to the index"); 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_log_error("Failed to add FILE_NAME attribute.\n"); err = errno; /* Try to remove just added attribute from index. */ if (ntfs_index_remove(dir_ni, fn, fn_len)) 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: free(fn); errno = err; return -1;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -