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
#include <unistd.h>
#ifdef HAVE_ALLOCA_H
-#include <alloca.h>
+# include <alloca.h>
#endif
/*
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);
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;
}
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;
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.
*
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;
}
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;
}
#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
{
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)
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