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_network_io.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 DIRNAME "data"
27#define FILENAME DIRNAME "/file_datafile.txt"
28#define TESTSTR  "This is the file data file."
29
30#define TESTREAD_BLKSIZE 1024
31#define APR_BUFFERSIZE   4096 /* This should match APR's buffer size. */
32
33
34
35static void test_open_noreadwrite(abts_case *tc, void *data)
36{
37    apr_status_t rv;
38    apr_file_t *thefile = NULL;
39
40    rv = apr_file_open(&thefile, FILENAME,
41                       APR_FOPEN_CREATE | APR_FOPEN_EXCL,
42                       APR_UREAD | APR_UWRITE | APR_GREAD, p);
43    ABTS_TRUE(tc, rv != APR_SUCCESS);
44    ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_EACCES(rv));
45    ABTS_PTR_EQUAL(tc, NULL, thefile);
46}
47
48static void test_open_excl(abts_case *tc, void *data)
49{
50    apr_status_t rv;
51    apr_file_t *thefile = NULL;
52
53    rv = apr_file_open(&thefile, FILENAME,
54                       APR_FOPEN_CREATE | APR_FOPEN_EXCL | APR_FOPEN_WRITE,
55                       APR_UREAD | APR_UWRITE | APR_GREAD, p);
56    ABTS_TRUE(tc, rv != APR_SUCCESS);
57    ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_EEXIST(rv));
58    ABTS_PTR_EQUAL(tc, NULL, thefile);
59}
60
61static void test_open_read(abts_case *tc, void *data)
62{
63    apr_status_t rv;
64    apr_file_t *filetest = NULL;
65
66    rv = apr_file_open(&filetest, FILENAME,
67                       APR_FOPEN_READ,
68                       APR_UREAD | APR_UWRITE | APR_GREAD, p);
69    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
70    ABTS_PTR_NOTNULL(tc, filetest);
71    apr_file_close(filetest);
72}
73
74static void link_existing(abts_case *tc, void *data)
75{
76    apr_status_t rv;
77
78    rv = apr_file_link("data/file_datafile.txt", "data/file_datafile2.txt");
79    apr_file_remove("data/file_datafile2.txt", p);
80    ABTS_ASSERT(tc, "Couldn't create hardlink to file", rv == APR_SUCCESS);
81}
82
83static void link_nonexisting(abts_case *tc, void *data)
84{
85    apr_status_t rv;
86
87    rv = apr_file_link("data/does_not_exist.txt", "data/fake.txt");
88    ABTS_ASSERT(tc, "", rv != APR_SUCCESS);
89}
90
91static void test_read(abts_case *tc, void *data)
92{
93    apr_status_t rv;
94    apr_size_t nbytes = 256;
95    char *str = apr_pcalloc(p, nbytes + 1);
96    apr_file_t *filetest = NULL;
97
98    rv = apr_file_open(&filetest, FILENAME,
99                       APR_FOPEN_READ,
100                       APR_UREAD | APR_UWRITE | APR_GREAD, p);
101
102    APR_ASSERT_SUCCESS(tc, "Opening test file " FILENAME, rv);
103    rv = apr_file_read(filetest, str, &nbytes);
104    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
105    ABTS_SIZE_EQUAL(tc, strlen(TESTSTR), nbytes);
106    ABTS_STR_EQUAL(tc, TESTSTR, str);
107
108    apr_file_close(filetest);
109}
110
111static void test_readzero(abts_case *tc, void *data)
112{
113    apr_status_t rv;
114    apr_size_t nbytes = 0;
115    char *str = NULL;
116    apr_file_t *filetest;
117
118    rv = apr_file_open(&filetest, FILENAME, APR_FOPEN_READ, APR_OS_DEFAULT, p);
119    APR_ASSERT_SUCCESS(tc, "Opening test file " FILENAME, rv);
120
121    rv = apr_file_read(filetest, str, &nbytes);
122    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
123    ABTS_SIZE_EQUAL(tc, 0, nbytes);
124
125    apr_file_close(filetest);
126}
127
128static void test_filename(abts_case *tc, void *data)
129{
130    const char *str;
131    apr_status_t rv;
132    apr_file_t *filetest = NULL;
133
134    rv = apr_file_open(&filetest, FILENAME,
135                       APR_FOPEN_READ,
136                       APR_UREAD | APR_UWRITE | APR_GREAD, p);
137    APR_ASSERT_SUCCESS(tc, "Opening test file " FILENAME, rv);
138
139    rv = apr_file_name_get(&str, filetest);
140    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
141    ABTS_STR_EQUAL(tc, FILENAME, str);
142
143    apr_file_close(filetest);
144}
145
146static void test_fileclose(abts_case *tc, void *data)
147{
148    char str;
149    apr_status_t rv;
150    apr_size_t one = 1;
151    apr_file_t *filetest = NULL;
152
153    rv = apr_file_open(&filetest, FILENAME,
154                       APR_FOPEN_READ,
155                       APR_UREAD | APR_UWRITE | APR_GREAD, p);
156    APR_ASSERT_SUCCESS(tc, "Opening test file " FILENAME, rv);
157
158    rv = apr_file_close(filetest);
159    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
160    /* We just closed the file, so this should fail */
161    rv = apr_file_read(filetest, &str, &one);
162    ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_EBADF(rv));
163}
164
165static void test_file_remove(abts_case *tc, void *data)
166{
167    apr_status_t rv;
168    apr_file_t *filetest = NULL;
169
170    rv = apr_file_remove(FILENAME, p);
171    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
172
173    rv = apr_file_open(&filetest, FILENAME, APR_FOPEN_READ,
174                       APR_UREAD | APR_UWRITE | APR_GREAD, p);
175    ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_ENOENT(rv));
176}
177
178static void test_open_write(abts_case *tc, void *data)
179{
180    apr_status_t rv;
181    apr_file_t *filetest = NULL;
182
183    filetest = NULL;
184    rv = apr_file_open(&filetest, FILENAME,
185                       APR_FOPEN_WRITE,
186                       APR_UREAD | APR_UWRITE | APR_GREAD, p);
187    ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_ENOENT(rv));
188    ABTS_PTR_EQUAL(tc, NULL, filetest);
189}
190
191static void test_open_writecreate(abts_case *tc, void *data)
192{
193    apr_status_t rv;
194    apr_file_t *filetest = NULL;
195
196    filetest = NULL;
197    rv = apr_file_open(&filetest, FILENAME,
198                       APR_FOPEN_WRITE | APR_FOPEN_CREATE,
199                       APR_UREAD | APR_UWRITE | APR_GREAD, p);
200    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
201
202    apr_file_close(filetest);
203}
204
205static void test_write(abts_case *tc, void *data)
206{
207    apr_status_t rv;
208    apr_size_t bytes = strlen(TESTSTR);
209    apr_file_t *filetest = NULL;
210
211    rv = apr_file_open(&filetest, FILENAME,
212                       APR_FOPEN_WRITE | APR_FOPEN_CREATE,
213                       APR_UREAD | APR_UWRITE | APR_GREAD, p);
214    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
215
216    rv = apr_file_write(filetest, TESTSTR, &bytes);
217    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
218
219    apr_file_close(filetest);
220}
221
222static void test_open_readwrite(abts_case *tc, void *data)
223{
224    apr_status_t rv;
225    apr_file_t *filetest = NULL;
226
227    filetest = NULL;
228    rv = apr_file_open(&filetest, FILENAME,
229                       APR_FOPEN_READ | APR_FOPEN_WRITE,
230                       APR_UREAD | APR_UWRITE | APR_GREAD, p);
231    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
232    ABTS_PTR_NOTNULL(tc, filetest);
233
234    apr_file_close(filetest);
235}
236
237static void test_seek(abts_case *tc, void *data)
238{
239    apr_status_t rv;
240    apr_off_t offset = 5;
241    apr_size_t nbytes = 256;
242    char *str = apr_pcalloc(p, nbytes + 1);
243    apr_file_t *filetest = NULL;
244
245    rv = apr_file_open(&filetest, FILENAME,
246                       APR_FOPEN_READ,
247                       APR_UREAD | APR_UWRITE | APR_GREAD, p);
248    APR_ASSERT_SUCCESS(tc, "Open test file " FILENAME, rv);
249
250    rv = apr_file_read(filetest, str, &nbytes);
251    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
252    ABTS_SIZE_EQUAL(tc, strlen(TESTSTR), nbytes);
253    ABTS_STR_EQUAL(tc, TESTSTR, str);
254
255    memset(str, 0, nbytes + 1);
256
257    rv = apr_file_seek(filetest, SEEK_SET, &offset);
258    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
259
260    rv = apr_file_read(filetest, str, &nbytes);
261    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
262    ABTS_SIZE_EQUAL(tc, strlen(TESTSTR) - 5, nbytes);
263    ABTS_STR_EQUAL(tc, TESTSTR + 5, str);
264
265    apr_file_close(filetest);
266
267    /* Test for regression of sign error bug with SEEK_END and
268       buffered files. */
269    rv = apr_file_open(&filetest, FILENAME,
270                       APR_FOPEN_READ | APR_FOPEN_BUFFERED,
271                       APR_UREAD | APR_UWRITE | APR_GREAD, p);
272    APR_ASSERT_SUCCESS(tc, "Open test file " FILENAME, rv);
273
274    offset = -5;
275    rv = apr_file_seek(filetest, SEEK_END, &offset);
276    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
277    ABTS_SIZE_EQUAL(tc, strlen(TESTSTR) - 5, nbytes);
278
279    memset(str, 0, nbytes + 1);
280    nbytes = 256;
281    rv = apr_file_read(filetest, str, &nbytes);
282    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
283    ABTS_SIZE_EQUAL(tc, 5, nbytes);
284    ABTS_STR_EQUAL(tc, TESTSTR + strlen(TESTSTR) - 5, str);
285
286    apr_file_close(filetest);
287}
288
289static void test_userdata_set(abts_case *tc, void *data)
290{
291    apr_status_t rv;
292    apr_file_t *filetest = NULL;
293
294    rv = apr_file_open(&filetest, FILENAME,
295                       APR_FOPEN_WRITE,
296                       APR_UREAD | APR_UWRITE | APR_GREAD, p);
297    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
298
299    rv = apr_file_data_set(filetest, "This is a test",
300                           "test", apr_pool_cleanup_null);
301    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
302    apr_file_close(filetest);
303}
304
305static void test_userdata_get(abts_case *tc, void *data)
306{
307    apr_status_t rv;
308    void *udata;
309    char *teststr;
310    apr_file_t *filetest = NULL;
311
312    rv = apr_file_open(&filetest, FILENAME,
313                       APR_FOPEN_WRITE,
314                       APR_UREAD | APR_UWRITE | APR_GREAD, p);
315    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
316
317    rv = apr_file_data_set(filetest, "This is a test",
318                           "test", apr_pool_cleanup_null);
319    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
320
321    rv = apr_file_data_get(&udata, "test", filetest);
322    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
323    teststr = udata;
324    ABTS_STR_EQUAL(tc, "This is a test", teststr);
325
326    apr_file_close(filetest);
327}
328
329static void test_userdata_getnokey(abts_case *tc, void *data)
330{
331    apr_status_t rv;
332    void *teststr;
333    apr_file_t *filetest = NULL;
334
335    rv = apr_file_open(&filetest, FILENAME,
336                       APR_FOPEN_WRITE,
337                       APR_UREAD | APR_UWRITE | APR_GREAD, p);
338    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
339
340    rv = apr_file_data_get(&teststr, "nokey", filetest);
341    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
342    ABTS_PTR_EQUAL(tc, NULL, teststr);
343    apr_file_close(filetest);
344}
345
346static void test_buffer_set_get(abts_case *tc, void *data)
347{
348    apr_status_t rv;
349    apr_size_t bufsize;
350    apr_file_t *filetest = NULL;
351    char   * buffer;
352
353    rv = apr_file_open(&filetest, FILENAME,
354                       APR_FOPEN_WRITE | APR_FOPEN_BUFFERED,
355                       APR_UREAD | APR_UWRITE | APR_GREAD, p);
356    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
357
358    bufsize = apr_file_buffer_size_get(filetest);
359    ABTS_SIZE_EQUAL(tc, APR_BUFFERSIZE, bufsize);
360
361    buffer = apr_pcalloc(p, 10240);
362    rv = apr_file_buffer_set(filetest, buffer, 10240);
363    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
364
365    bufsize = apr_file_buffer_size_get(filetest);
366    ABTS_SIZE_EQUAL(tc, 10240, bufsize);
367
368    rv = apr_file_buffer_set(filetest, buffer, 12);
369    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
370
371    bufsize = apr_file_buffer_size_get(filetest);
372    ABTS_SIZE_EQUAL(tc, 12, bufsize);
373
374    apr_file_close(filetest);
375}
376static void test_getc(abts_case *tc, void *data)
377{
378    apr_file_t *f = NULL;
379    apr_status_t rv;
380    char ch;
381
382    rv = apr_file_open(&f, FILENAME, APR_FOPEN_READ, 0, p);
383    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
384
385    apr_file_getc(&ch, f);
386    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
387    ABTS_INT_EQUAL(tc, (int)TESTSTR[0], (int)ch);
388    apr_file_close(f);
389}
390
391static void test_ungetc(abts_case *tc, void *data)
392{
393    apr_file_t *f = NULL;
394    apr_status_t rv;
395    char ch;
396
397    rv = apr_file_open(&f, FILENAME, APR_FOPEN_READ, 0, p);
398    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
399
400    apr_file_getc(&ch, f);
401    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
402    ABTS_INT_EQUAL(tc, (int)TESTSTR[0], (int)ch);
403
404    apr_file_ungetc('X', f);
405    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
406
407    apr_file_getc(&ch, f);
408    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
409    ABTS_INT_EQUAL(tc, 'X', (int)ch);
410
411    apr_file_close(f);
412}
413
414static void test_gets(abts_case *tc, void *data)
415{
416    apr_file_t *f = NULL;
417    apr_status_t rv;
418    char *str = apr_palloc(p, 256);
419
420    rv = apr_file_open(&f, FILENAME, APR_FOPEN_READ, 0, p);
421    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
422
423    rv = apr_file_gets(str, 256, f);
424    /* Only one line in the test file, so APR will encounter EOF on the first
425     * call to gets, but we should get APR_SUCCESS on this call and
426     * APR_EOF on the next.
427     */
428    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
429    ABTS_STR_EQUAL(tc, TESTSTR, str);
430    rv = apr_file_gets(str, 256, f);
431    ABTS_INT_EQUAL(tc, APR_EOF, rv);
432    ABTS_STR_EQUAL(tc, "", str);
433    apr_file_close(f);
434}
435
436static void test_gets_buffered(abts_case *tc, void *data)
437{
438    apr_file_t *f = NULL;
439    apr_status_t rv;
440    char *str = apr_palloc(p, 256);
441
442    /* This will deadlock gets before the r524355 fix. */
443    rv = apr_file_open(&f, FILENAME, APR_FOPEN_READ|APR_FOPEN_BUFFERED|APR_FOPEN_XTHREAD, 0, p);
444    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
445
446    rv = apr_file_gets(str, 256, f);
447    /* Only one line in the test file, so APR will encounter EOF on the first
448     * call to gets, but we should get APR_SUCCESS on this call and
449     * APR_EOF on the next.
450     */
451    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
452    ABTS_STR_EQUAL(tc, TESTSTR, str);
453    rv = apr_file_gets(str, 256, f);
454    ABTS_INT_EQUAL(tc, APR_EOF, rv);
455    ABTS_STR_EQUAL(tc, "", str);
456    apr_file_close(f);
457}
458
459static void test_bigread(abts_case *tc, void *data)
460{
461    apr_file_t *f = NULL;
462    apr_status_t rv;
463    char buf[APR_BUFFERSIZE * 2];
464    apr_size_t nbytes;
465
466    /* Create a test file with known content.
467     */
468    rv = apr_file_open(&f, "data/created_file",
469                       APR_FOPEN_CREATE | APR_FOPEN_WRITE | APR_FOPEN_TRUNCATE,
470                       APR_UREAD | APR_UWRITE, p);
471    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
472
473    nbytes = APR_BUFFERSIZE;
474    memset(buf, 0xFE, nbytes);
475
476    rv = apr_file_write(f, buf, &nbytes);
477    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
478    ABTS_SIZE_EQUAL(tc, APR_BUFFERSIZE, nbytes);
479
480    rv = apr_file_close(f);
481    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
482
483    f = NULL;
484    rv = apr_file_open(&f, "data/created_file", APR_FOPEN_READ, 0, p);
485    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
486
487    nbytes = sizeof buf;
488    rv = apr_file_read(f, buf, &nbytes);
489    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
490    ABTS_SIZE_EQUAL(tc, APR_BUFFERSIZE, nbytes);
491
492    rv = apr_file_close(f);
493    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
494
495    rv = apr_file_remove("data/created_file", p);
496    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
497}
498
499/* This is a horrible name for this function.  We are testing APR, not how
500 * Apache uses APR.  And, this function tests _way_ too much stuff.
501 */
502static void test_mod_neg(abts_case *tc, void *data)
503{
504    apr_status_t rv;
505    apr_file_t *f;
506    const char *s;
507    int i;
508    apr_size_t nbytes;
509    char buf[8192];
510    apr_off_t cur;
511    const char *fname = "data/modneg.dat";
512
513    rv = apr_file_open(&f, fname,
514                       APR_FOPEN_CREATE | APR_FOPEN_WRITE, APR_UREAD | APR_UWRITE, p);
515    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
516
517    s = "body56789\n";
518    nbytes = strlen(s);
519    rv = apr_file_write(f, s, &nbytes);
520    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
521    ABTS_SIZE_EQUAL(tc, strlen(s), nbytes);
522
523    for (i = 0; i < 7980; i++) {
524        s = "0";
525        nbytes = strlen(s);
526        rv = apr_file_write(f, s, &nbytes);
527        ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
528        ABTS_SIZE_EQUAL(tc, strlen(s), nbytes);
529    }
530
531    s = "end456789\n";
532    nbytes = strlen(s);
533    rv = apr_file_write(f, s, &nbytes);
534    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
535    ABTS_SIZE_EQUAL(tc, strlen(s), nbytes);
536
537    for (i = 0; i < 10000; i++) {
538        s = "1";
539        nbytes = strlen(s);
540        rv = apr_file_write(f, s, &nbytes);
541        ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
542        ABTS_SIZE_EQUAL(tc, strlen(s), nbytes);
543    }
544
545    rv = apr_file_close(f);
546    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
547
548    rv = apr_file_open(&f, fname, APR_FOPEN_READ, 0, p);
549    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
550
551    rv = apr_file_gets(buf, 11, f);
552    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
553    ABTS_STR_EQUAL(tc, "body56789\n", buf);
554
555    cur = 0;
556    rv = apr_file_seek(f, APR_CUR, &cur);
557    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
558    ABTS_ASSERT(tc, "File Pointer Mismatch, expected 10", cur == 10);
559
560    nbytes = sizeof(buf);
561    rv = apr_file_read(f, buf, &nbytes);
562    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
563    ABTS_SIZE_EQUAL(tc, nbytes, sizeof(buf));
564
565    cur = -((apr_off_t)nbytes - 7980);
566    rv = apr_file_seek(f, APR_CUR, &cur);
567    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
568    ABTS_ASSERT(tc, "File Pointer Mismatch, expected 7990", cur == 7990);
569
570    rv = apr_file_gets(buf, 11, f);
571    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
572    ABTS_STR_EQUAL(tc, "end456789\n", buf);
573
574    rv = apr_file_close(f);
575    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
576
577    rv = apr_file_remove(fname, p);
578    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
579}
580
581/* Test that the contents of file FNAME are equal to data EXPECT of
582 * length EXPECTLEN. */
583static void file_contents_equal(abts_case *tc,
584                                const char *fname,
585                                const void *expect,
586                                apr_size_t expectlen)
587{
588    void *actual = apr_palloc(p, expectlen);
589    apr_file_t *f;
590
591    APR_ASSERT_SUCCESS(tc, "open file",
592                       apr_file_open(&f, fname, APR_FOPEN_READ|APR_FOPEN_BUFFERED,
593                                     0, p));
594    APR_ASSERT_SUCCESS(tc, "read from file",
595                       apr_file_read_full(f, actual, expectlen, NULL));
596
597    ABTS_ASSERT(tc, "matched expected file contents",
598                memcmp(expect, actual, expectlen) == 0);
599
600    APR_ASSERT_SUCCESS(tc, "close file", apr_file_close(f));
601}
602
603#define LINE1 "this is a line of text\n"
604#define LINE2 "this is a second line of text\n"
605
606static void test_puts(abts_case *tc, void *data)
607{
608    apr_file_t *f;
609    const char *fname = "data/testputs.txt";
610
611    APR_ASSERT_SUCCESS(tc, "open file for writing",
612                       apr_file_open(&f, fname,
613                                     APR_FOPEN_WRITE|APR_FOPEN_CREATE|APR_FOPEN_TRUNCATE,
614                                     APR_OS_DEFAULT, p));
615
616    APR_ASSERT_SUCCESS(tc, "write line to file",
617                       apr_file_puts(LINE1, f));
618    APR_ASSERT_SUCCESS(tc, "write second line to file",
619                       apr_file_puts(LINE2, f));
620
621    APR_ASSERT_SUCCESS(tc, "close for writing",
622                       apr_file_close(f));
623
624    file_contents_equal(tc, fname, LINE1 LINE2, strlen(LINE1 LINE2));
625}
626
627static void test_writev(abts_case *tc, void *data)
628{
629    apr_file_t *f;
630    apr_size_t nbytes;
631    struct iovec vec[5];
632    const char *fname = "data/testwritev.txt";
633
634    APR_ASSERT_SUCCESS(tc, "open file for writing",
635                       apr_file_open(&f, fname,
636                                     APR_FOPEN_WRITE|APR_FOPEN_CREATE|APR_FOPEN_TRUNCATE,
637                                     APR_OS_DEFAULT, p));
638
639    vec[0].iov_base = LINE1;
640    vec[0].iov_len = strlen(LINE1);
641
642    APR_ASSERT_SUCCESS(tc, "writev of size 1 to file",
643                       apr_file_writev(f, vec, 1, &nbytes));
644
645    file_contents_equal(tc, fname, LINE1, strlen(LINE1));
646
647    vec[0].iov_base = LINE1;
648    vec[0].iov_len = strlen(LINE1);
649    vec[1].iov_base = LINE2;
650    vec[1].iov_len = strlen(LINE2);
651    vec[2].iov_base = LINE1;
652    vec[2].iov_len = strlen(LINE1);
653    vec[3].iov_base = LINE1;
654    vec[3].iov_len = strlen(LINE1);
655    vec[4].iov_base = LINE2;
656    vec[4].iov_len = strlen(LINE2);
657
658    APR_ASSERT_SUCCESS(tc, "writev of size 5 to file",
659                       apr_file_writev(f, vec, 5, &nbytes));
660
661    APR_ASSERT_SUCCESS(tc, "close for writing",
662                       apr_file_close(f));
663
664    file_contents_equal(tc, fname, LINE1 LINE1 LINE2 LINE1 LINE1 LINE2,
665                        strlen(LINE1)*4 + strlen(LINE2)*2);
666
667}
668
669static void test_writev_full(abts_case *tc, void *data)
670{
671    apr_file_t *f;
672    apr_size_t nbytes;
673    struct iovec vec[5];
674    const char *fname = "data/testwritev_full.txt";
675
676    APR_ASSERT_SUCCESS(tc, "open file for writing",
677                       apr_file_open(&f, fname,
678                                     APR_FOPEN_WRITE|APR_FOPEN_CREATE|APR_FOPEN_TRUNCATE,
679                                     APR_OS_DEFAULT, p));
680
681    vec[0].iov_base = LINE1;
682    vec[0].iov_len = strlen(LINE1);
683    vec[1].iov_base = LINE2;
684    vec[1].iov_len = strlen(LINE2);
685    vec[2].iov_base = LINE1;
686    vec[2].iov_len = strlen(LINE1);
687    vec[3].iov_base = LINE1;
688    vec[3].iov_len = strlen(LINE1);
689    vec[4].iov_base = LINE2;
690    vec[4].iov_len = strlen(LINE2);
691
692    APR_ASSERT_SUCCESS(tc, "writev_full of size 5 to file",
693                       apr_file_writev_full(f, vec, 5, &nbytes));
694
695    ABTS_SIZE_EQUAL(tc, strlen(LINE1)*3 + strlen(LINE2)*2, nbytes);
696
697    APR_ASSERT_SUCCESS(tc, "close for writing",
698                       apr_file_close(f));
699
700    file_contents_equal(tc, fname, LINE1 LINE2 LINE1 LINE1 LINE2,
701                        strlen(LINE1)*3 + strlen(LINE2)*2);
702
703}
704
705static void test_writev_buffered(abts_case *tc, void *data)
706{
707    apr_file_t *f;
708    apr_size_t nbytes;
709    struct iovec vec[2];
710    const char *fname = "data/testwritev_buffered.dat";
711
712    APR_ASSERT_SUCCESS(tc, "open file for writing",
713                       apr_file_open(&f, fname,
714                                     APR_FOPEN_WRITE | APR_FOPEN_CREATE | APR_FOPEN_TRUNCATE |
715                                     APR_FOPEN_BUFFERED, APR_OS_DEFAULT, p));
716
717    nbytes = strlen(TESTSTR);
718    APR_ASSERT_SUCCESS(tc, "buffered write",
719                       apr_file_write(f, TESTSTR, &nbytes));
720
721    vec[0].iov_base = LINE1;
722    vec[0].iov_len = strlen(LINE1);
723    vec[1].iov_base = LINE2;
724    vec[1].iov_len = strlen(LINE2);
725
726    APR_ASSERT_SUCCESS(tc, "writev of size 2 to file",
727                       apr_file_writev(f, vec, 2, &nbytes));
728
729    APR_ASSERT_SUCCESS(tc, "close for writing",
730                       apr_file_close(f));
731
732    file_contents_equal(tc, fname, TESTSTR LINE1 LINE2,
733                        strlen(TESTSTR) + strlen(LINE1) + strlen(LINE2));
734}
735
736static void test_writev_buffered_seek(abts_case *tc, void *data)
737{
738    apr_file_t *f;
739    apr_status_t rv;
740    apr_off_t off = 0;
741    struct iovec vec[3];
742    apr_size_t nbytes = strlen(TESTSTR);
743    char *str = apr_pcalloc(p, nbytes+1);
744    const char *fname = "data/testwritev_buffered.dat";
745
746    APR_ASSERT_SUCCESS(tc, "open file for writing",
747                       apr_file_open(&f, fname,
748                                     APR_FOPEN_WRITE | APR_FOPEN_READ | APR_FOPEN_BUFFERED,
749                                     APR_OS_DEFAULT, p));
750
751    rv = apr_file_read(f, str, &nbytes);
752    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
753    ABTS_STR_EQUAL(tc, TESTSTR, str);
754    APR_ASSERT_SUCCESS(tc, "buffered seek", apr_file_seek(f, APR_SET, &off));
755
756    vec[0].iov_base = LINE1;
757    vec[0].iov_len = strlen(LINE1);
758    vec[1].iov_base = LINE2;
759    vec[1].iov_len = strlen(LINE2);
760    vec[2].iov_base = TESTSTR;
761    vec[2].iov_len = strlen(TESTSTR);
762
763    APR_ASSERT_SUCCESS(tc, "writev of size 2 to file",
764                       apr_file_writev(f, vec, 3, &nbytes));
765
766    APR_ASSERT_SUCCESS(tc, "close for writing",
767                       apr_file_close(f));
768
769    file_contents_equal(tc, fname, LINE1 LINE2 TESTSTR,
770                        strlen(LINE1) + strlen(LINE2) + strlen(TESTSTR));
771
772    APR_ASSERT_SUCCESS(tc, "remove file", apr_file_remove(fname, p));
773}
774
775static void test_truncate(abts_case *tc, void *data)
776{
777    apr_status_t rv;
778    apr_file_t *f;
779    const char *fname = "data/testtruncate.dat";
780    const char *s;
781    apr_size_t nbytes;
782    apr_finfo_t finfo;
783
784    apr_file_remove(fname, p);
785
786    rv = apr_file_open(&f, fname,
787                       APR_FOPEN_CREATE | APR_FOPEN_WRITE, APR_UREAD | APR_UWRITE, p);
788    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
789
790    s = "some data";
791    nbytes = strlen(s);
792    rv = apr_file_write(f, s, &nbytes);
793    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
794    ABTS_SIZE_EQUAL(tc, strlen(s), nbytes);
795
796    rv = apr_file_close(f);
797    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
798
799    rv = apr_file_open(&f, fname,
800                       APR_FOPEN_TRUNCATE | APR_FOPEN_WRITE, APR_UREAD | APR_UWRITE, p);
801    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
802
803    rv = apr_file_close(f);
804    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
805
806    rv = apr_stat(&finfo, fname, APR_FINFO_SIZE, p);
807    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
808    ABTS_ASSERT(tc, "File size mismatch, expected 0 (empty)", finfo.size == 0);
809
810    rv = apr_file_remove(fname, p);
811    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
812}
813
814static void test_bigfprintf(abts_case *tc, void *data)
815{
816    apr_file_t *f;
817    const char *fname = "data/testbigfprintf.dat";
818    char *to_write;
819    int i;
820
821    apr_file_remove(fname, p);
822
823    APR_ASSERT_SUCCESS(tc, "open test file",
824                       apr_file_open(&f, fname,
825                                     APR_FOPEN_CREATE|APR_FOPEN_WRITE,
826                                     APR_UREAD|APR_UWRITE, p));
827
828
829    to_write = malloc(HUGE_STRING_LEN + 3);
830
831    for (i = 0; i < HUGE_STRING_LEN + 1; ++i)
832        to_write[i] = 'A' + i%26;
833
834    strcpy(to_write + HUGE_STRING_LEN, "42");
835
836    i = apr_file_printf(f, "%s", to_write);
837    ABTS_INT_EQUAL(tc, HUGE_STRING_LEN + 2, i);
838
839    apr_file_close(f);
840
841    file_contents_equal(tc, fname, to_write, HUGE_STRING_LEN + 2);
842
843    free(to_write);
844}
845
846static void test_fail_write_flush(abts_case *tc, void *data)
847{
848    apr_file_t *f;
849    const char *fname = "data/testflush.dat";
850    apr_status_t rv;
851    char buf[APR_BUFFERSIZE];
852    int n;
853
854    apr_file_remove(fname, p);
855
856    APR_ASSERT_SUCCESS(tc, "open test file",
857                       apr_file_open(&f, fname,
858                                     APR_FOPEN_CREATE|APR_FOPEN_READ|APR_FOPEN_BUFFERED,
859                                     APR_UREAD|APR_UWRITE, p));
860
861    memset(buf, 'A', sizeof buf);
862
863    /* Try three writes.  One of these should fail when it exceeds the
864     * internal buffer and actually tries to write to the file, which
865     * was opened read-only and hence should be unwritable. */
866    for (n = 0, rv = APR_SUCCESS; n < 4 && rv == APR_SUCCESS; n++) {
867        apr_size_t bytes = sizeof buf;
868        rv = apr_file_write(f, buf, &bytes);
869    }
870
871    ABTS_ASSERT(tc, "failed to write to read-only buffered fd",
872                rv != APR_SUCCESS);
873
874    apr_file_close(f);
875}
876
877static void test_fail_read_flush(abts_case *tc, void *data)
878{
879    apr_file_t *f;
880    const char *fname = "data/testflush.dat";
881    apr_status_t rv;
882    char buf[2];
883
884    apr_file_remove(fname, p);
885
886    APR_ASSERT_SUCCESS(tc, "open test file",
887                       apr_file_open(&f, fname,
888                                     APR_FOPEN_CREATE|APR_FOPEN_READ|APR_FOPEN_BUFFERED,
889                                     APR_UREAD|APR_UWRITE, p));
890
891    /* this write should be buffered. */
892    APR_ASSERT_SUCCESS(tc, "buffered write should succeed",
893                       apr_file_puts("hello", f));
894
895    /* Now, trying a read should fail since the write must be flushed,
896     * and should fail with something other than EOF since the file is
897     * opened read-only. */
898    rv = apr_file_read_full(f, buf, 2, NULL);
899
900    ABTS_ASSERT(tc, "read should flush buffered write and fail",
901                rv != APR_SUCCESS && rv != APR_EOF);
902
903    /* Likewise for gets */
904    rv = apr_file_gets(buf, 2, f);
905
906    ABTS_ASSERT(tc, "gets should flush buffered write and fail",
907                rv != APR_SUCCESS && rv != APR_EOF);
908
909    /* Likewise for seek. */
910    {
911        apr_off_t offset = 0;
912
913        rv = apr_file_seek(f, APR_SET, &offset);
914    }
915
916    ABTS_ASSERT(tc, "seek should flush buffered write and fail",
917                rv != APR_SUCCESS && rv != APR_EOF);
918
919    apr_file_close(f);
920}
921
922static void test_xthread(abts_case *tc, void *data)
923{
924    apr_file_t *f;
925    const char *fname = "data/testxthread.dat";
926    apr_status_t rv;
927    apr_int32_t flags = APR_FOPEN_CREATE|APR_FOPEN_READ|APR_FOPEN_WRITE|APR_FOPEN_APPEND|APR_FOPEN_XTHREAD;
928    char buf[128] = { 0 };
929
930    /* Test for bug 38438, opening file with append + xthread and seeking to
931       the end of the file resulted in writes going to the beginning not the
932       end. */
933
934    apr_file_remove(fname, p);
935
936    APR_ASSERT_SUCCESS(tc, "open test file",
937                       apr_file_open(&f, fname, flags,
938                                     APR_UREAD|APR_UWRITE, p));
939
940    APR_ASSERT_SUCCESS(tc, "write should succeed",
941                       apr_file_puts("hello", f));
942
943    apr_file_close(f);
944
945    APR_ASSERT_SUCCESS(tc, "open test file",
946                       apr_file_open(&f, fname, flags,
947                                     APR_UREAD|APR_UWRITE, p));
948
949    /* Seek to the end. */
950    {
951        apr_off_t offset = 0;
952
953        rv = apr_file_seek(f, APR_END, &offset);
954        ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
955    }
956
957    APR_ASSERT_SUCCESS(tc, "more writes should succeed",
958                       apr_file_puts("world", f));
959
960    /* Back to the beginning. */
961    {
962        apr_off_t offset = 0;
963
964        rv = apr_file_seek(f, APR_SET, &offset);
965        ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
966    }
967
968    apr_file_read_full(f, buf, sizeof(buf), NULL);
969
970    ABTS_STR_EQUAL(tc, "helloworld", buf);
971
972    apr_file_close(f);
973}
974
975abts_suite *testfile(abts_suite *suite)
976{
977    suite = ADD_SUITE(suite)
978
979    abts_run_test(suite, test_open_noreadwrite, NULL);
980    abts_run_test(suite, test_open_excl, NULL);
981    abts_run_test(suite, test_open_read, NULL);
982    abts_run_test(suite, test_open_readwrite, NULL);
983    abts_run_test(suite, link_existing, NULL);
984    abts_run_test(suite, link_nonexisting, NULL);
985    abts_run_test(suite, test_read, NULL);
986    abts_run_test(suite, test_readzero, NULL);
987    abts_run_test(suite, test_seek, NULL);
988    abts_run_test(suite, test_filename, NULL);
989    abts_run_test(suite, test_fileclose, NULL);
990    abts_run_test(suite, test_file_remove, NULL);
991    abts_run_test(suite, test_open_write, NULL);
992    abts_run_test(suite, test_open_writecreate, NULL);
993    abts_run_test(suite, test_write, NULL);
994    abts_run_test(suite, test_userdata_set, NULL);
995    abts_run_test(suite, test_userdata_get, NULL);
996    abts_run_test(suite, test_userdata_getnokey, NULL);
997    abts_run_test(suite, test_getc, NULL);
998    abts_run_test(suite, test_ungetc, NULL);
999    abts_run_test(suite, test_gets, NULL);
1000    abts_run_test(suite, test_gets_buffered, NULL);
1001    abts_run_test(suite, test_puts, NULL);
1002    abts_run_test(suite, test_writev, NULL);
1003    abts_run_test(suite, test_writev_full, NULL);
1004    abts_run_test(suite, test_writev_buffered, NULL);
1005    abts_run_test(suite, test_writev_buffered_seek, NULL);
1006    abts_run_test(suite, test_bigread, NULL);
1007    abts_run_test(suite, test_mod_neg, NULL);
1008    abts_run_test(suite, test_truncate, NULL);
1009    abts_run_test(suite, test_bigfprintf, NULL);
1010    abts_run_test(suite, test_fail_write_flush, NULL);
1011    abts_run_test(suite, test_fail_read_flush, NULL);
1012    abts_run_test(suite, test_buffer_set_get, NULL);
1013    abts_run_test(suite, test_xthread, NULL);
1014
1015    return suite;
1016}
1017
1018