return (1);
}
+/* Verify a/b/mtime of 'pathname'. */
+/* If 'recent', verify that it's within last 10 seconds. */
+static int
+assertion_file_time(const char *file, int line,
+ const char *pathname, long t, long nsec, char type, int recent)
+{
+ long filet, filet_nsec;
+ int r;
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ FILETIME ftime, fbirthtime, fatime, fmtime;
+ ULARGE_INTEGER wintm;
+ HANDLE h;
+
+ assertion_count(file, line);
+ h = CreateFile(pathname, FILE_READ_ATTRIBUTES, 0, NULL,
+ OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (h == INVALID_HANDLE_VALUE) {
+ failure_start(file, line, "Can't access %s\n", pathname);
+ failure_finish(NULL);
+ return (0);
+ }
+ r = GetFileTime(h, &fbirthtime, &fatime, &fmtime);
+ switch (type) {
+ case 'a': ftime = fatime; break;
+ case 'm': ftime = fmtime; break;
+ case 'b': ftime = fbirthtime; break;
+ }
+ CloseHandle(h);
+ if (r == 0) {
+ failure_start(file, line, "Can't GetFileTime %s\n", pathname);
+ failure_finish(NULL);
+ return (0);
+ }
+ wintm.LowPart = fmtime.dwLowDateTime;
+ wintm.HighPart = fmtime.dwHighDateTime;
+ filet = (wintm.QuadPart - EPOC_TIME) / 10000000;
+ filet_nsec = ((wintm.QuadPart - EPOC_TIME) % 10000000) * 100;
+ nsec = (nsec / 100) * 100; /* Round the request */
+#else
+ struct stat st;
+
+ assertion_count(file, line);
+ r = lstat(pathname, &st);
+ if (r != 0) {
+ failure_start(file, line, "Can't stat %s\n", pathname);
+ failure_finish(NULL);
+ return (0);
+ }
+ switch (type) {
+ case 'a': filet = st.st_atime; break;
+ case 'm': filet = st.st_mtime; break;
+ case 'b': filet = 0; break;
+ default: fprintf(stderr, "INTERNAL: Bad type %c for file time", type);
+ exit(1);
+ }
+#if defined(__FreeBSD__)
+ switch (type) {
+ case 'a': filet_nsec = st.st_atimespec.tv_nsec; break;
+ case 'b': filet = st.st_birthtime;
+ filet_nsec = st.st_birthtimespec.tv_nsec; break;
+ case 'm': filet_nsec = st.st_mtimespec.tv_nsec; break;
+ default: fprintf(stderr, "INTERNAL: Bad type %c for file time", type);
+ exit(1);
+ }
+ /* FreeBSD generally only stores to microsecond res, so round. */
+ filet_nsec = (filet_nsec / 1000) * 1000;
+ nsec = (nsec / 1000) * 1000;
+#else
+ filet_nsec = nsec = 0; /* Generic POSIX only has whole seconds. */
+ if (type == 'b') return (1); /* Generic POSIX doesn't have birthtime */
+#endif
+#endif
+ if (recent) {
+ /* Check that requested time is up-to-date. */
+ time_t now = time(NULL);
+ if (filet < now - 10 || filet > now + 1) {
+ failure_start(file, line,
+ "File %s has %ctime %ld, %ld seconds ago\n",
+ pathname, type, filet, now - filet);
+ failure_finish(NULL);
+ return (0);
+ }
+ } else if (filet != t || filet_nsec != nsec) {
+ failure_start(file, line,
+ "File %s has %ctime %ld.%09ld, expected %ld.%09ld",
+ pathname, type, filet, filet_nsec, t, nsec);
+ failure_finish(NULL);
+ return (0);
+ }
+ return (1);
+}
+
+/* Verify atime of 'pathname'. */
+int
+assertion_file_atime(const char *file, int line,
+ const char *pathname, long t, long nsec)
+{
+ return assertion_file_time(file, line, pathname, t, nsec, 'a', 0);
+}
+
+/* Verify atime of 'pathname' is up-to-date. */
+int
+assertion_file_atime_recent(const char *file, int line, const char *pathname)
+{
+ return assertion_file_time(file, line, pathname, 0, 0, 'a', 1);
+}
+
+/* Verify birthtime of 'pathname'. */
+int
+assertion_file_birthtime(const char *file, int line,
+ const char *pathname, long t, long nsec)
+{
+ return assertion_file_time(file, line, pathname, t, nsec, 'b', 0);
+}
+
+/* Verify birthtime of 'pathname' is up-to-date. */
+int
+assertion_file_birthtime_recent(const char *file, int line,
+ const char *pathname)
+{
+ return assertion_file_time(file, line, pathname, 0, 0, 'b', 1);
+}
+
+/* Verify mtime of 'pathname'. */
+int
+assertion_file_mtime(const char *file, int line,
+ const char *pathname, long t, long nsec)
+{
+ return assertion_file_time(file, line, pathname, t, nsec, 'm', 0);
+}
+
+/* Verify mtime of 'pathname' is up-to-date. */
+int
+assertion_file_mtime_recent(const char *file, int line, const char *pathname)
+{
+ return assertion_file_time(file, line, pathname, 0, 0, 'm', 1);
+}
+
/* Verify number of links to 'pathname'. */
int
assertion_file_nlinks(const char *file, int line,
/* Assert that a file is not empty; supports printf-style arguments. */
#define assertNonEmptyFile \
assertion_setup(__FILE__, __LINE__);assertion_non_empty_file
+#define assertFileAtime(pathname, sec, nsec) \
+ assertion_file_atime(__FILE__, __LINE__, pathname, sec, nsec)
+#define assertFileAtimeRecent(pathname) \
+ assertion_file_atime_recent(__FILE__, __LINE__, pathname)
+#define assertFileBirthtime(pathname, sec, nsec) \
+ assertion_file_birthtime(__FILE__, __LINE__, pathname, sec, nsec)
+#define assertFileBirthtimeRecent(pathname) \
+ assertion_file_birthtime_recent(__FILE__, __LINE__, pathname)
/* Assert that a file exists; supports printf-style arguments. */
#define assertFileExists \
assertion_setup(__FILE__, __LINE__);assertion_file_exists
assertion_setup(__FILE__, __LINE__);assertion_file_contents
#define assertFileHardlinks(path1, path2) \
assertion_file_hardlinks(__FILE__, __LINE__, path1, path2)
+#define assertFileMtime(pathname, sec, nsec) \
+ assertion_file_mtime(__FILE__, __LINE__, pathname, sec, nsec)
+#define assertFileMtimeRecent(pathname) \
+ assertion_file_mtime_recent(__FILE__, __LINE__, pathname)
#define assertFileNLinks(pathname, nlinks) \
assertion_file_nlinks(__FILE__, __LINE__, pathname, nlinks)
#define assertFileSize(pathname, size) \
int assertion_equal_mem(const char *, int, const void *, const char *, const void *, const char *, size_t, const char *, void *);
int assertion_equal_string(const char *, int, const char *v1, const char *, const char *v2, const char *, void *);
int assertion_equal_wstring(const char *, int, const wchar_t *v1, const char *, const wchar_t *v2, const char *, void *);
+int assertion_file_atime(const char *, int, const char *, long, long);
+int assertion_file_atime_recent(const char *, int, const char *);
+int assertion_file_birthtime(const char *, int, const char *, long, long);
+int assertion_file_birthtime_recent(const char *, int, const char *);
int assertion_file_contents(const void *, int, const char *, ...);
int assertion_file_exists(const char *, ...);
int assertion_file_hardlinks(const char *, int, const char *, const char *);
+int assertion_file_mtime(const char *, int, const char *, long, long);
+int assertion_file_mtime_recent(const char *, int, const char *);
int assertion_file_nlinks(const char *, int, const char *, int);
int assertion_file_not_exists(const char *, ...);
int assertion_file_size(const char *, int, const char *, long);
{
static const char data[]="abcdefghijklmnopqrstuvwxyz";
struct archive *ad;
- struct stat st;
- time_t now;
/* Write the entry to disk. */
assert((ad = archive_write_disk_new()) != NULL);
assertIsReg(archive_entry_pathname(ae), archive_entry_mode(ae) & 0777);
assertFileSize(archive_entry_pathname(ae), sizeof(data));
/* test_write_disk_times has more detailed tests of this area. */
- assert(0 == stat(archive_entry_pathname(ae), &st));
- assertEqualInt(st.st_mtime, 123456789);
- failure("No atime was specified, so atime should get set to current time");
- now = time(NULL);
- assert(st.st_atime <= now && st.st_atime > now - 5);
+ assertFileMtime(archive_entry_pathname(ae), 123456789, 0);
+ failure("No atime given, so atime should get set to current time");
+ assertFileAtimeRecent(archive_entry_pathname(ae));
}
static void create_reg_file2(struct archive_entry *ae, const char *msg)
{
struct archive *a;
struct archive_entry *ae;
- struct stat st;
- time_t now = time(NULL);
/* Create an archive_write_disk object. */
assert((a = archive_write_disk_new()) != NULL);
assertEqualInt(ARCHIVE_OK, archive_write_finish_entry(a));
archive_entry_free(ae);
/* Verify */
- assertEqualInt(0, stat("file1", &st));
- assertEqualInt(123456, st.st_atime);
- assertEqualInt(234567, st.st_mtime);
+ assertFileAtime("file1", 123456, 0);
+ assertFileMtime("file1", 234567, 0);
/*
* mtime specified, but not atime
assertEqualInt(ARCHIVE_OK, archive_write_header(a, ae));
assertEqualInt(ARCHIVE_OK, archive_write_finish_entry(a));
archive_entry_free(ae);
- /* Verify: Current atime and mtime as specified. */
- assertEqualInt(0, stat("file2", &st));
- assertEqualInt(234567, st.st_mtime);
- failure("now: %ld st.st_atime: %ld", (long)now, (long)st.st_atime);
- assert(st.st_atime >= now && st.st_atime < now + 3);
+ assertFileMtime("file2", 234567, 0);
+ assertFileAtimeRecent("file2");
/*
* atime specified, but not mtime
assertEqualInt(ARCHIVE_OK, archive_write_finish_entry(a));
archive_entry_free(ae);
/* Verify: Current mtime and atime as specified. */
- assertEqualInt(0, stat("file3", &st));
- assertEqualInt(345678, st.st_atime);
- failure("now: %ld st.st_mtime: %ld", (long)now, (long)st.st_mtime);
- assert(st.st_mtime >= now && st.st_mtime < now + 3);
+ assertFileAtime("file3", 345678, 0);
+ assertFileMtimeRecent("file3");
/*
* Neither atime nor mtime specified.
assertEqualInt(ARCHIVE_OK, archive_write_finish_entry(a));
archive_entry_free(ae);
/* Verify: Current mtime and atime. */
- assertEqualInt(0, stat("file4", &st));
- failure("now: %ld st.st_atime: %ld", (long)now, (long)st.st_atime);
- assert(st.st_atime >= now && st.st_atime < now + 3);
- failure("now: %ld st.st_mtime: %ld", (long)now, (long)st.st_mtime);
- assert(st.st_mtime >= now && st.st_mtime < now + 3);
+ assertFileAtimeRecent("file4");
+ assertFileMtimeRecent("file4");
#if defined(__FreeBSD__)
/*
assertEqualInt(ARCHIVE_OK, archive_write_finish_entry(a));
archive_entry_free(ae);
/* Verify */
- /* FreeBSD can only store usec resolution, hence rounding here. */
- assertEqualInt(0, stat("file10", &st));
- assertEqualInt(1234567, st.st_atime);
- assertEqualInt(23000, st.st_atimespec.tv_nsec);
- assertEqualInt(2345678, st.st_mtime);
- assertEqualInt(4000, st.st_mtimespec.tv_nsec);
+ assertFileMtime("file10", 2345678, 4567);
+ assertFileAtime("file10", 1234567, 23456);
/*
* Birthtime, mtime and atime on FreeBSD
assertEqualInt(ARCHIVE_OK, archive_write_finish_entry(a));
archive_entry_free(ae);
/* Verify */
- /* FreeBSD can only store usec resolution, hence rounding here. */
- assertEqualInt(0, stat("file11", &st));
- assertEqualInt(1234567, st.st_atime);
- assertEqualInt(23000, st.st_atimespec.tv_nsec);
- assertEqualInt(3456789, st.st_birthtime);
- assertEqualInt(12000, st.st_birthtimespec.tv_nsec);
- assertEqualInt(12345678, st.st_mtime);
- assertEqualInt(4000, st.st_mtimespec.tv_nsec);
+ assertFileAtime("file11", 1234567, 23456);
+ assertFileBirthtime("file11", 3456789, 12345);
+ assertFileMtime("file11", 12345678, 4567);
/*
* Birthtime only on FreeBSD.
assertEqualInt(ARCHIVE_OK, archive_write_finish_entry(a));
archive_entry_free(ae);
/* Verify */
- /* FreeBSD can only store usec resolution, hence rounding here. */
- assertEqualInt(0, stat("file12", &st));
- assertEqualInt(3456789, st.st_birthtime);
- assertEqualInt(12000, st.st_birthtimespec.tv_nsec);
- failure("now: %ld st.st_atime: %ld", (long)now, (long)st.st_atime);
- assert(st.st_atime >= now && st.st_atime < now + 3);
- failure("now: %ld st.st_mtime: %ld", (long)now, (long)st.st_mtime);
- assert(st.st_mtime >= now && st.st_mtime < now + 3);
+ assertFileAtimeRecent("file12");
+ assertFileBirthtime("file12", 3456789, 12345);
+ assertFileMtimeRecent("file12");
/*
* mtime only on FreeBSD.
assertEqualInt(ARCHIVE_OK, archive_write_finish_entry(a));
archive_entry_free(ae);
/* Verify */
- /* FreeBSD can only store usec resolution, hence rounding here. */
- assertEqualInt(0, stat("file13", &st));
- assertEqualInt(4567890, st.st_birthtime);
- assertEqualInt(23000, st.st_birthtimespec.tv_nsec);
- assertEqualInt(4567890, st.st_mtime);
- assertEqualInt(23000, st.st_mtimespec.tv_nsec);
- failure("now: %ld st.st_atime: %ld", (long)now, (long)st.st_atime);
- assert(st.st_atime >= now && st.st_atime < now + 3);
+ assertFileAtimeRecent("file13");
+ assertFileBirthtime("file13", 4567890, 23456);
+ assertFileMtime("file13", 4567890, 23456);
#else
skipping("Platform-specific time restore tests");
#endif