Developped getting and setting NTFS times

N2009_11_14_FIXES
jpandre 2009-07-09 15:20:14 +00:00
parent 78285e42b4
commit 5e650c0c91
4 changed files with 197 additions and 10 deletions

View File

@ -49,6 +49,7 @@ typedef enum {
NI_FileNameDirty, /* 1: FILE_NAME attributes need to be updated
in the index. */
NI_v3_Extensions, /* 1: JPA v3.x extensions present. */
NI_TimesDirty, /* 1: Times need to be updated */
} ntfs_inode_state_bits;
#define test_nino_flag(ni, flag) test_bit(NI_##flag, (ni)->state)
@ -194,4 +195,9 @@ extern int ntfs_inode_free_space(ntfs_inode *ni, int size);
extern int ntfs_inode_badclus_bad(u64 mft_no, ATTR_RECORD *a);
extern int ntfs_inode_get_times(const char *path, char *value,
size_t size, ntfs_inode *ni);
extern int ntfs_inode_set_times(const char *path, const char *value,
size_t size, int flags, ntfs_inode *ni);
#endif /* defined _NTFS_INODE_H */

View File

@ -35,6 +35,9 @@
#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif
#ifdef HAVE_SETXATTR
#include <sys/xattr.h>
#endif
#include "compat.h"
#include "types.h"
@ -554,10 +557,12 @@ static int ntfs_inode_sync_standard_information(ntfs_inode *ni)
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);
if (test_nino_flag(ni, TimesDirty)) {
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);
}
/* JPA update v3.x extensions, ensuring consistency */
@ -655,10 +660,12 @@ static int ntfs_inode_sync_file_name(ntfs_inode *ni)
(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);
if (test_nino_flag(ni, TimesDirty)) {
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) && !err)
@ -1137,6 +1144,7 @@ void ntfs_inode_update_times(ntfs_inode *ni, ntfs_time_update_flags mask)
if (mask & NTFS_UPDATE_CTIME)
ni->last_mft_change_time = now;
set_nino_flag(ni, TimesDirty);
NInoFileNameSetDirty(ni);
NInoSetDirty(ni);
}
@ -1184,3 +1192,151 @@ int ntfs_inode_badclus_bad(u64 mft_no, ATTR_RECORD *attr)
return ret;
}
/*
* Get high precision NTFS times
*
* They are returned in following order : create, update, access, change
* provided they fit in requested size.
*
* Returns the modified size if successfull (or 32 if buffer size is null)
* -errno if failed
*/
int ntfs_inode_get_times(const char *path __attribute__((unused)),
char *value, size_t size, ntfs_inode *ni)
{
ntfs_attr_search_ctx *ctx;
STANDARD_INFORMATION *std_info;
u64 *times;
int ret;
ret = 0;
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));
if (value && (size >= 8)) {
times = (u64*)value;
times[0] = le64_to_cpu(std_info->creation_time);
ret = 8;
if (size >= 16) {
times[1] = le64_to_cpu(std_info->last_data_change_time);
ret = 16;
}
if (size >= 24) {
times[2] = le64_to_cpu(std_info->last_access_time);
ret = 24;
}
if (size >= 32) {
times[3] = le64_to_cpu(std_info->last_mft_change_time);
ret = 32;
}
} else
if (!size)
ret = 32;
else
ret = -ERANGE;
}
ntfs_attr_put_search_ctx(ctx);
}
return (ret ? ret : -errno);
}
/*
* Set high precision NTFS times
*
* They are expected in this order : create, update, access
* provided they are present in input. The change time is set to
* current time.
*
* The times are inserted directly in the standard_information and
* file names attributes to avoid manipulating low precision times
*
* Returns 0 if success
* -1 if there were an error (described by errno)
*/
int ntfs_inode_set_times(const char *path __attribute__((unused)),
const char *value, size_t size,
int flags, ntfs_inode *ni)
{
ntfs_attr_search_ctx *ctx;
STANDARD_INFORMATION *std_info;
FILE_NAME_ATTR *fn;
const u64 *times;
le64 now;
int cnt;
int ret;
ret = -1;
if ((size >= 8) && !(flags & XATTR_CREATE)) {
times = (const u64*)value;
now = utc2ntfs(time((time_t*)NULL));
/* 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));
/*
* Do not mark times dirty to avoid
* overwriting them when the inode is closed.
*/
std_info->creation_time = cpu_to_le64(times[0]);
if (size >= 16)
std_info->last_data_change_time = cpu_to_le64(times[1]);
if (size >= 24)
std_info->last_access_time = cpu_to_le64(times[2]);
std_info->last_mft_change_time = now;
ntfs_inode_mark_dirty(ctx->ntfs_ino);
/* 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));
/*
* Do not mark times dirty to avoid
* overwriting them when the inode is closed.
*/
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);
}

View File

@ -1476,6 +1476,7 @@ found_free_rec:
ni->creation_time = ni->last_data_change_time =
ni->last_mft_change_time =
ni->last_access_time = time(NULL);
set_nino_flag(ni, TimesDirty);
/* Update the default mft allocation position if it was used. */
if (!base_ni)
vol->mft_data_pos = bit + 1;
@ -1778,6 +1779,7 @@ found_free_rec:
ni->creation_time = ni->last_data_change_time =
ni->last_mft_change_time =
ni->last_access_time = time(NULL);
set_nino_flag(ni, TimesDirty);
/* Update the default mft allocation position if it was used. */
if (!base_ni)
vol->mft_data_pos = bit + 1;

View File

@ -2014,6 +2014,7 @@ enum { XATTR_UNMAPPED,
XATTR_NTFS_EFSINFO,
XATTR_NTFS_REPARSE_DATA,
XATTR_NTFS_DOS_NAME,
XATTR_NTFS_TIMES,
XATTR_POSIX_ACC,
XATTR_POSIX_DEF } ;
@ -2022,6 +2023,7 @@ static const char nf_ns_xattr_attrib[] = "system.ntfs_attrib";
static const char nf_ns_xattr_efsinfo[] = "user.ntfs.efsinfo";
static const char nf_ns_xattr_reparse[] = "system.ntfs_reparse_data";
static const char nf_ns_xattr_dos_name[] = "system.ntfs_dos_name";
static const char nf_ns_xattr_times[] = "system.ntfs_times";
static const char nf_ns_xattr_posix_access[] = "system.posix_acl_access";
static const char nf_ns_xattr_posix_default[] = "system.posix_acl_default";
@ -2036,6 +2038,7 @@ static struct XATTRNAME nf_ns_xattr_names[] = {
{ XATTR_NTFS_EFSINFO, nf_ns_xattr_efsinfo },
{ XATTR_NTFS_REPARSE_DATA, nf_ns_xattr_reparse },
{ XATTR_NTFS_DOS_NAME, nf_ns_xattr_dos_name },
{ XATTR_NTFS_TIMES, nf_ns_xattr_times },
{ XATTR_POSIX_ACC, nf_ns_xattr_posix_access },
{ XATTR_POSIX_DEF, nf_ns_xattr_posix_default },
{ XATTR_UNMAPPED, (char*)NULL } /* terminator */
@ -2422,6 +2425,10 @@ static int ntfs_fuse_getxattr(const char *path, const char *name,
res = ntfs_get_ntfs_dos_name(path,
value,size,ni);
break;
case XATTR_NTFS_TIMES:
res = ntfs_inode_get_times(path,
value,size,ni);
break;
default : /* not possible */
break;
}
@ -2472,6 +2479,10 @@ static int ntfs_fuse_getxattr(const char *path, const char *name,
res = ntfs_get_ntfs_dos_name(path,
value,size,ni);
break;
case XATTR_NTFS_TIMES:
res = ntfs_inode_get_times(path,
value,size,ni);
break;
default :
/*
* make sure applications do not see
@ -2601,6 +2612,10 @@ static int ntfs_fuse_setxattr(const char *path, const char *name,
res = ntfs_set_ntfs_dos_name(path,
value,size,flags,ni);
break;
case XATTR_NTFS_TIMES:
res = ntfs_inode_set_times(path,
value,size,flags,ni);
break;
default : /* not possible */
break;
}
@ -2656,6 +2671,10 @@ static int ntfs_fuse_setxattr(const char *path, const char *name,
res = ntfs_set_ntfs_dos_name(path,
value,size,flags,ni);
break;
case XATTR_NTFS_TIMES:
res = ntfs_inode_set_times(path,
value,size,flags,ni);
break;
default :
/*
* make sure applications do not see
@ -2805,11 +2824,13 @@ static int ntfs_fuse_removexattr(const char *path, const char *name)
res = 0;
switch (attr) {
/*
* Removal of NTFS ACL or ATTRIB is never allowed
* Removal of NTFS ACL, ATTRIB, EFSINFO or TIMES
* is never allowed
*/
case XATTR_NTFS_ACL :
case XATTR_NTFS_ATTRIB :
case XATTR_NTFS_EFSINFO :
case XATTR_NTFS_TIMES :
res = -EPERM;
break;
case XATTR_POSIX_ACC :
@ -2854,11 +2875,13 @@ static int ntfs_fuse_removexattr(const char *path, const char *name)
else {
switch (attr) {
/*
* Removal of NTFS ACL or ATTRIB is never allowed
* Removal of NTFS ACL, ATTRIB, EFSINFO or TIMES
* is never allowed
*/
case XATTR_NTFS_ACL :
case XATTR_NTFS_ATTRIB :
case XATTR_NTFS_EFSINFO :
case XATTR_NTFS_TIMES :
res = -EPERM;
break;
case XATTR_NTFS_REPARSE_DATA :