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
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
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.
15 */
16
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"
22 #include "apr_poll.h"
23 #include "apr_lib.h"
24 #include "testutil.h"
25
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."
29
30 static const struct view_fileinfo
31 {
32 apr_int32_t bits;
33 char *description;
34 } vfi[] = {
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"},
48 {0, NULL}
49 };
50
finfo_equal(abts_case * tc,apr_finfo_t * f1,apr_finfo_t * f2)51 static void finfo_equal(abts_case *tc, apr_finfo_t *f1, apr_finfo_t *f2)
52 {
53 /* Minimum supported flags across all platforms (APR_FINFO_MIN) */
54 ABTS_ASSERT(tc, "apr_stat and apr_getfileinfo must return APR_FINFO_TYPE",
55 (f1->valid & f2->valid & APR_FINFO_TYPE));
56 ABTS_ASSERT(tc, "apr_stat and apr_getfileinfo differ in filetype",
57 f1->filetype == f2->filetype);
58 ABTS_ASSERT(tc, "apr_stat and apr_getfileinfo must return APR_FINFO_SIZE",
59 (f1->valid & f2->valid & APR_FINFO_SIZE));
60 ABTS_ASSERT(tc, "apr_stat and apr_getfileinfo differ in size",
61 f1->size == f2->size);
62 ABTS_ASSERT(tc, "apr_stat and apr_getfileinfo must return APR_FINFO_ATIME",
63 (f1->valid & f2->valid & APR_FINFO_ATIME));
64 ABTS_ASSERT(tc, "apr_stat and apr_getfileinfo differ in atime",
65 f1->atime == f2->atime);
66 ABTS_ASSERT(tc, "apr_stat and apr_getfileinfo must return APR_FINFO_MTIME",
67 (f1->valid & f2->valid & APR_FINFO_MTIME));
68 ABTS_ASSERT(tc, "apr_stat and apr_getfileinfo differ in mtime",
69 f1->mtime == f2->mtime);
70 ABTS_ASSERT(tc, "apr_stat and apr_getfileinfo must return APR_FINFO_CTIME",
71 (f1->valid & f2->valid & APR_FINFO_CTIME));
72 ABTS_ASSERT(tc, "apr_stat and apr_getfileinfo differ in ctime",
73 f1->ctime == f2->ctime);
74
75 if (f1->valid & f2->valid & APR_FINFO_NAME)
76 ABTS_ASSERT(tc, "apr_stat and apr_getfileinfo differ in name",
77 !strcmp(f1->name, f2->name));
78 if (f1->fname && f2->fname)
79 ABTS_ASSERT(tc, "apr_stat and apr_getfileinfo differ in fname",
80 !strcmp(f1->fname, f2->fname));
81
82 /* Additional supported flags not supported on all platforms */
83 if (f1->valid & f2->valid & APR_FINFO_USER)
84 ABTS_ASSERT(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 ABTS_ASSERT(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 ABTS_ASSERT(tc, "apr_stat and apr_getfileinfo differ in inode",
91 f1->inode == f2->inode);
92 if (f1->valid & f2->valid & APR_FINFO_DEV)
93 ABTS_ASSERT(tc, "apr_stat and apr_getfileinfo differ in device",
94 f1->device == f2->device);
95 if (f1->valid & f2->valid & APR_FINFO_NLINK)
96 ABTS_ASSERT(tc, "apr_stat and apr_getfileinfo differ in nlink",
97 f1->nlink == f2->nlink);
98 if (f1->valid & f2->valid & APR_FINFO_CSIZE)
99 ABTS_ASSERT(tc, "apr_stat and apr_getfileinfo differ in csize",
100 f1->csize == f2->csize);
101 if (f1->valid & f2->valid & APR_FINFO_PROT)
102 ABTS_ASSERT(tc, "apr_stat and apr_getfileinfo differ in protection",
103 f1->protection == f2->protection);
104 }
105
test_info_get(abts_case * tc,void * data)106 static void test_info_get(abts_case *tc, void *data)
107 {
108 apr_file_t *thefile;
109 apr_finfo_t finfo;
110 apr_status_t rv;
111
112 rv = apr_file_open(&thefile, FILENAME, APR_READ, APR_OS_DEFAULT, p);
113 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
114
115 rv = apr_file_info_get(&finfo, APR_FINFO_NORM, thefile);
116 if (rv == APR_INCOMPLETE) {
117 char *str;
118 int i;
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);
123 }
124 }
125 ABTS_FAIL(tc, str);
126 }
127 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
128 apr_file_close(thefile);
129 }
130
test_stat(abts_case * tc,void * data)131 static void test_stat(abts_case *tc, void *data)
132 {
133 apr_finfo_t finfo;
134 apr_status_t rv;
135
136 rv = apr_stat(&finfo, FILENAME, APR_FINFO_NORM, p);
137 if (rv == APR_INCOMPLETE) {
138 char *str;
139 int i;
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);
144 }
145 }
146 ABTS_FAIL(tc, str);
147 }
148 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
149 }
150
test_stat_eq_finfo(abts_case * tc,void * data)151 static void test_stat_eq_finfo(abts_case *tc, void *data)
152 {
153 apr_file_t *thefile;
154 apr_finfo_t finfo;
155 apr_finfo_t stat_finfo;
156 apr_status_t rv;
157
158 rv = apr_file_open(&thefile, FILENAME, APR_READ, APR_OS_DEFAULT, p);
159 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
160 rv = apr_file_info_get(&finfo, APR_FINFO_NORM, thefile);
161
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...
165 */
166 rv = apr_stat(&stat_finfo, FILENAME, APR_FINFO_NORM, p);
167 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
168
169 apr_file_close(thefile);
170
171 finfo_equal(tc, &stat_finfo, &finfo);
172 }
173
test_buffered_write_size(abts_case * tc,void * data)174 static void test_buffered_write_size(abts_case *tc, void *data)
175 {
176 const apr_size_t data_len = strlen(NEWFILEDATA);
177 apr_file_t *thefile;
178 apr_finfo_t finfo;
179 apr_status_t rv;
180 apr_size_t bytes;
181
182 rv = apr_file_open(&thefile, NEWFILENAME,
183 APR_READ | APR_WRITE | APR_CREATE | APR_TRUNCATE
184 | APR_BUFFERED | APR_DELONCLOSE,
185 APR_OS_DEFAULT, p);
186 APR_ASSERT_SUCCESS(tc, "open file", rv);
187
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.
192 */
193 bytes = data_len;
194 rv = apr_file_write(thefile, NEWFILEDATA, &bytes);
195 APR_ASSERT_SUCCESS(tc, "write file contents", rv);
196 ABTS_TRUE(tc, data_len == bytes);
197
198 rv = apr_file_info_get(&finfo, APR_FINFO_SIZE, thefile);
199 APR_ASSERT_SUCCESS(tc, "get file size", rv);
200 ABTS_TRUE(tc, bytes == (apr_size_t) finfo.size);
201 apr_file_close(thefile);
202 }
203
test_mtime_set(abts_case * tc,void * data)204 static void test_mtime_set(abts_case *tc, void *data)
205 {
206 apr_file_t *thefile;
207 apr_finfo_t finfo;
208 apr_time_t epoch = 0;
209 apr_status_t rv;
210
211 /* This test sort of depends on the system clock being at least
212 * marginally ccorrect; We'll be setting the modification time to
213 * the epoch.
214 */
215 rv = apr_file_open(&thefile, NEWFILENAME,
216 APR_READ | APR_WRITE | APR_CREATE | APR_TRUNCATE
217 | APR_BUFFERED | APR_DELONCLOSE,
218 APR_OS_DEFAULT, p);
219 APR_ASSERT_SUCCESS(tc, "open file", rv);
220
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) {
224 char *str;
225 int i;
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);
230 }
231 }
232 ABTS_FAIL(tc, str);
233 }
234 APR_ASSERT_SUCCESS(tc, "get initial mtime", rv);
235 ABTS_TRUE(tc, finfo.mtime != epoch);
236
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.
240 */
241 rv = apr_file_mtime_set(NEWFILENAME, epoch, p);
242 APR_ASSERT_SUCCESS(tc, "set mtime", rv);
243
244 rv = apr_stat(&finfo, NEWFILENAME, APR_FINFO_MTIME, p);
245 APR_ASSERT_SUCCESS(tc, "get modified mtime", rv);
246 ABTS_TRUE(tc, finfo.mtime == epoch);
247
248 apr_file_close(thefile);
249 }
250
testfileinfo(abts_suite * suite)251 abts_suite *testfileinfo(abts_suite *suite)
252 {
253 suite = ADD_SUITE(suite)
254
255 abts_run_test(suite, test_info_get, NULL);
256 abts_run_test(suite, test_stat, NULL);
257 abts_run_test(suite, test_stat_eq_finfo, NULL);
258 abts_run_test(suite, test_buffered_write_size, NULL);
259 abts_run_test(suite, test_mtime_set, NULL);
260
261 return suite;
262 }
263
264