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 <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include "apr_file_io.h"
21 #include "apr_file_info.h"
22 #include "apr_errno.h"
23 #include "apr_general.h"
24 #include "apr_lib.h"
25 #include "apr_thread_proc.h"
26 #include "testutil.h"
27
test_mkdir(abts_case * tc,void * data)28 static void test_mkdir(abts_case *tc, void *data)
29 {
30 apr_status_t rv;
31 apr_finfo_t finfo;
32
33 rv = apr_dir_make("data/testdir", APR_UREAD | APR_UWRITE | APR_UEXECUTE, p);
34 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
35
36 rv = apr_stat(&finfo, "data/testdir", APR_FINFO_TYPE, p);
37 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
38 ABTS_INT_EQUAL(tc, APR_DIR, finfo.filetype);
39 }
40
test_mkdir_recurs(abts_case * tc,void * data)41 static void test_mkdir_recurs(abts_case *tc, void *data)
42 {
43 apr_status_t rv;
44 apr_finfo_t finfo;
45
46 rv = apr_dir_make_recursive("data/one/two/three",
47 APR_UREAD | APR_UWRITE | APR_UEXECUTE, p);
48 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
49
50 rv = apr_stat(&finfo, "data/one", APR_FINFO_TYPE, p);
51 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
52 ABTS_INT_EQUAL(tc, APR_DIR, finfo.filetype);
53
54 rv = apr_stat(&finfo, "data/one/two", APR_FINFO_TYPE, p);
55 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
56 ABTS_INT_EQUAL(tc, APR_DIR, finfo.filetype);
57
58 rv = apr_stat(&finfo, "data/one/two/three", APR_FINFO_TYPE, p);
59 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
60 ABTS_INT_EQUAL(tc, APR_DIR, finfo.filetype);
61 }
62
63 struct thread_data
64 {
65 abts_case *tc;
66 apr_pool_t *pool;
67 };
68
thread_mkdir_func(apr_thread_t * thd,void * data)69 static void *APR_THREAD_FUNC thread_mkdir_func(apr_thread_t *thd, void *data)
70 {
71 struct thread_data *td = data;
72 apr_status_t s1, s2, s3, s4, s5;
73
74 s1 = apr_dir_make_recursive("data/prll/one/thwo/three",
75 APR_FPROT_UREAD | APR_FPROT_UWRITE | APR_FPROT_UEXECUTE,
76 td->pool);
77 s2 = apr_dir_make_recursive("data/prll/four/five/six/seven/eight",
78 APR_FPROT_UREAD | APR_FPROT_UWRITE | APR_FPROT_UEXECUTE,
79 td->pool);
80 s3 = apr_dir_make_recursive("data/prll/nine/ten",
81 APR_FPROT_UREAD | APR_FPROT_UWRITE | APR_FPROT_UEXECUTE,
82 td->pool);
83 s4 = apr_dir_make_recursive("data/prll/11/12/13/14/15/16/17/18/19/20",
84 APR_FPROT_UREAD | APR_FPROT_UWRITE | APR_FPROT_UEXECUTE,
85 td->pool);
86 s5 = apr_dir_make_recursive("data/fortytwo",
87 APR_FPROT_UREAD | APR_FPROT_UWRITE | APR_FPROT_UEXECUTE,
88 td->pool);
89
90 ABTS_INT_EQUAL(td->tc, APR_SUCCESS, s1);
91 ABTS_INT_EQUAL(td->tc, APR_SUCCESS, s2);
92 ABTS_INT_EQUAL(td->tc, APR_SUCCESS, s3);
93 ABTS_INT_EQUAL(td->tc, APR_SUCCESS, s4);
94 ABTS_INT_EQUAL(td->tc, APR_SUCCESS, s5);
95 return NULL;
96 }
97
test_mkdir_recurs_parallel(abts_case * tc,void * data)98 static void test_mkdir_recurs_parallel(abts_case *tc, void *data)
99 {
100 struct thread_data td1, td2, td3, td4;
101 apr_thread_t *t1, *t2, *t3, *t4;
102 apr_status_t s1, s2, s3, s4;
103
104 td1.tc = td2.tc = td3.tc = td4.tc = tc;
105 apr_pool_create(&td1.pool, p);
106 apr_pool_create(&td2.pool, p);
107 apr_pool_create(&td3.pool, p);
108 apr_pool_create(&td4.pool, p);
109
110 s1 = apr_thread_create(&t1, NULL, thread_mkdir_func, &td1, td1.pool);
111 ABTS_INT_EQUAL(tc, APR_SUCCESS, s1);
112 s2 = apr_thread_create(&t2, NULL, thread_mkdir_func, &td2, td2.pool);
113 ABTS_INT_EQUAL(tc, APR_SUCCESS, s2);
114 s3 = apr_thread_create(&t3, NULL, thread_mkdir_func, &td3, td3.pool);
115 ABTS_INT_EQUAL(tc, APR_SUCCESS, s3);
116 s4 = apr_thread_create(&t4, NULL, thread_mkdir_func, &td4, td4.pool);
117 ABTS_INT_EQUAL(tc, APR_SUCCESS, s4);
118
119 apr_thread_join(&s1, t1);
120 apr_thread_join(&s2, t2);
121 apr_thread_join(&s3, t3);
122 apr_thread_join(&s4, t4);
123
124 ABTS_INT_EQUAL(tc, APR_SUCCESS, s1);
125 ABTS_INT_EQUAL(tc, APR_SUCCESS, s2);
126 ABTS_INT_EQUAL(tc, APR_SUCCESS, s3);
127 ABTS_INT_EQUAL(tc, APR_SUCCESS, s4);
128 }
129
test_remove(abts_case * tc,void * data)130 static void test_remove(abts_case *tc, void *data)
131 {
132 apr_status_t rv;
133 apr_finfo_t finfo;
134
135 rv = apr_dir_remove("data/testdir", p);
136 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
137
138 rv = apr_stat(&finfo, "data/testdir", APR_FINFO_TYPE, p);
139 ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_ENOENT(rv));
140 }
141
test_removeall_fail(abts_case * tc,void * data)142 static void test_removeall_fail(abts_case *tc, void *data)
143 {
144 apr_status_t rv;
145
146 rv = apr_dir_remove("data/one", p);
147 ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_ENOTEMPTY(rv));
148 }
149
test_removeall(abts_case * tc,void * data)150 static void test_removeall(abts_case *tc, void *data)
151 {
152 apr_status_t rv;
153
154 rv = apr_dir_remove("data/one/two/three", p);
155 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
156
157 rv = apr_dir_remove("data/one/two", p);
158 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
159
160 rv = apr_dir_remove("data/one", p);
161 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
162
163 rv = apr_dir_remove("data/prll/one/thwo/three", p);
164 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
165
166 rv = apr_dir_remove("data/prll/one/thwo", p);
167 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
168
169 rv = apr_dir_remove("data/prll/one", p);
170 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
171
172 rv = apr_dir_remove("data/prll/four/five/six/seven/eight", p);
173 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
174
175 rv = apr_dir_remove("data/prll/four/five/six/seven", p);
176 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
177
178 rv = apr_dir_remove("data/prll/four/five/six", p);
179 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
180
181 rv = apr_dir_remove("data/prll/four/five", p);
182 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
183
184 rv = apr_dir_remove("data/prll/four", p);
185 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
186
187 rv = apr_dir_remove("data/prll/nine/ten", p);
188 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
189
190 rv = apr_dir_remove("data/prll/nine", p);
191 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
192
193 rv = apr_dir_remove("data/prll/11/12/13/14/15/16/17/18/19/20", p);
194 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
195
196 rv = apr_dir_remove("data/prll/11/12/13/14/15/16/17/18/19", p);
197 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
198
199 rv = apr_dir_remove("data/prll/11/12/13/14/15/16/17/18", p);
200 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
201
202 rv = apr_dir_remove("data/prll/11/12/13/14/15/16/17", p);
203 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
204
205 rv = apr_dir_remove("data/prll/11/12/13/14/15/16", p);
206 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
207
208 rv = apr_dir_remove("data/prll/11/12/13/14/15", p);
209 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
210
211 rv = apr_dir_remove("data/prll/11/12/13/14", p);
212 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
213
214 rv = apr_dir_remove("data/prll/11/12/13", p);
215 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
216
217 rv = apr_dir_remove("data/prll/11/12", p);
218 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
219
220 rv = apr_dir_remove("data/prll/11", p);
221 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
222
223 rv = apr_dir_remove("data/prll", p);
224 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
225
226 rv = apr_dir_remove("data/fortytwo", p);
227 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
228 }
229
test_remove_notthere(abts_case * tc,void * data)230 static void test_remove_notthere(abts_case *tc, void *data)
231 {
232 apr_status_t rv;
233
234 rv = apr_dir_remove("data/notthere", p);
235 ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_ENOENT(rv));
236 }
237
test_mkdir_twice(abts_case * tc,void * data)238 static void test_mkdir_twice(abts_case *tc, void *data)
239 {
240 apr_status_t rv;
241
242 rv = apr_dir_make("data/testdir", APR_UREAD | APR_UWRITE | APR_UEXECUTE, p);
243 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
244
245 rv = apr_dir_make("data/testdir", APR_UREAD | APR_UWRITE | APR_UEXECUTE, p);
246 ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_EEXIST(rv));
247
248 rv = apr_dir_remove("data/testdir", p);
249 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
250 }
251
test_opendir(abts_case * tc,void * data)252 static void test_opendir(abts_case *tc, void *data)
253 {
254 apr_status_t rv;
255 apr_dir_t *dir;
256
257 rv = apr_dir_open(&dir, "data", p);
258 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
259 apr_dir_close(dir);
260 }
261
test_opendir_notthere(abts_case * tc,void * data)262 static void test_opendir_notthere(abts_case *tc, void *data)
263 {
264 apr_status_t rv;
265 apr_dir_t *dir;
266
267 rv = apr_dir_open(&dir, "notthere", p);
268 ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_ENOENT(rv));
269 }
270
test_closedir(abts_case * tc,void * data)271 static void test_closedir(abts_case *tc, void *data)
272 {
273 apr_status_t rv;
274 apr_dir_t *dir;
275
276 rv = apr_dir_open(&dir, "data", p);
277 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
278 rv = apr_dir_close(dir);
279 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
280 }
281
test_rewind(abts_case * tc,void * data)282 static void test_rewind(abts_case *tc, void *data)
283 {
284 apr_dir_t *dir;
285 apr_finfo_t first, second;
286
287 APR_ASSERT_SUCCESS(tc, "apr_dir_open failed", apr_dir_open(&dir, "data", p));
288
289 APR_ASSERT_SUCCESS(tc, "apr_dir_read failed",
290 apr_dir_read(&first, APR_FINFO_DIRENT, dir));
291
292 APR_ASSERT_SUCCESS(tc, "apr_dir_rewind failed", apr_dir_rewind(dir));
293
294 APR_ASSERT_SUCCESS(tc, "second apr_dir_read failed",
295 apr_dir_read(&second, APR_FINFO_DIRENT, dir));
296
297 APR_ASSERT_SUCCESS(tc, "apr_dir_close failed", apr_dir_close(dir));
298
299 ABTS_STR_EQUAL(tc, first.name, second.name);
300 }
301
302 /* Test for a (fixed) bug in apr_dir_read(). This bug only happened
303 in threadless cases. */
test_uncleared_errno(abts_case * tc,void * data)304 static void test_uncleared_errno(abts_case *tc, void *data)
305 {
306 apr_file_t *thefile = NULL;
307 apr_finfo_t finfo;
308 apr_int32_t finfo_flags = APR_FINFO_TYPE | APR_FINFO_NAME;
309 apr_dir_t *this_dir;
310 apr_status_t rv;
311
312 rv = apr_dir_make("dir1", APR_OS_DEFAULT, p);
313 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
314 rv = apr_dir_make("dir2", APR_OS_DEFAULT, p);
315 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
316 rv = apr_file_open(&thefile, "dir1/file1",
317 APR_FOPEN_READ | APR_FOPEN_WRITE | APR_FOPEN_CREATE, APR_OS_DEFAULT, p);
318 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
319 rv = apr_file_close(thefile);
320 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
321
322 /* Try to remove dir1. This should fail because it's not empty.
323 However, on a platform with threads disabled (such as FreeBSD),
324 `errno' will be set as a result. */
325 rv = apr_dir_remove("dir1", p);
326 ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_ENOTEMPTY(rv));
327
328 /* Read `.' and `..' out of dir2. */
329 rv = apr_dir_open(&this_dir, "dir2", p);
330 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
331 rv = apr_dir_read(&finfo, finfo_flags, this_dir);
332 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
333 rv = apr_dir_read(&finfo, finfo_flags, this_dir);
334 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
335
336 /* Now, when we attempt to do a third read of empty dir2, and the
337 underlying system readdir() returns NULL, the old value of
338 errno shouldn't cause a false alarm. We should get an ENOENT
339 back from apr_dir_read, and *not* the old errno. */
340 rv = apr_dir_read(&finfo, finfo_flags, this_dir);
341 ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_ENOENT(rv));
342
343 rv = apr_dir_close(this_dir);
344 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
345
346 /* Cleanup */
347 rv = apr_file_remove("dir1/file1", p);
348 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
349 rv = apr_dir_remove("dir1", p);
350 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
351 rv = apr_dir_remove("dir2", p);
352 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
353
354 }
355
test_rmkdir_nocwd(abts_case * tc,void * data)356 static void test_rmkdir_nocwd(abts_case *tc, void *data)
357 {
358 char *cwd, *path;
359
360 APR_ASSERT_SUCCESS(tc, "make temp dir",
361 apr_dir_make("dir3", APR_OS_DEFAULT, p));
362
363 APR_ASSERT_SUCCESS(tc, "obtain cwd", apr_filepath_get(&cwd, 0, p));
364
365 APR_ASSERT_SUCCESS(tc, "determine path to temp dir",
366 apr_filepath_merge(&path, cwd, "dir3", 0, p));
367
368 APR_ASSERT_SUCCESS(tc, "change to temp dir", apr_filepath_set(path, p));
369
370 APR_ASSERT_SUCCESS(tc, "restore cwd", apr_filepath_set(cwd, p));
371
372 APR_ASSERT_SUCCESS(tc, "remove cwd", apr_dir_remove(path, p));
373 }
374
375
testdir(abts_suite * suite)376 abts_suite *testdir(abts_suite *suite)
377 {
378 suite = ADD_SUITE(suite)
379
380 abts_run_test(suite, test_mkdir, NULL);
381 abts_run_test(suite, test_mkdir_recurs, NULL);
382 abts_run_test(suite, test_mkdir_recurs_parallel, NULL);
383 abts_run_test(suite, test_remove, NULL);
384 abts_run_test(suite, test_removeall_fail, NULL);
385 abts_run_test(suite, test_removeall, NULL);
386 abts_run_test(suite, test_remove_notthere, NULL);
387 abts_run_test(suite, test_mkdir_twice, NULL);
388 abts_run_test(suite, test_rmkdir_nocwd, NULL);
389
390 abts_run_test(suite, test_rewind, NULL);
391
392 abts_run_test(suite, test_opendir, NULL);
393 abts_run_test(suite, test_opendir_notthere, NULL);
394 abts_run_test(suite, test_closedir, NULL);
395 abts_run_test(suite, test_uncleared_errno, NULL);
396
397 return suite;
398 }
399
400