inode.c
来自「LINUX下读写NTFS分区的工具。 已经集成了通过LIBCONV库支持中文的」· C语言 代码 · 共 1,184 行 · 第 1/3 页
C
1,184 行
if (err) { errno = err; ret = -1; } ntfs_log_leave("\n"); return ret;}/** * ntfs_inode_add_attrlist - add attribute list to inode and fill it * @ni: opened ntfs inode to which add attribute list * * Return 0 on success or -1 on error with errno set to the error code. * The following error codes are defined: * EINVAL - Invalid arguments were passed to the function. * EEXIST - Attribute list already exist. * EIO - Input/Ouput error occurred. * ENOMEM - Not enough memory to perform add. */int ntfs_inode_add_attrlist(ntfs_inode *ni){ int err; ntfs_attr_search_ctx *ctx; u8 *al = NULL, *aln; int al_len = 0; ATTR_LIST_ENTRY *ale = NULL; ntfs_attr *na; if (!ni) { errno = EINVAL; ntfs_log_perror("%s", __FUNCTION__); return -1; } ntfs_log_trace("inode %llu\n", (unsigned long long) ni->mft_no); if (NInoAttrList(ni) || ni->nr_extents) { errno = EEXIST; ntfs_log_perror("Inode already has attribute list"); return -1; } /* Form attribute list. */ ctx = ntfs_attr_get_search_ctx(ni, NULL); if (!ctx) { err = errno; goto err_out; } /* Walk through all attributes. */ while (!ntfs_attr_lookup(AT_UNUSED, NULL, 0, 0, 0, NULL, 0, ctx)) { int ale_size; if (ctx->attr->type == AT_ATTRIBUTE_LIST) { err = EIO; ntfs_log_perror("Attribute list already present"); goto put_err_out; } ale_size = (sizeof(ATTR_LIST_ENTRY) + sizeof(ntfschar) * ctx->attr->name_length + 7) & ~7; al_len += ale_size; aln = realloc(al, al_len); if (!aln) { err = errno; ntfs_log_perror("Failed to realloc %d bytes", al_len); goto put_err_out; } ale = (ATTR_LIST_ENTRY *)(aln + ((u8 *)ale - al)); al = aln; memset(ale, 0, ale_size); /* Add attribute to attribute list. */ ale->type = ctx->attr->type; ale->length = cpu_to_le16((sizeof(ATTR_LIST_ENTRY) + sizeof(ntfschar) * ctx->attr->name_length + 7) & ~7); ale->name_length = ctx->attr->name_length; ale->name_offset = (u8 *)ale->name - (u8 *)ale; if (ctx->attr->non_resident) ale->lowest_vcn = ctx->attr->lowest_vcn; else ale->lowest_vcn = 0; ale->mft_reference = MK_LE_MREF(ni->mft_no, le16_to_cpu(ni->mrec->sequence_number)); ale->instance = ctx->attr->instance; memcpy(ale->name, (u8 *)ctx->attr + le16_to_cpu(ctx->attr->name_offset), ctx->attr->name_length * sizeof(ntfschar)); ale = (ATTR_LIST_ENTRY *)(al + al_len); } /* Check for real error occurred. */ if (errno != ENOENT) { err = errno; ntfs_log_perror("%s: Attribute lookup failed, inode %lld", __FUNCTION__, (long long)ni->mft_no); goto put_err_out; } /* Set in-memory attribute list. */ ni->attr_list = al; ni->attr_list_size = al_len; NInoSetAttrList(ni); NInoAttrListSetDirty(ni); /* Free space if there is not enough it for $ATTRIBUTE_LIST. */ if (le32_to_cpu(ni->mrec->bytes_allocated) - le32_to_cpu(ni->mrec->bytes_in_use) < offsetof(ATTR_RECORD, resident_end)) { if (ntfs_inode_free_space(ni, offsetof(ATTR_RECORD, resident_end))) { /* Failed to free space. */ err = errno; ntfs_log_perror("Failed to free space for attrlist"); goto rollback; } } /* Add $ATTRIBUTE_LIST to mft record. */ if (ntfs_resident_attr_record_add(ni, AT_ATTRIBUTE_LIST, NULL, 0, NULL, 0, 0) < 0) { err = errno; ntfs_log_perror("Couldn't add $ATTRIBUTE_LIST to MFT"); goto rollback; } /* Resize it. */ na = ntfs_attr_open(ni, AT_ATTRIBUTE_LIST, AT_UNNAMED, 0); if (!na) { err = errno; ntfs_log_perror("Failed to open just added $ATTRIBUTE_LIST"); goto remove_attrlist_record; } if (ntfs_attr_truncate(na, al_len)) { err = errno; ntfs_log_perror("Failed to resize just added $ATTRIBUTE_LIST"); ntfs_attr_close(na); goto remove_attrlist_record;; } ntfs_attr_put_search_ctx(ctx); ntfs_attr_close(na); return 0;remove_attrlist_record: /* Prevent ntfs_attr_recorm_rm from freeing attribute list. */ ni->attr_list = NULL; NInoClearAttrList(ni); /* Remove $ATTRIBUTE_LIST record. */ ntfs_attr_reinit_search_ctx(ctx); if (!ntfs_attr_lookup(AT_ATTRIBUTE_LIST, NULL, 0, CASE_SENSITIVE, 0, NULL, 0, ctx)) { if (ntfs_attr_record_rm(ctx)) ntfs_log_perror("Rollback failed to remove attrlist"); } else ntfs_log_perror("Rollback failed to find attrlist"); /* Setup back in-memory runlist. */ ni->attr_list = al; ni->attr_list_size = al_len; NInoSetAttrList(ni);rollback: /* * Scan attribute list for attributes that placed not in the base MFT * record and move them to it. */ ntfs_attr_reinit_search_ctx(ctx); ale = (ATTR_LIST_ENTRY*)al; while ((u8*)ale < al + al_len) { if (MREF_LE(ale->mft_reference) != ni->mft_no) { if (!ntfs_attr_lookup(ale->type, ale->name, ale->name_length, CASE_SENSITIVE, sle64_to_cpu(ale->lowest_vcn), NULL, 0, ctx)) { if (ntfs_attr_record_move_to(ctx, ni)) ntfs_log_perror("Rollback failed to " "move attribute"); } else ntfs_log_perror("Rollback failed to find attr"); ntfs_attr_reinit_search_ctx(ctx); } ale = (ATTR_LIST_ENTRY*)((u8*)ale + le16_to_cpu(ale->length)); } /* Remove in-memory attribute list. */ ni->attr_list = NULL; ni->attr_list_size = 0; NInoClearAttrList(ni); NInoAttrListClearDirty(ni);put_err_out: ntfs_attr_put_search_ctx(ctx);err_out: free(al); errno = err; return -1;}/** * ntfs_inode_free_space - free space in the MFT record of inode * @ni: ntfs inode in which MFT record free space * @size: amount of space needed to free * * Return 0 on success or -1 on error with errno set to the error code. */int ntfs_inode_free_space(ntfs_inode *ni, int size){ ntfs_attr_search_ctx *ctx; int freed, err; if (!ni || size < 0) { errno = EINVAL; ntfs_log_perror("%s: ni=%p size=%d", __FUNCTION__, ni, size); return -1; } ntfs_log_trace("Entering for inode %lld, size %d\n", (unsigned long long)ni->mft_no, size); freed = (le32_to_cpu(ni->mrec->bytes_allocated) - le32_to_cpu(ni->mrec->bytes_in_use)); if (size <= freed) return 0; ctx = ntfs_attr_get_search_ctx(ni, NULL); if (!ctx) return -1; /* * Chkdsk complain if $STANDARD_INFORMATION is not in the base MFT * record. FIXME: I'm not sure in this, need to recheck. For now simply * do not move $STANDARD_INFORMATION at all. * * Also we can't move $ATTRIBUTE_LIST from base MFT_RECORD, so position * search context on first attribute after $STANDARD_INFORMATION and * $ATTRIBUTE_LIST. * * Why we reposition instead of simply skip this attributes during * enumeration? Because in case we have got only in-memory attribute * list ntfs_attr_lookup will fail when it will try to find * $ATTRIBUTE_LIST. */ if (ntfs_attr_lookup(AT_FILE_NAME, NULL, 0, CASE_SENSITIVE, 0, NULL, 0, ctx)) { if (errno != ENOENT) { err = errno; ntfs_log_perror("%s: attr lookup failed #2", __FUNCTION__); goto put_err_out; } if (ctx->attr->type == AT_END) { err = ENOSPC; goto put_err_out; } } while (1) { int record_size; /* * Check whether attribute is from different MFT record. If so, * find next, because we don't need such. */ while (ctx->ntfs_ino->mft_no != ni->mft_no) { if (ntfs_attr_lookup(AT_UNUSED, NULL, 0, CASE_SENSITIVE, 0, NULL, 0, ctx)) { err = errno; if (errno != ENOENT) { ntfs_log_perror("Attr lookup failed #2"); } else err = ENOSPC; goto put_err_out; } } record_size = le32_to_cpu(ctx->attr->length); /* Move away attribute. */ if (ntfs_attr_record_move_away(ctx, 0)) { err = errno; ntfs_log_perror("Failed to move out attribute #2"); break; } freed += record_size; /* Check whether we done. */ if (size <= freed) { ntfs_attr_put_search_ctx(ctx); return 0; } /* * Reposition to first attribute after $STANDARD_INFORMATION and * $ATTRIBUTE_LIST (see comments upwards). */ ntfs_attr_reinit_search_ctx(ctx); if (ntfs_attr_lookup(AT_FILE_NAME, NULL, 0, CASE_SENSITIVE, 0, NULL, 0, ctx)) { if (errno != ENOENT) { err = errno; ntfs_log_perror("Attr lookup #2 failed"); break; } if (ctx->attr->type == AT_END) { err = ENOSPC; break; } } }put_err_out: ntfs_attr_put_search_ctx(ctx); if (err == ENOSPC) ntfs_log_trace("No attributes left that can be moved out.\n"); errno = err; return -1;}/** * ntfs_inode_update_times - update selected time fields for ntfs inode * @ni: ntfs inode for which update time fields * @mask: select which time fields should be updated * * This function updates time fields to current time. Fields to update are * selected using @mask (see enum @ntfs_time_update_flags for posssible values). */void ntfs_inode_update_times(ntfs_inode *ni, ntfs_time_update_flags mask){ time_t now; if (!ni) { ntfs_log_error("%s(): Invalid arguments.\n", __FUNCTION__); return; } if ((ni->mft_no < FILE_first_user && ni->mft_no != FILE_root) || NVolReadOnly(ni->vol) || !mask) return; now = time(NULL); if (mask & NTFS_UPDATE_ATIME) ni->last_access_time = now; if (mask & NTFS_UPDATE_MTIME) ni->last_data_change_time = now; if (mask & NTFS_UPDATE_CTIME) ni->last_mft_change_time = now; NInoFileNameSetDirty(ni); NInoSetDirty(ni);}/** * ntfs_inode_badclus_bad - check for $Badclus:$Bad data attribute * @mft_no: mft record number where @attr is present * @attr: attribute record used to check for the $Bad attribute * * Check if the mft record given by @mft_no and @attr contains the bad sector * list. Please note that mft record numbers describing $Badclus extent inodes * will not match the current $Badclus:$Bad check. * * On success return 1 if the file is $Badclus:$Bad, otherwise return 0. * On error return -1 with errno set to the error code. */int ntfs_inode_badclus_bad(u64 mft_no, ATTR_RECORD *attr){ int len, ret = 0; ntfschar *ustr; if (!attr) { ntfs_log_error("Invalid argument.\n"); errno = EINVAL; return -1; } if (mft_no != FILE_BadClus) return 0; if (attr->type != AT_DATA) return 0; if ((ustr = ntfs_str2ucs("$Bad", &len)) == NULL) { ntfs_log_perror("Couldn't convert '$Bad' to Unicode"); return -1; } if (ustr && ntfs_names_are_equal(ustr, len, (ntfschar *)((u8 *)attr + le16_to_cpu(attr->name_offset)), attr->name_length, 0, NULL, 0)) ret = 1; ntfs_ucsfree(ustr); return ret;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?