1
/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as
4
* Licensed under the Apache License, Version 2.0 (the "License");
5
* you may not use this file except in compliance with the License.
6
* 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(abts_case *tc, apr_finfo_t *f1, apr_finfo_t *f2)
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);
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));
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);
106
static void test_info_get(abts_case *tc, void *data)
112
rv = apr_file_open(&thefile, FILENAME, APR_READ, APR_OS_DEFAULT, p);
113
ABTS_INT_EQUAL(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
ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
128
apr_file_close(thefile);
131
static void test_stat(abts_case *tc, void *data)
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
ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
151
static void test_stat_eq_finfo(abts_case *tc, void *data)
155
apr_finfo_t stat_finfo;
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);
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
ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
169
apr_file_close(thefile);
171
finfo_equal(tc, &stat_finfo, &finfo);
174
static void test_buffered_write_size(abts_case *tc, void *data)
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
ABTS_TRUE(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
ABTS_TRUE(tc, bytes == (apr_size_t) finfo.size);
201
apr_file_close(thefile);
204
static void test_mtime_set(abts_case *tc, void *data)
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
ABTS_TRUE(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
ABTS_TRUE(tc, finfo.mtime == epoch);
248
apr_file_close(thefile);
251
abts_suite *testfileinfo(abts_suite *suite)
253
suite = ADD_SUITE(suite)
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);