/** * ntfs_usnjrnl_stamp - stamp the transaction log ($UsnJrnl) on an ntfs volume * @vol: ntfs volume on which to stamp the transaction log * * Stamp the transaction log ($UsnJrnl) on the ntfs volume @vol and return 0 * on success and errno on error. * * This function assumes that the transaction log has already been loaded and * consistency checked by a call to ntfs_vfsops.c::ntfs_usnjrnl_load(). */ errno_t ntfs_usnjrnl_stamp(ntfs_volume *vol) { ntfs_debug("Entering."); if (!NVolUsnJrnlStamped(vol)) { sle64 j_size, stamp; upl_t upl; upl_page_info_array_t pl; USN_HEADER *uh; ntfs_inode *max_ni; errno_t err; mtx_lock_spin(&vol->usnjrnl_j_ni->size_lock); j_size = vol->usnjrnl_j_ni->data_size; mtx_unlock_spin(&vol->usnjrnl_j_ni->size_lock); max_ni = vol->usnjrnl_max_ni; /* * FIXME: Next If statement always false because of * replacing vnode_get() with vhold() */ vhold(max_ni->vn); if (0) { ntfs_error(vol->mp, "Failed to get vnode for " "$UsnJrnl/$DATA/$Max."); return err; } sx_slock(&max_ni->lock); err = ntfs_page_map(max_ni, 0, &upl, &pl, (u8**)&uh, TRUE); if (err) { ntfs_error(vol->mp, "Failed to read from " "$UsnJrnl/$DATA/$Max attribute."); vdrop(max_ni->vn); return err; } stamp = ntfs_current_time(); ntfs_debug("Stamping transaction log ($UsnJrnl): old " "journal_id 0x%llx, old lowest_valid_usn " "0x%llx, new journal_id 0x%llx, new " "lowest_valid_usn 0x%llx.", (unsigned long long) sle64_to_cpu(uh->journal_id), (unsigned long long) sle64_to_cpu(uh->lowest_valid_usn), (unsigned long long)sle64_to_cpu(stamp), (unsigned long long)j_size); uh->lowest_valid_usn = cpu_to_sle64(j_size); uh->journal_id = stamp; ntfs_page_unmap(max_ni, upl, pl, TRUE); sx_sunlock(&max_ni->lock); vdrop(max_ni->vn); /* Set the flag so we do not have to do it again on remount. */ NVolSetUsnJrnlStamped(vol); // TODO: Should we mark any times on the base inode $UsnJrnl // for update here? } ntfs_debug("Done."); return 0; }
/** * 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) { ntfs_time 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 = ntfs_current_time(); 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_feed_encrypt - Encrypt the contents of stdin to an encrypted file * @inode: An encrypted file's inode structure, as obtained by * ntfs_inode_open(). * @fek: A file encryption key. As obtained by ntfs_inode_fek_get(). */ static int ntfs_feed_encrypt(ntfs_inode *inode, ntfs_fek *fek) { const int bufsize = 512; unsigned char *buffer; ntfs_attr *attr; s64 bytes_read, written, offset, total; unsigned char *b; long val; int count; int i; buffer = (unsigned char*)malloc(bufsize); if (!buffer) return 1; attr = ntfs_attr_open(inode, AT_DATA, NULL, 0); if (!attr) { ntfs_log_error("Cannot feed into a directory.\n"); goto rejected; } total = 0; if (!(attr->data_flags & ATTR_IS_ENCRYPTED)) { ntfs_log_error("The data stream was not encrypted\n"); goto rejected; } inode->vol->efs_raw = TRUE; if (ntfs_attr_truncate(attr, 0)) { ntfs_log_error("Failed to truncate the data stream\n"); goto rejected; } offset = 0; do { bytes_read = fread(buffer, 1, bufsize, stdin); if (bytes_read <= 0) { if (bytes_read < 0) ntfs_log_perror("ERROR: Couldn't read data"); } else { if (bytes_read < bufsize) { /* Fill with random data */ srandom((unsigned int)(sle64_to_cpu( inode->last_data_change_time) /100000000)); count = bufsize - bytes_read; b = &buffer[bytes_read]; do { val = random(); switch (count) { default : *b++ = val; val >>= 8; case 3 : *b++ = val; val >>= 8; case 2 : *b++ = val; val >>= 8; case 1 : *b++ = val; val >>= 8; } count -= 4; } while (count > 0); } if ((i = ntfs_fek_encrypt_sector(fek, buffer, offset)) < bufsize) { ntfs_log_perror("ERROR: Couldn't encrypt all data!"); ntfs_log_error("%u/%lld/%lld/%lld\n", i, (long long)bytes_read, (long long)offset, (long long)total); break; } written = ntfs_attr_pwrite(attr, offset, bufsize, buffer); if (written != bufsize) { ntfs_log_perror("ERROR: Couldn't output all data!"); break; } offset += bufsize; total += bytes_read; } } while (bytes_read == bufsize); ntfs_attr_truncate(attr, total); inode->last_data_change_time = ntfs_current_time(); NAttrSetEncrypted(attr); ntfs_attr_close(attr); free(buffer); return 0; rejected : free(buffer); return (-1); }
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); }