Developped getting and setting NTFS times
parent
78285e42b4
commit
5e650c0c91
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 :
|
||||
|
|
Loading…
Reference in New Issue