Developed time stamping up to 100ns resolution

PERMISSION_HANDLING_BRANCH
jpandre 2010-01-04 08:24:44 +00:00
parent ee18659989
commit d78add4e8f
7 changed files with 142 additions and 65 deletions

View File

@ -313,7 +313,7 @@ AC_CHECK_FUNCS([ \
atexit basename daemon dup2 fdatasync ffs getopt_long hasmntopt \
mbsinit memmove memset realpath regcomp setlocale setxattr \
strcasecmp strchr strdup strerror strnlen strsep strtol strtoul \
sysconf utime utimensat fork \
sysconf utime utimensat gettimeofday clock_gettime fork \
])
AC_SYS_LARGEFILE

View File

@ -32,6 +32,7 @@ typedef struct _ntfs_inode ntfs_inode;
#include "layout.h"
#include "support.h"
#include "volume.h"
#include "ntfstime.h"
/**
* enum ntfs_inode_state_bits -
@ -153,10 +154,10 @@ struct _ntfs_inode {
* STANDARD_INFORMATION attribute and used to sync it and FILE_NAME
* attribute in the index.
*/
time_t creation_time;
time_t last_data_change_time;
time_t last_mft_change_time;
time_t last_access_time;
ntfs_time creation_time;
ntfs_time last_data_change_time;
ntfs_time last_mft_change_time;
ntfs_time last_access_time;
/* NTFS 3.x extensions added by JPA */
/* only if NI_v3_Extensions is set in state */
le32 owner_id;

View File

@ -3,6 +3,7 @@
*
* Copyright (c) 2005 Anton Altaparmakov
* Copyright (c) 2005 Yura Pakhuchiy
* Copyright (c) 2010 Jean-Pierre Andre
*
* This program/include file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published
@ -26,44 +27,105 @@
#ifdef HAVE_TIME_H
#include <time.h>
#endif
#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#ifdef HAVE_GETTIMEOFDAY
#include <sys/time.h>
#endif
#include "types.h"
/*
* assume "struct timespec" is not defined if st_mtime is not defined
*/
#ifndef st_mtime
struct timespec {
time_t tv_sec;
long tv_nsec;
} ;
#endif
/*
* There are four times more conversions of internal representation
* to ntfs representation than any other conversion, so the most
* efficient internal representation is ntfs representation
* (with low endianness)
*/
typedef sle64 ntfs_time;
#define NTFS_TIME_OFFSET ((s64)(369 * 365 + 89) * 24 * 3600 * 10000000)
/**
* ntfs2utc - Convert an NTFS time to Unix time
* ntfs2timespec - Convert an NTFS time to Unix time
* @ntfs_time: An NTFS time in 100ns units since 1601
*
* NTFS stores times as the number of 100ns intervals since January 1st 1601 at
* 00:00 UTC. This system will not suffer from Y2K problems until ~57000AD.
*
* Return: n A Unix time (number of seconds since 1970)
* Return: A Unix time (number of seconds since 1970, and nanoseconds)
*/
static __inline__ time_t ntfs2utc(s64 ntfs_time)
static __inline__ struct timespec ntfs2timespec(ntfs_time ntfstime)
{
return (sle64_to_cpu(ntfs_time) - (NTFS_TIME_OFFSET)) / 10000000;
struct timespec spec;
s64 cputime;
cputime = sle64_to_cpu(ntfstime);
spec.tv_sec = (cputime - (NTFS_TIME_OFFSET)) / 10000000;
spec.tv_nsec = (cputime - (NTFS_TIME_OFFSET)
- (s64)spec.tv_sec*10000000)*100;
/* force zero nsec for overflowing dates */
if ((spec.tv_nsec < 0) || (spec.tv_nsec > 999999999))
spec.tv_nsec = 0;
return (spec);
}
/**
* utc2ntfs - Convert Linux time to NTFS time
* timespec2ntfs - Convert Linux time to NTFS time
* @utc_time: Linux time to convert to NTFS
*
* Convert the Linux time @utc_time to its corresponding NTFS time.
*
* Linux stores time in a long at present and measures it as the number of
* 1-second intervals since 1st January 1970, 00:00:00 UTC.
* 1-second intervals since 1st January 1970, 00:00:00 UTC
* with a separated non-negative nanosecond value
*
* NTFS uses Microsoft's standard time format which is stored in a s64 and is
* NTFS uses Microsoft's standard time format which is stored in a sle64 and is
* measured as the number of 100 nano-second intervals since 1st January 1601,
* 00:00:00 UTC.
*
* Return: n An NTFS time (100ns units since Jan 1601)
* Return: An NTFS time (100ns units since Jan 1601)
*/
static __inline__ s64 utc2ntfs(time_t utc_time)
static __inline__ ntfs_time timespec2ntfs(struct timespec spec)
{
/* Convert to 100ns intervals and then add the NTFS time offset. */
return cpu_to_sle64((s64)utc_time * 10000000 + NTFS_TIME_OFFSET);
s64 units;
units = (s64)spec.tv_sec * 10000000
+ NTFS_TIME_OFFSET + spec.tv_nsec/100;
return (cpu_to_le64(units));
}
/*
* Return the current time in ntfs format
*/
static __inline__ ntfs_time ntfs_current_time(void)
{
struct timespec now;
#if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_SYS_CLOCK_GETTIME)
clock_gettime(CLOCK_REALTIME, &now);
#elif defined(HAVE_GETTIMEOFDAY)
struct timeval microseconds;
gettimeofday(&microseconds, (struct timezone*)NULL);
now.tv_sec = microseconds.tv_sec;
now.tv_nsec = microseconds.tv_usec*1000;
#else
now.tv_sec = time((time_t*)NULL);
now.tv_nsec = 0;
#endif
return (timespec2ntfs(now));
}
#endif /* _NTFS_NTFSTIME_H */

View File

@ -5,7 +5,7 @@
* Copyright (c) 2004-2005 Richard Russon
* Copyright (c) 2004-2008 Szabolcs Szakacsits
* Copyright (c) 2005-2007 Yura Pakhuchiy
* Copyright (c) 2008-2009 Jean-Pierre Andre
* Copyright (c) 2008-2010 Jean-Pierre Andre
*
* This program/include file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published
@ -1380,10 +1380,10 @@ static ntfs_inode *__ntfs_create(ntfs_inode *dir_ni, le32 securid,
err = errno;
goto err_out;
}
si->creation_time = utc2ntfs(ni->creation_time);
si->last_data_change_time = utc2ntfs(ni->last_data_change_time);
si->last_mft_change_time = utc2ntfs(ni->last_mft_change_time);
si->last_access_time = utc2ntfs(ni->last_access_time);
si->creation_time = ni->creation_time;
si->last_data_change_time = ni->last_data_change_time;
si->last_mft_change_time = ni->last_mft_change_time;
si->last_access_time = ni->last_access_time;
if (securid) {
set_nino_flag(ni, v3_Extensions);
ni->owner_id = si->owner_id = 0;
@ -1525,10 +1525,10 @@ static ntfs_inode *__ntfs_create(ntfs_inode *dir_ni, le32 securid,
fn->file_attributes = FILE_ATTR_SYSTEM;
else
fn->file_attributes |= ni->flags & FILE_ATTR_COMPRESSED;
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);
fn->creation_time = ni->creation_time;
fn->last_data_change_time = ni->last_data_change_time;
fn->last_mft_change_time = ni->last_mft_change_time;
fn->last_access_time = ni->last_access_time;
if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)
fn->data_size = fn->allocated_size = const_cpu_to_le64(0);
else {
@ -2007,10 +2007,10 @@ static int ntfs_link_i(ntfs_inode *ni, ntfs_inode *dir_ni, ntfschar *name,
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);
fn->creation_time = ni->creation_time;
fn->last_data_change_time = ni->last_data_change_time;
fn->last_mft_change_time = ni->last_mft_change_time;
fn->last_access_time = ni->last_access_time;
memcpy(fn->file_name, name, name_len * sizeof(ntfschar));
/* Add FILE_NAME attribute to index. */
if (ntfs_index_add_filename(dir_ni, fn, MK_MREF(ni->mft_no,

View File

@ -5,7 +5,7 @@
* Copyright (c) 2002-2008 Szabolcs Szakacsits
* Copyright (c) 2004-2007 Yura Pakhuchiy
* Copyright (c) 2004-2005 Richard Russon
* Copyright (c) 2009 Jean-Pierre Andre
* Copyright (c) 2009-2010 Jean-Pierre Andre
*
* This program/include file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published
@ -194,10 +194,10 @@ static ntfs_inode *ntfs_inode_real_open(ntfs_volume *vol, const MFT_REF mref)
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);
ni->creation_time = std_info->creation_time;
ni->last_data_change_time = std_info->last_data_change_time;
ni->last_mft_change_time = std_info->last_mft_change_time;
ni->last_access_time = 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;
@ -718,10 +718,10 @@ static int ntfs_inode_sync_standard_information(ntfs_inode *ni)
le16_to_cpu(ctx->attr->value_offset));
std_info->file_attributes = ni->flags;
if (!test_nino_flag(ni, TimesSet)) {
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);
std_info->creation_time = ni->creation_time;
std_info->last_data_change_time = ni->last_data_change_time;
std_info->last_mft_change_time = ni->last_mft_change_time;
std_info->last_access_time = ni->last_access_time;
}
/* JPA update v3.x extensions, ensuring consistency */
@ -831,10 +831,10 @@ static int ntfs_inode_sync_file_name(ntfs_inode *ni, ntfs_inode *dir_ni)
fnx->data_size = cpu_to_sle64(ni->data_size);
}
if (!test_nino_flag(ni, TimesSet)) {
fnx->creation_time = utc2ntfs(ni->creation_time);
fnx->last_data_change_time = utc2ntfs(ni->last_data_change_time);
fnx->last_mft_change_time = utc2ntfs(ni->last_mft_change_time);
fnx->last_access_time = utc2ntfs(ni->last_access_time);
fnx->creation_time = ni->creation_time;
fnx->last_data_change_time = ni->last_data_change_time;
fnx->last_mft_change_time = ni->last_mft_change_time;
fnx->last_access_time = ni->last_access_time;
} else {
fnx->creation_time = fn->creation_time;
fnx->last_data_change_time = fn->last_data_change_time;
@ -1322,7 +1322,7 @@ put_err_out:
*/
void ntfs_inode_update_times(ntfs_inode *ni, ntfs_time_update_flags mask)
{
time_t now;
ntfs_time now;
if (!ni) {
ntfs_log_error("%s(): Invalid arguments.\n", __FUNCTION__);
@ -1333,7 +1333,7 @@ void ntfs_inode_update_times(ntfs_inode *ni, ntfs_time_update_flags mask)
NVolReadOnly(ni->vol) || !mask)
return;
now = time(NULL);
now = ntfs_current_time();
if (mask & NTFS_UPDATE_ATIME)
ni->last_access_time = now;
if (mask & NTFS_UPDATE_MTIME)
@ -1466,14 +1466,14 @@ int ntfs_inode_set_times(ntfs_inode *ni, const char *value, size_t size,
STANDARD_INFORMATION *std_info;
FILE_NAME_ATTR *fn;
const u64 *times;
le64 now;
ntfs_time now;
int cnt;
int ret;
ret = -1;
if ((size >= 8) && !(flags & XATTR_CREATE)) {
times = (const u64*)value;
now = utc2ntfs(time((time_t*)NULL));
now = ntfs_current_time();
/* update the standard information attribute */
ctx = ntfs_attr_get_search_ctx(ni, NULL);
if (ctx) {
@ -1496,19 +1496,19 @@ int ntfs_inode_set_times(ntfs_inode *ni, const char *value, size_t size,
set_nino_flag(ni, TimesSet);
std_info->creation_time = cpu_to_le64(times[0]);
ni->creation_time
= ntfs2utc(std_info->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
= ntfs2utc(std_info->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
= ntfs2utc(std_info->last_access_time);
= std_info->last_access_time;
}
std_info->last_mft_change_time = now;
ni->last_mft_change_time = ntfs2utc(now);
ni->last_mft_change_time = now;
ntfs_inode_mark_dirty(ctx->ntfs_ino);
NInoFileNameSetDirty(ni);

View File

@ -1478,7 +1478,7 @@ found_free_rec:
ni->flags = 0;
ni->creation_time = ni->last_data_change_time =
ni->last_mft_change_time =
ni->last_access_time = time(NULL);
ni->last_access_time = ntfs_current_time();
/* Update the default mft allocation position if it was used. */
if (!base_ni)
vol->mft_data_pos = bit + 1;
@ -1780,7 +1780,7 @@ found_free_rec:
ni->flags = 0;
ni->creation_time = ni->last_data_change_time =
ni->last_mft_change_time =
ni->last_access_time = time(NULL);
ni->last_access_time = ntfs_current_time();
/* Update the default mft allocation position if it was used. */
if (!base_ni)
vol->mft_data_pos = bit + 1;

View File

@ -4,7 +4,7 @@
* Copyright (c) 2005-2007 Yura Pakhuchiy
* Copyright (c) 2005 Yuval Fledel
* Copyright (c) 2006-2009 Szabolcs Szakacsits
* Copyright (c) 2007-2009 Jean-Pierre Andre
* Copyright (c) 2007-2010 Jean-Pierre Andre
* Copyright (c) 2009 Erik Larsson
*
* This file is originated from the Linux-NTFS project.
@ -217,7 +217,7 @@ static const char *usage_msg =
"\n"
"Copyright (C) 2005-2007 Yura Pakhuchiy\n"
"Copyright (C) 2006-2009 Szabolcs Szakacsits\n"
"Copyright (C) 2007-2009 Jean-Pierre Andre\n"
"Copyright (C) 2007-2010 Jean-Pierre Andre\n"
"Copyright (C) 2009 Erik Larsson\n"
"\n"
"Usage: %s [-o option[,...]] <device|image_file> <mount_point>\n"
@ -275,8 +275,10 @@ static void ntfs_fuse_update_times(ntfs_inode *ni, ntfs_time_update_flags mask)
if (ctx->atime == ATIME_DISABLED)
mask &= ~NTFS_UPDATE_ATIME;
else if (ctx->atime == ATIME_RELATIVE && mask == NTFS_UPDATE_ATIME &&
ni->last_access_time >= ni->last_data_change_time &&
ni->last_access_time >= ni->last_mft_change_time)
(le64_to_cpu(ni->last_access_time)
>= le64_to_cpu(ni->last_data_change_time)) &&
(le64_to_cpu(ni->last_access_time)
>= le64_to_cpu(ni->last_mft_change_time)))
return;
ntfs_inode_update_times(ni, mask);
}
@ -860,9 +862,9 @@ static int ntfs_fuse_getattr(const char *org_path, struct stat *stbuf)
if (S_ISLNK(stbuf->st_mode))
stbuf->st_mode |= 0777;
stbuf->st_ino = ni->mft_no;
stbuf->st_atime = ni->last_access_time;
stbuf->st_ctime = ni->last_mft_change_time;
stbuf->st_mtime = ni->last_data_change_time;
stbuf->st_atim = ntfs2timespec(ni->last_access_time);
stbuf->st_ctim = ntfs2timespec(ni->last_mft_change_time);
stbuf->st_mtim = ntfs2timespec(ni->last_data_change_time);
exit:
if (ntfs_inode_close(ni))
set_fuse_error(&res);
@ -2223,12 +2225,14 @@ static int ntfs_fuse_utimens(const char *path, const struct timespec tv[2])
mask |= NTFS_UPDATE_ATIME;
else
if (tv[0].tv_nsec != UTIME_OMIT)
ni->last_access_time = tv[0].tv_sec;
ni->last_access_time
= timespec2ntfs(tv[0]);
if (tv[1].tv_nsec == UTIME_NOW)
mask |= NTFS_UPDATE_MTIME;
else
if (tv[1].tv_nsec != UTIME_OMIT)
ni->last_data_change_time = tv[1].tv_sec;
ni->last_data_change_time
= timespec2ntfs(tv[1]);
ntfs_inode_update_times(ni, mask);
#if !KERNELPERMS | (POSIXACLS & !KERNELACLS)
} else
@ -2246,6 +2250,8 @@ static int ntfs_fuse_utime(const char *path, struct utimbuf *buf)
{
ntfs_inode *ni;
int res = 0;
struct timespec actime;
struct timespec modtime;
#if !KERNELPERMS | (POSIXACLS & !KERNELACLS)
BOOL ownerok;
BOOL writeok;
@ -2282,8 +2288,12 @@ static int ntfs_fuse_utime(const char *path, struct utimbuf *buf)
if (!ownerok && !writeok)
res = (buf->actime == buf->modtime ? -EACCES : -EPERM);
else {
ni->last_access_time = buf->actime;
ni->last_data_change_time = buf->modtime;
actime.tv_sec = buf->actime;
actime.tv_nsec = 0;
modtime.tv_sec = buf->modtime;
modtime.tv_nsec = 0;
ni->last_access_time = timespec2ntfs(actime);
ni->last_data_change_time = timespec2ntfs(modtime);
ntfs_fuse_update_times(ni, NTFS_UPDATE_CTIME);
}
} else {
@ -2297,8 +2307,12 @@ static int ntfs_fuse_utime(const char *path, struct utimbuf *buf)
}
#else
if (buf) {
ni->last_access_time = buf->actime;
ni->last_data_change_time = buf->modtime;
actime.tv_sec = buf->actime;
actime.tv_nsec = 0;
modtime.tv_sec = buf->modtime;
modtime.tv_nsec = 0;
ni->last_access_time = timespec2ntfs(actime);
ni->last_data_change_time = timespec2ntfs(modtime);
ntfs_fuse_update_times(ni, NTFS_UPDATE_CTIME);
} else
ntfs_inode_update_times(ni, NTFS_UPDATE_AMCTIME);