1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2003-2008 Tim Kientzle
5 * All rights reserved.
6 */
7 #include "test.h"
8 #if defined(HAVE_UTIME_H)
9 #include <utime.h>
10 #elif defined(HAVE_SYS_UTIME_H)
11 #include <sys/utime.h>
12 #endif
13
14 static struct {
15 const char *name;
16 time_t atime_sec;
17 } files[] = {
18 { "f0", 0 },
19 { "f1", 0 },
20 { "f2", 0 },
21 { "f3", 0 },
22 { "f4", 0 },
23 { "f5", 0 }
24 };
25
26 /*
27 * Create a bunch of test files and record their atimes.
28 * For the atime preserve/change tests, the files must have
29 * atimes in the past. We can accomplish this by explicitly invoking
30 * utime() on platforms that support it or by simply sleeping
31 * for a second after creating the files. (Creating all of the files
32 * at once means we only need to sleep once.)
33 */
34 static void
test_create(void)35 test_create(void)
36 {
37 struct stat st;
38 struct utimbuf times;
39 static const int numfiles = sizeof(files) / sizeof(files[0]);
40 int i;
41
42 for (i = 0; i < numfiles; ++i) {
43 /*
44 * Note: Have to write at least one byte to the file.
45 * cpio doesn't bother reading the file if it's zero length,
46 * so the atime never gets changed in that case, which
47 * makes the tests below rather pointless.
48 */
49 assertMakeFile(files[i].name, 0644, "a");
50
51 /* If utime() isn't supported on your platform, just
52 * #ifdef this section out. Most of the test below is
53 * still valid. */
54 memset(×, 0, sizeof(times));
55 #if defined(_WIN32) && !defined(CYGWIN)
56 times.actime = 86400;
57 times.modtime = 86400;
58 #else
59 times.actime = 1;
60 times.modtime = 3;
61 #endif
62 assertEqualInt(0, utime(files[i].name, ×));
63
64 /* Record whatever atime the file ended up with. */
65 /* If utime() is available, this should be 1, but there's
66 * no harm in being careful. */
67 assertEqualInt(0, stat(files[i].name, &st));
68 files[i].atime_sec = st.st_atime;
69 }
70
71 /* Wait until the atime on the last file is actually in the past. */
72 sleepUntilAfter(files[numfiles - 1].atime_sec);
73 }
74
DEFINE_TEST(test_option_a)75 DEFINE_TEST(test_option_a)
76 {
77 struct stat st;
78 int r;
79 char *p;
80
81 /* Create all of the test files. */
82 test_create();
83
84 /* Sanity check; verify that atimes really do get modified. */
85 p = slurpfile(NULL, "f0");
86 assert(p != NULL);
87 free(p);
88 assertEqualInt(0, stat("f0", &st));
89 if (st.st_atime == files[0].atime_sec) {
90 skipping("Cannot verify -a option\n"
91 " Your system appears to not support atime.");
92 }
93 else
94 {
95 /*
96 * If this disk is mounted noatime, then we can't
97 * verify correct operation without -a.
98 */
99
100 /* Copy the file without -a; should change the atime. */
101 r = systemf("echo %s | %s -pd copy-no-a > copy-no-a.out 2>copy-no-a.err", files[1].name, testprog);
102 assertEqualInt(r, 0);
103 assertTextFileContents("1 block\n", "copy-no-a.err");
104 assertEmptyFile("copy-no-a.out");
105 assertEqualInt(0, stat(files[1].name, &st));
106 failure("Copying file without -a should have changed atime.");
107 assert(st.st_atime != files[1].atime_sec);
108
109 /* Archive the file without -a; should change the atime. */
110 r = systemf("echo %s | %s -o > archive-no-a.out 2>archive-no-a.err", files[2].name, testprog);
111 assertEqualInt(r, 0);
112 assertTextFileContents("1 block\n", "copy-no-a.err");
113 assertEqualInt(0, stat(files[2].name, &st));
114 failure("Archiving file without -a should have changed atime.");
115 assert(st.st_atime != files[2].atime_sec);
116 }
117
118 /*
119 * We can, of course, still verify that the atime is unchanged
120 * when using the -a option.
121 */
122
123 /* Copy the file with -a; should not change the atime. */
124 r = systemf("echo %s | %s -pad copy-a > copy-a.out 2>copy-a.err",
125 files[3].name, testprog);
126 assertEqualInt(r, 0);
127 assertTextFileContents("1 block\n", "copy-a.err");
128 assertEmptyFile("copy-a.out");
129 assertEqualInt(0, stat(files[3].name, &st));
130 failure("Copying file with -a should not have changed atime.");
131 assertEqualInt(st.st_atime, files[3].atime_sec);
132
133 /* Archive the file with -a; should not change the atime. */
134 r = systemf("echo %s | %s -oa > archive-a.out 2>archive-a.err",
135 files[4].name, testprog);
136 assertEqualInt(r, 0);
137 assertTextFileContents("1 block\n", "copy-a.err");
138 assertEqualInt(0, stat(files[4].name, &st));
139 failure("Archiving file with -a should not have changed atime.");
140 assertEqualInt(st.st_atime, files[4].atime_sec);
141 }
142