📄 inode.c
字号:
return -1; } if (ni->nr_extents == -1) ni = ni->base_ni; ntfs_log_trace("Entering for inode 0x%llx.\n", (long long) ni->mft_no); /* Inode haven't got attribute list, thus nothing to attach. */ if (!NInoAttrList(ni)) return 0; if (!ni->attr_list) { ntfs_log_trace("Corrupt in-memory struct.\n"); errno = EINVAL; return -1; } /* Walk through attribute list and attach all extents. */ errno = 0; ale = (ATTR_LIST_ENTRY *)ni->attr_list; while ((u8*)ale < ni->attr_list + ni->attr_list_size) { if (ni->mft_no != MREF_LE(ale->mft_reference) && prev_attached != MREF_LE(ale->mft_reference)) { if (!ntfs_extent_inode_open(ni, MREF_LE(ale->mft_reference))) { ntfs_log_trace("Couldn't attach extent inode.\n"); return -1; } prev_attached = MREF_LE(ale->mft_reference); } ale = (ATTR_LIST_ENTRY *)((u8*)ale + le16_to_cpu(ale->length)); } return 0;}/** * ntfs_inode_sync_standard_information - update standard information attribute * @ni: ntfs inode to update standard information * * Return 0 on success or -1 on error with errno set to the error code. */static int ntfs_inode_sync_standard_information(ntfs_inode *ni){ ntfs_attr_search_ctx *ctx; STANDARD_INFORMATION *std_info; int err; ntfs_log_trace("Entering for inode 0x%llx.\n", (long long) ni->mft_no); ctx = ntfs_attr_get_search_ctx(ni, NULL); if (!ctx) return -1; if (ntfs_attr_lookup(AT_STANDARD_INFORMATION, AT_UNNAMED, 0, CASE_SENSITIVE, 0, NULL, 0, ctx)) { err = errno; ntfs_log_trace("Failed to receive STANDARD_INFORMATION " "attribute.\n"); ntfs_attr_put_search_ctx(ctx); errno = err; return -1; } std_info = (STANDARD_INFORMATION *)((u8 *)ctx->attr + le16_to_cpu(ctx->attr->value_offset)); std_info->file_attributes = ni->flags; std_info->creation_time = utc2ntfs(ni->creation_time); std_info->last_data_change_time = utc2ntfs(ni->last_data_change_time); std_info->last_mft_change_time = utc2ntfs(ni->last_mft_change_time); std_info->last_access_time = utc2ntfs(ni->last_access_time); ntfs_inode_mark_dirty(ctx->ntfs_ino); ntfs_attr_put_search_ctx(ctx); return 0;}/** * ntfs_inode_sync_file_name - update FILE_NAME attributes * @ni: ntfs inode to update FILE_NAME attributes * * Update all FILE_NAME attributes for inode @ni in the index. * * Return 0 on success or -1 on error with errno set to the error code. */static int ntfs_inode_sync_file_name(ntfs_inode *ni){ ntfs_attr_search_ctx *ctx = NULL; ntfs_index_context *ictx; ntfs_inode *index_ni; FILE_NAME_ATTR *fn; int err = 0; ntfs_log_trace("Entering for inode 0x%llx.\n", (long long) ni->mft_no); ctx = ntfs_attr_get_search_ctx(ni, NULL); if (!ctx) { err = errno; ntfs_log_trace("Failed to get attribute search context.\n"); goto err_out; } /* Walk through all FILE_NAME attributes and update them. */ while (!ntfs_attr_lookup(AT_FILE_NAME, NULL, 0, 0, 0, NULL, 0, ctx)) { fn = (FILE_NAME_ATTR *)((u8 *)ctx->attr + le16_to_cpu(ctx->attr->value_offset)); if (MREF_LE(fn->parent_directory) == ni->mft_no) { /* * WARNING: We cheater here and obtain 2 attribute * search contexts for one inode (first we obtained * above, second will be obtained inside * ntfs_index_lookup), it's acceptable for library, * but will lock kernel. */ index_ni = ni; } else index_ni = ntfs_inode_open(ni->vol, le64_to_cpu(fn->parent_directory)); if (!index_ni) { if (!err) err = errno; ntfs_log_trace("Failed to open inode with index.\n"); continue; } ictx = ntfs_index_ctx_get(index_ni, NTFS_INDEX_I30, 4); if (!ictx) { if (!err) err = errno; ntfs_log_trace("Failed to get index context.\n"); ntfs_inode_close(index_ni); continue; } if (ntfs_index_lookup(fn, sizeof(FILE_NAME_ATTR), ictx)) { if (!err) { if (errno == ENOENT) err = EIO; else err = errno; } ntfs_log_trace("Index lookup failed.\n"); ntfs_index_ctx_put(ictx); ntfs_inode_close(index_ni); continue; } /* Update flags and file size. */ fn = (FILE_NAME_ATTR *)ictx->data; fn->file_attributes = (fn->file_attributes & ~FILE_ATTR_VALID_FLAGS) | (ni->flags & FILE_ATTR_VALID_FLAGS); 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); ntfs_index_entry_mark_dirty(ictx); ntfs_index_ctx_put(ictx); if (ni != index_ni) ntfs_inode_close(index_ni); } /* Check for real error occurred. */ if (errno != ENOENT) { err = errno; ntfs_log_trace("Attribute lookup failed.\n"); goto err_out; } ntfs_attr_put_search_ctx(ctx); if (err) { errno = err; return -1; } return 0;err_out: if (ctx) ntfs_attr_put_search_ctx(ctx); errno = err; return -1;}/** * ntfs_inode_sync - write the inode (and its dirty extents) to disk * @ni: ntfs inode to write * * Write the inode @ni to disk as well as its dirty extent inodes if such * exist and @ni is a base inode. If @ni is an extent inode, only @ni is * written completely disregarding its base inode and any other extent inodes. * * For a base inode with dirty extent inodes if any writes fail for whatever * reason, the failing inode is skipped and the sync process is continued. At * the end the error condition that brought about the failure is returned. Thus * the smallest amount of data loss possible occurs. * * 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. * EBUSY - Inode and/or one of its extents is busy, try again later. * EIO - I/O error while writing the inode (or one of its extents). */int ntfs_inode_sync(ntfs_inode *ni){ int err = 0; if (!ni) { errno = EINVAL; return -1; } ntfs_log_trace("Entering for inode 0x%llx.\n", (long long) ni->mft_no); /* Update STANDARD_INFORMATION. */ if ((ni->mrec->flags & MFT_RECORD_IN_USE) && ni->nr_extents != -1 && ntfs_inode_sync_standard_information(ni)) { if (!err || errno == EIO) { err = errno; if (err != EIO) err = EBUSY; } ntfs_log_trace("Failed to sync standard information.\n"); } /* Update FILE_NAME's in the index. */ if ((ni->mrec->flags & MFT_RECORD_IN_USE) && ni->nr_extents != -1 && NInoFileNameTestAndClearDirty(ni) && ntfs_inode_sync_file_name(ni)) { if (!err || errno == EIO) { err = errno; if (err != EIO) err = EBUSY; } ntfs_log_trace("Failed to sync FILE_NAME attributes.\n"); NInoFileNameSetDirty(ni); } /* Write out attribute list from cache to disk. */ if ((ni->mrec->flags & MFT_RECORD_IN_USE) && ni->nr_extents != -1 && NInoAttrList(ni) && NInoAttrListTestAndClearDirty(ni)) { ntfs_attr *na; na = ntfs_attr_open(ni, AT_ATTRIBUTE_LIST, AT_UNNAMED, 0); if (!na) { if (!err || errno == EIO) { err = errno; if (err != EIO) err = EBUSY; ntfs_log_trace("Attribute list sync failed (open " "failed).\n"); } NInoAttrListSetDirty(ni); } else { if (na->data_size == ni->attr_list_size) { if (ntfs_attr_pwrite(na, 0, ni->attr_list_size, ni->attr_list) != ni->attr_list_size) { if (!err || errno == EIO) { err = errno; if (err != EIO) err = EBUSY; ntfs_log_trace("Attribute list sync " "failed (write failed).\n"); } NInoAttrListSetDirty(ni); } } else { err = EIO; ntfs_log_trace("Attribute list sync failed (invalid size).\n"); NInoAttrListSetDirty(ni); } ntfs_attr_close(na); } } /* Write this inode out to the $MFT (and $MFTMirr if applicable). */ if (NInoTestAndClearDirty(ni)) { if (ntfs_mft_record_write(ni->vol, ni->mft_no, ni->mrec)) { if (!err || errno == EIO) { err = errno; if (err != EIO) err = EBUSY; } NInoSetDirty(ni); ntfs_log_trace("Base MFT record sync failed.\n"); } } /* If this is a base inode with extents write all dirty extents, too. */ if (ni->nr_extents > 0) { s32 i; for (i = 0; i < ni->nr_extents; ++i) { ntfs_inode *eni; eni = ni->extent_nis[i]; if (NInoTestAndClearDirty(eni)) { if (ntfs_mft_record_write(eni->vol, eni->mft_no, eni->mrec)) { if (!err || errno == EIO) { err = errno; if (err != EIO) err = EBUSY; } NInoSetDirty(eni); ntfs_log_trace("Extent MFT record sync " "failed.\n"); } } } } if (!err) return 0; errno = err; return -1;}/** * 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, *aln; int al_len, al_allocated; ATTR_LIST_ENTRY *ale; 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; } al_allocated = 0x40; al_len = 0; al = malloc(al_allocated); ale = (ATTR_LIST_ENTRY *) al; if (!al) { ntfs_log_trace("Not enough memory.\n"); errno = ENOMEM; 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)) { if (ctx->attr->type == AT_ATTRIBUTE_LIST) { err = EIO; ntfs_log_trace("Eeek! Attribute list already present.\n"); goto put_err_out; } /* Calculate new length of attribute list. */ al_len += (sizeof(ATTR_LIST_ENTRY) + sizeof(ntfschar) * ctx->attr->name_length + 7) & ~7; /* Allocate more memory if needed. */ while (al_len > al_allocated) { al_allocated += 0x40; aln = realloc(al, al_allocated); if (!aln) { ntfs_log_trace("Not enough memory.\n"); err = ENOMEM; goto put_err_out; } ale = (ATTR_LIST_ENTRY *)(aln + ((u8 *)ale - al)); al = aln; } /* 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; } /* Deallocate trailing memory. */ aln = realloc(al, al_len); if (!aln) { err = errno; ntfs_log_trace("realloc() failed.\n"); goto put_err_out; } al = aln; /* 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");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -