From: Eric Biggers Date: Mon, 18 Mar 2013 02:42:20 +0000 (-0500) Subject: Update timestamp code; use utimensat() X-Git-Tag: v1.3.0~13 X-Git-Url: https://wimlib.net/git/?p=wimlib;a=commitdiff_plain;h=7acdc3aecd7ce546727ae8239e0d942c2a00db43;hp=4498586932ab670cf4791d8cf991d9b3e0ce1545 Update timestamp code; use utimensat() --- diff --git a/doc/imagex-apply.1.in b/doc/imagex-apply.1.in index 86b47f3d..59114271 100644 --- a/doc/imagex-apply.1.in +++ b/doc/imagex-apply.1.in @@ -48,7 +48,8 @@ The default (unnamed) data stream of each file Hard links .IP \[bu] File and directory creation, access, and modification timestamps to the nearest -microsecond, if supported by the underlying filesystem +100 nanoseconds, if supported by the underlying filesystem, operating system, +and C library .IP \[bu] Symbolic links and junction points, although they will not necessarily point to the desired location (for example, the target of the link may contain a Windows diff --git a/src/add_image.c b/src/add_image.c index 7c974992..67a354e4 100644 --- a/src/add_image.c +++ b/src/add_image.c @@ -44,7 +44,7 @@ #include #ifdef HAVE_ALLOCA_H -#include +# include #endif /* @@ -226,9 +226,9 @@ static int unix_build_dentry_tree(struct wim_dentry **root_ret, inode = root->d_inode; #ifdef HAVE_STAT_NANOSECOND_PRECISION - inode->i_creation_time = timespec_to_wim_timestamp(&root_stbuf.st_mtim); - inode->i_last_write_time = timespec_to_wim_timestamp(&root_stbuf.st_mtim); - inode->i_last_access_time = timespec_to_wim_timestamp(&root_stbuf.st_atim); + inode->i_creation_time = timespec_to_wim_timestamp(root_stbuf.st_mtim); + inode->i_last_write_time = timespec_to_wim_timestamp(root_stbuf.st_mtim); + inode->i_last_access_time = timespec_to_wim_timestamp(root_stbuf.st_atim); #else inode->i_creation_time = unix_timestamp_to_wim(root_stbuf.st_mtime); inode->i_last_write_time = unix_timestamp_to_wim(root_stbuf.st_mtime); diff --git a/src/extract_image.c b/src/extract_image.c index dece5437..19b87d4d 100644 --- a/src/extract_image.c +++ b/src/extract_image.c @@ -399,32 +399,53 @@ static int unix_do_apply_dentry_timestamps(const char *output_path, int ret; const struct wim_inode *inode = dentry->d_inode; +#ifdef HAVE_UTIMENSAT /* Convert the WIM timestamps, which are accurate to 100 nanoseconds, - * into struct timeval's. */ - struct timeval tv[2]; - wim_timestamp_to_timeval(inode->i_last_access_time, &tv[0]); - wim_timestamp_to_timeval(inode->i_last_write_time, &tv[1]); + * into `struct timespec's for passing to utimensat(), which is accurate + * to 1 nanosecond. */ + + struct timespec ts[2]; + ts[0] = wim_timestamp_to_timespec(inode->i_last_access_time); + ts[1] = wim_timestamp_to_timespec(inode->i_last_write_time); + ret = utimensat(AT_FDCWD, output_path, ts, AT_SYMLINK_NOFOLLOW); + if (ret) + ret = errno; +#else + ret = ENOSYS; +#endif + + if (ret == ENOSYS) { + /* utimensat() not implemented or not available */ #ifdef HAVE_LUTIMES - ret = lutimes(output_path, tv); - #else - ret = -1; - errno = ENOSYS; + /* Convert the WIM timestamps, which are accurate to 100 + * nanoseconds, into `struct timeval's for passing to lutimes(), + * which is accurate to 1 microsecond. */ + struct timeval tv[2]; + tv[0] = wim_timestamp_to_timeval(inode->i_last_access_time); + tv[1] = wim_timestamp_to_timeval(inode->i_last_write_time); + ret = lutimes(output_path, tv); + if (ret) + ret = errno; #endif - if (ret != 0) { - #ifdef HAVE_UTIME - if (errno == ENOSYS) { - struct utimbuf buf; - buf.actime = wim_timestamp_to_unix(inode->i_last_access_time); - buf.modtime = wim_timestamp_to_unix(inode->i_last_write_time); - if (utime(output_path, &buf) == 0) - return 0; - } - #endif - if (errno != ENOSYS || args->num_lutimes_warnings < 10) { - /*WARNING_WITH_ERRNO("Failed to set timestamp on file `%s',*/ - /*output_path");*/ - args->num_lutimes_warnings++; - } + } + + if (ret == ENOSYS) { + /* utimensat() and lutimes() both not implemented or not + * available */ + #ifdef HAVE_UTIME + /* Convert the WIM timestamps, which are accurate to 100 + * nanoseconds, into a `struct utimbuf's for passing to + * utime(), which is accurate to 1 second. */ + struct utimbuf buf; + buf.actime = wim_timestamp_to_unix(inode->i_last_access_time); + buf.modtime = wim_timestamp_to_unix(inode->i_last_write_time); + ret = utime(output_path, &buf); + #endif + } + if (ret && args->num_utime_warnings < 10) { + WARNING_WITH_ERRNO("Failed to set timestamp on file `%s'", + output_path); + args->num_utime_warnings++; } return 0; } @@ -728,12 +749,12 @@ static int extract_single_image(WIMStruct *w, int image, struct apply_args args; const struct apply_operations *ops; - args.w = w; - args.target = target; - args.extract_flags = extract_flags; - args.num_lutimes_warnings = 0; - args.stream_list = &stream_list; - args.progress_func = progress_func; + args.w = w; + args.target = target; + args.extract_flags = extract_flags; + args.num_utime_warnings = 0; + args.stream_list = &stream_list; + args.progress_func = progress_func; if (progress_func) { args.progress.extract.wimfile_name = w->filename; diff --git a/src/mount_image.c b/src/mount_image.c index afb09050..d9688765 100644 --- a/src/mount_image.c +++ b/src/mount_image.c @@ -420,13 +420,26 @@ static int inode_to_stbuf(const struct wim_inode *inode, stbuf->st_size = 0; } +#ifdef HAVE_STAT_NANOSECOND_PRECISION + stbuf->st_atim = wim_timestamp_to_timespec(inode->i_last_access_time); + stbuf->st_mtim = wim_timestamp_to_timespec(inode->i_last_write_time); + stbuf->st_ctim = stbuf->st_mtim; +#else stbuf->st_atime = wim_timestamp_to_unix(inode->i_last_access_time); stbuf->st_mtime = wim_timestamp_to_unix(inode->i_last_write_time); - stbuf->st_ctime = wim_timestamp_to_unix(inode->i_creation_time); + stbuf->st_ctime = stbuf->st_mtime; +#endif stbuf->st_blocks = (stbuf->st_size + 511) / 512; return 0; } +static void touch_inode(struct wim_inode *inode) +{ + u64 now = get_wim_timestamp(); + inode->i_last_access_time = now; + inode->i_last_write_time = now; +} + /* Creates a new staging file and returns its file descriptor opened for * writing. * @@ -2241,13 +2254,13 @@ static int wimfs_utimens(const char *path, const struct timespec tv[2]) if (tv[0].tv_nsec == UTIME_NOW) inode->i_last_access_time = get_wim_timestamp(); else - inode->i_last_access_time = timespec_to_wim_timestamp(&tv[0]); + inode->i_last_access_time = timespec_to_wim_timestamp(tv[0]); } if (tv[1].tv_nsec != UTIME_OMIT) { if (tv[1].tv_nsec == UTIME_NOW) inode->i_last_write_time = get_wim_timestamp(); else - inode->i_last_write_time = timespec_to_wim_timestamp(&tv[1]); + inode->i_last_write_time = timespec_to_wim_timestamp(tv[1]); } return 0; } @@ -2296,9 +2309,8 @@ static int wimfs_write(const char *path, const char *buf, size_t size, if (ret == -1) return -errno; - now = get_wim_timestamp(); - fd->f_inode->i_last_write_time = now; - fd->f_inode->i_last_access_time = now; + /* Update timestamps */ + touch_inode(fd->f_inode); return ret; } diff --git a/src/timestamp.h b/src/timestamp.h index 406f6a5d..4dcc429b 100644 --- a/src/timestamp.h +++ b/src/timestamp.h @@ -18,41 +18,60 @@ #define intervals_1601_to_1970 (years_1601_to_1970 * intervals_per_year \ + leap_years_1601_to_1970 * intervals_per_day) -static inline u64 unix_timestamp_to_wim(time_t t) +static inline u64 +unix_timestamp_to_wim(time_t t) { return (u64)intervals_1601_to_1970 + t * intervals_per_second; } - /* Converts a timestamp as used in the WIM file to a UNIX timestamp as used in * the time() function. */ -static inline time_t wim_timestamp_to_unix(u64 timestamp) +static inline time_t +wim_timestamp_to_unix(u64 timestamp) { return (timestamp - intervals_1601_to_1970) / intervals_per_second; } -static inline u64 timeval_to_wim_timestamp(const struct timeval *tv) +static inline u64 +timeval_to_wim_timestamp(const struct timeval tv) { return intervals_1601_to_1970 - + (u64)tv->tv_sec * intervals_per_second - + (u64)tv->tv_usec * intervals_per_microsecond; + + (u64)tv.tv_sec * intervals_per_second + + (u64)tv.tv_usec * intervals_per_microsecond; } -static inline void wim_timestamp_to_timeval(u64 timestamp, struct timeval *tv) +static inline struct timeval +wim_timestamp_to_timeval(u64 timestamp) { - tv->tv_sec = (timestamp - intervals_1601_to_1970) / intervals_per_second; - tv->tv_usec = ((timestamp - intervals_1601_to_1970) / + struct timeval tv; + tv.tv_sec = (timestamp - intervals_1601_to_1970) / intervals_per_second; + tv.tv_usec = ((timestamp - intervals_1601_to_1970) / intervals_per_microsecond) % 1000000; + return tv; } -static inline u64 timespec_to_wim_timestamp(const struct timespec *ts) +static inline u64 +timespec_to_wim_timestamp(const struct timespec ts) { return intervals_1601_to_1970 - + (u64)ts->tv_sec * intervals_per_second - + (u64)ts->tv_nsec / nanoseconds_per_interval; + + (u64)ts.tv_sec * intervals_per_second + + (u64)ts.tv_nsec / nanoseconds_per_interval; } -extern u64 get_wim_timestamp(); -extern void wim_timestamp_to_str(u64 timestamp, char *buf, size_t len); +static inline struct timespec +wim_timestamp_to_timespec(u64 timestamp) +{ + struct timespec ts; + ts.tv_sec = (timestamp - intervals_1601_to_1970) / intervals_per_second; + ts.tv_nsec = ((timestamp - intervals_1601_to_1970) % intervals_per_second) * + nanoseconds_per_interval; + return ts; +} + +extern u64 +get_wim_timestamp(); + +extern void +wim_timestamp_to_str(u64 timestamp, char *buf, size_t len); #endif diff --git a/src/util.c b/src/util.c index 31b51ff4..df813bb9 100644 --- a/src/util.c +++ b/src/util.c @@ -459,7 +459,7 @@ u64 get_wim_timestamp() { struct timeval tv; gettimeofday(&tv, NULL); - return timeval_to_wim_timestamp(&tv); + return timeval_to_wim_timestamp(tv); } void wim_timestamp_to_str(u64 timestamp, char *buf, size_t len) diff --git a/src/wimlib_internal.h b/src/wimlib_internal.h index 3f05d882..554d3cc4 100644 --- a/src/wimlib_internal.h +++ b/src/wimlib_internal.h @@ -425,7 +425,7 @@ struct apply_args { WIMStruct *w; const char *target; int extract_flags; - unsigned num_lutimes_warnings; + unsigned num_utime_warnings; struct list_head *stream_list; union wimlib_progress_info progress; #ifdef WITH_NTFS_3G