/** * 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; set_nino_flag(ni, TimesDirty); NInoFileNameSetDirty(ni); NInoSetDirty(ni); }
/** * ntfs_inode_open - open an inode ready for access * @vol: volume to get the inode from * @mref: inode number / mft record number to open * * Allocate an ntfs_inode structure and initialize it for the given inode * specified by @mref. @mref specifies the inode number / mft record to read, * including the sequence number, which can be 0 if no sequence number checking * is to be performed. * * Then, allocate a buffer for the mft record, read the mft record from the * volume @vol, and attach it to the ntfs_inode structure (->mrec). The * mft record is mst deprotected and sanity checked for validity and we abort * if deprotection or checks fail. * * Finally, search for an attribute list attribute in the mft record and if one * is found, load the attribute list attribute value and attach it to the * ntfs_inode structure (->attr_list). Also set the NI_AttrList bit to indicate * this. * * Return a pointer to the ntfs_inode structure on success or NULL on error, * with errno set to the error code. */ ntfs_inode *ntfs_inode_open(ntfs_volume *vol, const MFT_REF mref) { s64 l; ntfs_inode *ni = NULL; ntfs_attr_search_ctx *ctx; STANDARD_INFORMATION *std_info; le32 lthle; int olderrno; ntfs_log_enter("Entering for inode %lld\n", (long long)MREF(mref)); if (!vol) { errno = EINVAL; goto out; } ni = __ntfs_inode_allocate(vol); if (!ni) goto out; if (ntfs_file_record_read(vol, mref, &ni->mrec, NULL)) goto err_out; if (!(ni->mrec->flags & MFT_RECORD_IN_USE)) { errno = ENOENT; goto err_out; } ni->mft_no = MREF(mref); ctx = ntfs_attr_get_search_ctx(ni, NULL); if (!ctx) goto err_out; /* Receive some basic information about inode. */ if (ntfs_attr_lookup(AT_STANDARD_INFORMATION, AT_UNNAMED, 0, CASE_SENSITIVE, 0, NULL, 0, ctx)) { if (!ni->mrec->base_mft_record) ntfs_log_perror("No STANDARD_INFORMATION in base record" " %lld", (long long)MREF(mref)); goto put_err_out; } std_info = (STANDARD_INFORMATION *)((u8 *)ctx->attr + le16_to_cpu(ctx->attr->value_offset)); ni->flags = std_info->file_attributes; ni->creation_time = ntfs2utc(std_info->creation_time); ni->last_data_change_time = ntfs2utc(std_info->last_data_change_time); ni->last_mft_change_time = ntfs2utc(std_info->last_mft_change_time); ni->last_access_time = ntfs2utc(std_info->last_access_time); /* JPA insert v3 extensions if present */ /* length may be seen as 72 (v1.x) or 96 (v3.x) */ lthle = ctx->attr->length; if (le32_to_cpu(lthle) > sizeof(STANDARD_INFORMATION)) { set_nino_flag(ni, v3_Extensions); ni->owner_id = std_info->owner_id; ni->security_id = std_info->security_id; ni->quota_charged = std_info->quota_charged; ni->usn = std_info->usn; } else { clear_nino_flag(ni, v3_Extensions); ni->owner_id = 0; ni->security_id = 0; } /* Set attribute list information. */ olderrno = errno; if (ntfs_attr_lookup(AT_ATTRIBUTE_LIST, AT_UNNAMED, 0, 0, 0, NULL, 0, ctx)) { if (errno != ENOENT) goto put_err_out; /* Attribute list attribute does not present. */ /* restore previous errno to avoid misinterpretation */ errno = olderrno; goto get_size; } NInoSetAttrList(ni); l = ntfs_get_attribute_value_length(ctx->attr); if (!l) goto put_err_out; if (l > 0x40000) { errno = EIO; ntfs_log_perror("Too large attrlist attribute (%lld), inode " "%lld", (long long)l, (long long)MREF(mref)); goto put_err_out; } ni->attr_list_size = l; ni->attr_list = ntfs_malloc(ni->attr_list_size); if (!ni->attr_list) goto put_err_out; l = ntfs_get_attribute_value(vol, ctx->attr, ni->attr_list); if (!l) goto put_err_out; if (l != ni->attr_list_size) { errno = EIO; ntfs_log_perror("Unexpected attrlist size (%lld <> %u), inode " "%lld", (long long)l, ni->attr_list_size, (long long)MREF(mref)); goto put_err_out; } get_size: olderrno = errno; if (ntfs_attr_lookup(AT_DATA, AT_UNNAMED, 0, 0, 0, NULL, 0, ctx)) { if (errno != ENOENT) goto put_err_out; /* Directory or special file. */ /* restore previous errno to avoid misinterpretation */ errno = olderrno; ni->data_size = ni->allocated_size = 0; } else { if (ctx->attr->non_resident) { ni->data_size = sle64_to_cpu(ctx->attr->data_size); if (ctx->attr->flags & (ATTR_IS_COMPRESSED | ATTR_IS_SPARSE)) ni->allocated_size = sle64_to_cpu( ctx->attr->compressed_size); else ni->allocated_size = sle64_to_cpu( ctx->attr->allocated_size); } else { ni->data_size = le32_to_cpu(ctx->attr->value_length); ni->allocated_size = (ni->data_size + 7) & ~7; } } ntfs_attr_put_search_ctx(ctx); out: ntfs_log_leave("\n"); return ni; put_err_out: ntfs_attr_put_search_ctx(ctx); err_out: __ntfs_inode_release(ni); ni = NULL; goto out; }
int ntfs_inode_set_times(ntfs_inode *ni, const char *value, size_t size, int flags) { ntfs_attr_search_ctx *ctx; STANDARD_INFORMATION *std_info; FILE_NAME_ATTR *fn; const u64 *times; ntfs_time now; int cnt; int ret; ret = -1; if ((size >= 8) && !(flags & XATTR_CREATE)) { times = (const u64*)value; now = ntfs_current_time(); /* update the standard information attribute */ ctx = ntfs_attr_get_search_ctx(ni, NULL); if (ctx) { if (ntfs_attr_lookup(AT_STANDARD_INFORMATION, AT_UNNAMED, 0, CASE_SENSITIVE, 0, NULL, 0, ctx)) { ntfs_log_perror("Failed to get standard info (inode %lld)", (long long)ni->mft_no); } else { std_info = (STANDARD_INFORMATION *)((u8 *)ctx->attr + le16_to_cpu(ctx->attr->value_offset)); /* * Mark times set to avoid overwriting * them when the inode is closed. * The inode structure must also be updated * (with loss of precision) because of cacheing. * TODO : use NTFS precision in inode, and * return sub-second times in getattr() */ set_nino_flag(ni, TimesSet); std_info->creation_time = cpu_to_le64(times[0]); ni->creation_time = std_info->creation_time; if (size >= 16) { std_info->last_data_change_time = cpu_to_le64(times[1]); ni->last_data_change_time = std_info->last_data_change_time; } if (size >= 24) { std_info->last_access_time = cpu_to_le64(times[2]); ni->last_access_time = std_info->last_access_time; } std_info->last_mft_change_time = now; ni->last_mft_change_time = now; ntfs_inode_mark_dirty(ctx->ntfs_ino); NInoFileNameSetDirty(ni); /* update the file names attributes */ ntfs_attr_reinit_search_ctx(ctx); cnt = 0; while (!ntfs_attr_lookup(AT_FILE_NAME, AT_UNNAMED, 0, CASE_SENSITIVE, 0, NULL, 0, ctx)) { fn = (FILE_NAME_ATTR*)((u8 *)ctx->attr + le16_to_cpu(ctx->attr->value_offset)); fn->creation_time = cpu_to_le64(times[0]); if (size >= 16) fn->last_data_change_time = cpu_to_le64(times[1]); if (size >= 24) fn->last_access_time = cpu_to_le64(times[2]); fn->last_mft_change_time = now; cnt++; } if (cnt) ret = 0; else { ntfs_log_perror("Failed to get file names (inode %lld)", (long long)ni->mft_no); } } ntfs_attr_put_search_ctx(ctx); } } else if (size < 8) errno = ERANGE; else errno = EEXIST; return (ret); }