1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #include "apr_file_io.h"
18 #include "apr_file_info.h"
19 #include "apr_strings.h"
20 #include "apr_errno.h"
21 #include "apr_general.h"
26 #define FILENAME "data/file_datafile.txt"
27 #define NEWFILENAME "data/new_datafile.txt"
28 #define NEWFILEDATA "This is new text in a new file."
30 static const struct view_fileinfo
35 {APR_FINFO_MTIME, "MTIME"},
36 {APR_FINFO_CTIME, "CTIME"},
37 {APR_FINFO_ATIME, "ATIME"},
38 {APR_FINFO_SIZE, "SIZE"},
39 {APR_FINFO_DEV, "DEV"},
40 {APR_FINFO_INODE, "INODE"},
41 {APR_FINFO_NLINK, "NLINK"},
42 {APR_FINFO_TYPE, "TYPE"},
43 {APR_FINFO_USER, "USER"},
44 {APR_FINFO_GROUP, "GROUP"},
45 {APR_FINFO_UPROT, "UPROT"},
46 {APR_FINFO_GPROT, "GPROT"},
47 {APR_FINFO_WPROT, "WPROT"},
51 static void finfo_equal(CuTest *tc, apr_finfo_t f1, apr_finfo_t f2)
53 /* Minimum supported flags across all platforms (APR_FINFO_MIN) */
54 CuAssert(tc, "apr_stat and apr_getfileinfo must return APR_FINFO_TYPE",
55 (f1.valid & f2.valid & APR_FINFO_TYPE));
56 CuAssert(tc, "apr_stat and apr_getfileinfo differ in filetype",
57 f1.filetype == f2.filetype);
58 CuAssert(tc, "apr_stat and apr_getfileinfo must return APR_FINFO_SIZE",
59 (f1.valid & f2.valid & APR_FINFO_SIZE));
60 CuAssert(tc, "apr_stat and apr_getfileinfo differ in size",
62 CuAssert(tc, "apr_stat and apr_getfileinfo must return APR_FINFO_ATIME",
63 (f1.valid & f2.valid & APR_FINFO_ATIME));
64 CuAssert(tc, "apr_stat and apr_getfileinfo differ in atime",
65 f1.atime == f2.atime);
66 CuAssert(tc, "apr_stat and apr_getfileinfo must return APR_FINFO_MTIME",
67 (f1.valid & f2.valid & APR_FINFO_MTIME));
68 CuAssert(tc, "apr_stat and apr_getfileinfo differ in mtime",
69 f1.mtime == f2.mtime);
70 CuAssert(tc, "apr_stat and apr_getfileinfo must return APR_FINFO_CTIME",
71 (f1.valid & f2.valid & APR_FINFO_CTIME));
72 CuAssert(tc, "apr_stat and apr_getfileinfo differ in ctime",
73 f1.ctime == f2.ctime);
75 if (f1.valid & f2.valid & APR_FINFO_NAME)
76 CuAssert(tc, "apr_stat and apr_getfileinfo differ in name",
77 !strcmp(f1.name, f2.name));
78 if (f1.fname && f2.fname)
79 CuAssert(tc, "apr_stat and apr_getfileinfo differ in fname",
80 !strcmp(f1.fname, f2.fname));
82 /* Additional supported flags not supported on all platforms */
83 if (f1.valid & f2.valid & APR_FINFO_USER)
84 CuAssert(tc, "apr_stat and apr_getfileinfo differ in user",
85 !apr_uid_compare(f1.user, f2.user));
86 if (f1.valid & f2.valid & APR_FINFO_GROUP)
87 CuAssert(tc, "apr_stat and apr_getfileinfo differ in group",
88 !apr_gid_compare(f1.group, f2.group));
89 if (f1.valid & f2.valid & APR_FINFO_INODE)
90 CuAssert(tc, "apr_stat and apr_getfileinfo differ in inode",
91 f1.inode == f2.inode);
92 if (f1.valid & f2.valid & APR_FINFO_DEV)
93 CuAssert(tc, "apr_stat and apr_getfileinfo differ in device",
94 f1.device == f2.device);
95 if (f1.valid & f2.valid & APR_FINFO_NLINK)
96 CuAssert(tc, "apr_stat and apr_getfileinfo differ in nlink",
97 f1.nlink == f2.nlink);
98 if (f1.valid & f2.valid & APR_FINFO_CSIZE)
99 CuAssert(tc, "apr_stat and apr_getfileinfo differ in csize",
100 f1.csize == f2.csize);
101 if (f1.valid & f2.valid & APR_FINFO_PROT)
102 CuAssert(tc, "apr_stat and apr_getfileinfo differ in protection",
103 f1.protection == f2.protection);
106 static void test_info_get(CuTest *tc)
112 rv = apr_file_open(&thefile, FILENAME, APR_READ, APR_OS_DEFAULT, p);
113 CuAssertIntEquals(tc, APR_SUCCESS, rv);
115 rv = apr_file_info_get(&finfo, APR_FINFO_NORM, thefile);
116 if (rv == APR_INCOMPLETE) {
119 str = apr_pstrdup(p, "APR_INCOMPLETE: Missing ");
120 for (i = 0; vfi[i].bits; ++i) {
121 if (vfi[i].bits & ~finfo.valid) {
122 str = apr_pstrcat(p, str, vfi[i].description, " ", NULL);
127 CuAssertIntEquals(tc, APR_SUCCESS, rv);
128 apr_file_close(thefile);
131 static void test_stat(CuTest *tc)
136 rv = apr_stat(&finfo, FILENAME, APR_FINFO_NORM, p);
137 if (rv == APR_INCOMPLETE) {
140 str = apr_pstrdup(p, "APR_INCOMPLETE: Missing ");
141 for (i = 0; vfi[i].bits; ++i) {
142 if (vfi[i].bits & ~finfo.valid) {
143 str = apr_pstrcat(p, str, vfi[i].description, " ", NULL);
148 CuAssertIntEquals(tc, APR_SUCCESS, rv);
151 static void test_stat_eq_finfo(CuTest *tc)
155 apr_finfo_t stat_finfo;
158 rv = apr_file_open(&thefile, FILENAME, APR_READ, APR_OS_DEFAULT, p);
159 CuAssertIntEquals(tc, APR_SUCCESS, rv);
160 rv = apr_file_info_get(&finfo, APR_FINFO_NORM, thefile);
162 /* Opening the file may have toggled the atime member (time last
163 * accessed), so fetch our apr_stat() after getting the fileinfo
164 * of the open file...
166 rv = apr_stat(&stat_finfo, FILENAME, APR_FINFO_NORM, p);
167 CuAssertIntEquals(tc, APR_SUCCESS, rv);
169 apr_file_close(thefile);
171 finfo_equal(tc, stat_finfo, finfo);
174 static void test_buffered_write_size(CuTest *tc)
176 const apr_size_t data_len = strlen(NEWFILEDATA);
182 rv = apr_file_open(&thefile, NEWFILENAME,
183 APR_READ | APR_WRITE | APR_CREATE | APR_TRUNCATE
184 | APR_BUFFERED | APR_DELONCLOSE,
186 apr_assert_success(tc, "open file", rv);
188 /* A funny thing happened to me the other day: I wrote something
189 * into a buffered file, then asked for its size using
190 * apr_file_info_get; and guess what? The size was 0! That's not a
191 * nice way to behave.
194 rv = apr_file_write(thefile, NEWFILEDATA, &bytes);
195 apr_assert_success(tc, "write file contents", rv);
196 CuAssertTrue(tc, data_len == bytes);
198 rv = apr_file_info_get(&finfo, APR_FINFO_SIZE, thefile);
199 apr_assert_success(tc, "get file size", rv);
200 CuAssertTrue(tc, bytes == (apr_size_t) finfo.size);
201 apr_file_close(thefile);
204 static void test_mtime_set(CuTest *tc)
208 apr_time_t epoch = 0;
211 /* This test sort of depends on the system clock being at least
212 * marginally ccorrect; We'll be setting the modification time to
215 rv = apr_file_open(&thefile, NEWFILENAME,
216 APR_READ | APR_WRITE | APR_CREATE | APR_TRUNCATE
217 | APR_BUFFERED | APR_DELONCLOSE,
219 apr_assert_success(tc, "open file", rv);
221 /* Check that the current mtime is not the epoch */
222 rv = apr_stat(&finfo, NEWFILENAME, APR_FINFO_MTIME, p);
223 if (rv == APR_INCOMPLETE) {
226 str = apr_pstrdup(p, "APR_INCOMPLETE: Missing ");
227 for (i = 0; vfi[i].bits; ++i) {
228 if (vfi[i].bits & ~finfo.valid) {
229 str = apr_pstrcat(p, str, vfi[i].description, " ", NULL);
234 apr_assert_success(tc, "get initial mtime", rv);
235 CuAssertTrue(tc, finfo.mtime != epoch);
237 /* Reset the mtime to the epoch and verify the result.
238 * Note: we blindly assume that if the first apr_stat succeeded,
239 * the second one will, too.
241 rv = apr_file_mtime_set(NEWFILENAME, epoch, p);
242 apr_assert_success(tc, "set mtime", rv);
244 rv = apr_stat(&finfo, NEWFILENAME, APR_FINFO_MTIME, p);
245 apr_assert_success(tc, "get modified mtime", rv);
246 CuAssertTrue(tc, finfo.mtime == epoch);
248 apr_file_close(thefile);
251 CuSuite *testfileinfo(void)
253 CuSuite *suite = CuSuiteNew("File Info");
255 SUITE_ADD_TEST(suite, test_info_get);
256 SUITE_ADD_TEST(suite, test_stat);
257 SUITE_ADD_TEST(suite, test_stat_eq_finfo);
258 SUITE_ADD_TEST(suite, test_buffered_write_size);
259 SUITE_ADD_TEST(suite, test_mtime_set);