📄 inode.c
字号:
ntfs_attr_search_ctx *ctx; u8 *al = NULL, *aln; int al_len = 0; ATTR_LIST_ENTRY *ale = NULL; ntfs_attr *na; if (!ni) { ntfs_log_trace("Invalid arguments.\n"); errno = EINVAL; return -1; } ntfs_log_trace("Entering for inode 0x%llx.\n", (long long) ni->mft_no); if (NInoAttrList(ni) || ni->nr_extents) { ntfs_log_trace("Inode already has got attribute list.\n"); errno = EEXIST; return -1; } /* Form attribute list. */ ctx = ntfs_attr_get_search_ctx(ni, NULL); if (!ctx) { err = errno; ntfs_log_trace("Couldn't get search context.\n"); 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_trace("Eeek! Attribute list already present.\n"); 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_trace("Attribute lookup failed.\n"); 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_trace("Failed to free space for " "$ATTRIBUTE_LIST.\n"); 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_trace("Couldn't add $ATTRIBUTE_LIST to MFT record.\n"); goto rollback; } /* Resize it. */ na = ntfs_attr_open(ni, AT_ATTRIBUTE_LIST, AT_UNNAMED, 0); if (!na) { err = errno; ntfs_log_trace("Failed to open just added $ATTRIBUTE_LIST.\n"); goto remove_attrlist_record; } if (ntfs_attr_truncate(na, al_len)) { err = errno; ntfs_log_trace("Failed to resize just added $ATTRIBUTE_LIST.\n"); 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_trace("Rollback failed. Failed to remove attribute " "list record.\n"); } else ntfs_log_trace("Rollback failed. Couldn't find attribute list " "record.\n"); /* 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_trace("Rollback failed. Couldn't " "back attribute to base MFT record.\n"); } else ntfs_log_trace("Rollback failed. ntfs_attr_lookup " "failed.\n"); 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) { ntfs_log_trace("Invalid arguments.\n"); errno = EINVAL; return -1; } ntfs_log_trace("Entering for inode 0x%llx, size %d.\n", (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) { err = errno; ntfs_log_trace("Failed to get attribute search context.\n"); errno = err; 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_trace("Attribute lookup failed.\n"); 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_trace("Attribute lookup failed.\n"); } 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_trace("Failed to move out attribute.\n"); 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_trace("Attribute lookup failed.\n"); 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_atime - update access time for ntfs inode * @ni: ntfs inode for which update access time * * This function usually get called when user read not metadata from inode. * Do not update time for system files. */void ntfs_inode_update_atime(ntfs_inode *ni){ if (!NVolReadOnly(ni->vol) && !NVolNoATime(ni->vol) && (ni->mft_no >= FILE_first_user || ni->mft_no == FILE_root)) { ni->last_access_time = time(NULL); NInoFileNameSetDirty(ni); NInoSetDirty(ni); }}/** * ntfs_inode_update_time - update all times for ntfs inode * @ni: ntfs inode for which update times * * This function updates last access, mft and data change times. Usually * get called when user write not metadata to inode. Do not update time for * system files. */void ntfs_inode_update_time(ntfs_inode *ni){ if (!NVolReadOnly(ni->vol) && !NVolNoATime(ni->vol) && (ni->mft_no >= FILE_first_user || ni->mft_no == FILE_root)) { time_t now; now = time(NULL); ni->last_access_time = now; ni->last_data_change_time = now; 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 + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -