Coverage Report

Created: 2023-03-26 06:28

/src/httpd/srclib/apr/file_io/unix/filestat.c
Line
Count
Source (jump to first uncovered line)
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_arch_file_io.h"
18
#include "apr_file_io.h"
19
#include "apr_general.h"
20
#include "apr_strings.h"
21
#include "apr_errno.h"
22
23
#ifdef HAVE_UTIME
24
#include <utime.h>
25
#endif
26
27
static apr_filetype_e filetype_from_mode(mode_t mode)
28
1.26k
{
29
1.26k
    apr_filetype_e type;
30
31
1.26k
    switch (mode & S_IFMT) {
32
1.26k
    case S_IFREG:
33
1.26k
        type = APR_REG;  break;
34
0
    case S_IFDIR:
35
0
        type = APR_DIR;  break;
36
0
    case S_IFLNK:
37
0
        type = APR_LNK;  break;
38
0
    case S_IFCHR:
39
0
        type = APR_CHR;  break;
40
0
    case S_IFBLK:
41
0
        type = APR_BLK;  break;
42
#if defined(S_IFFIFO)
43
    case S_IFFIFO:
44
        type = APR_PIPE; break;
45
#endif
46
0
#if !defined(BEOS) && defined(S_IFSOCK)
47
0
    case S_IFSOCK:
48
0
        type = APR_SOCK; break;
49
0
#endif
50
51
0
    default:
52
  /* Work around missing S_IFxxx values above
53
         * for Linux et al.
54
         */
55
0
#if !defined(S_IFFIFO) && defined(S_ISFIFO)
56
0
      if (S_ISFIFO(mode)) {
57
0
            type = APR_PIPE;
58
0
  } else
59
0
#endif
60
#if !defined(BEOS) && !defined(S_IFSOCK) && defined(S_ISSOCK)
61
      if (S_ISSOCK(mode)) {
62
            type = APR_SOCK;
63
  } else
64
#endif
65
0
        type = APR_UNKFILE;
66
1.26k
    }
67
1.26k
    return type;
68
1.26k
}
69
70
static void fill_out_finfo(apr_finfo_t *finfo, struct_stat *info,
71
                           apr_int32_t wanted)
72
1.26k
{
73
1.26k
    finfo->valid = APR_FINFO_MIN | APR_FINFO_IDENT | APR_FINFO_NLINK
74
1.26k
                 | APR_FINFO_OWNER | APR_FINFO_PROT;
75
1.26k
    finfo->protection = apr_unix_mode2perms(info->st_mode);
76
1.26k
    finfo->filetype = filetype_from_mode(info->st_mode);
77
1.26k
    finfo->user = info->st_uid;
78
1.26k
    finfo->group = info->st_gid;
79
1.26k
    finfo->size = info->st_size;
80
1.26k
    finfo->device = info->st_dev;
81
1.26k
    finfo->nlink = info->st_nlink;
82
83
    /* Check for overflow if storing a 64-bit st_ino in a 32-bit
84
     * apr_ino_t for LFS builds: */
85
1.26k
    if (sizeof(apr_ino_t) >= sizeof(info->st_ino)
86
1.26k
        || (apr_ino_t)info->st_ino == info->st_ino) {
87
1.26k
        finfo->inode = info->st_ino;
88
1.26k
    } else {
89
0
        finfo->valid &= ~APR_FINFO_INODE;
90
0
    }
91
92
1.26k
    apr_time_ansi_put(&finfo->atime, info->st_atime);
93
1.26k
#ifdef HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC
94
1.26k
    finfo->atime += info->st_atim.tv_nsec / APR_TIME_C(1000);
95
#elif defined(HAVE_STRUCT_STAT_ST_ATIMENSEC)
96
    finfo->atime += info->st_atimensec / APR_TIME_C(1000);
97
#elif defined(HAVE_STRUCT_STAT_ST_ATIME_N)
98
    finfo->atime += info->st_atime_n / APR_TIME_C(1000);
99
#endif
100
101
1.26k
    apr_time_ansi_put(&finfo->mtime, info->st_mtime);
102
1.26k
#ifdef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC
103
1.26k
    finfo->mtime += info->st_mtim.tv_nsec / APR_TIME_C(1000);
104
#elif defined(HAVE_STRUCT_STAT_ST_MTIMENSEC)
105
    finfo->mtime += info->st_mtimensec / APR_TIME_C(1000);
106
#elif defined(HAVE_STRUCT_STAT_ST_MTIME_N)
107
    finfo->mtime += info->st_mtime_n / APR_TIME_C(1000);
108
#endif
109
110
1.26k
    apr_time_ansi_put(&finfo->ctime, info->st_ctime);
111
1.26k
#ifdef HAVE_STRUCT_STAT_ST_CTIM_TV_NSEC
112
1.26k
    finfo->ctime += info->st_ctim.tv_nsec / APR_TIME_C(1000);
113
#elif defined(HAVE_STRUCT_STAT_ST_CTIMENSEC)
114
    finfo->ctime += info->st_ctimensec / APR_TIME_C(1000);
115
#elif defined(HAVE_STRUCT_STAT_ST_CTIME_N)
116
    finfo->ctime += info->st_ctime_n / APR_TIME_C(1000);
117
#endif
118
119
1.26k
#ifdef HAVE_STRUCT_STAT_ST_BLOCKS
120
1.26k
#ifdef DEV_BSIZE
121
1.26k
    finfo->csize = (apr_off_t)info->st_blocks * (apr_off_t)DEV_BSIZE;
122
#else
123
    finfo->csize = (apr_off_t)info->st_blocks * (apr_off_t)512;
124
#endif
125
1.26k
    finfo->valid |= APR_FINFO_CSIZE;
126
1.26k
#endif
127
1.26k
}
128
129
apr_status_t apr_file_info_get_locked(apr_finfo_t *finfo, apr_int32_t wanted,
130
                                      apr_file_t *thefile)
131
0
{
132
0
    struct_stat info;
133
134
0
    if (thefile->buffered) {
135
0
        apr_status_t rv = apr_file_flush_locked(thefile);
136
0
        if (rv != APR_SUCCESS)
137
0
            return rv;
138
0
    }
139
140
0
    if (fstat(thefile->filedes, &info) == 0) {
141
0
        finfo->pool = thefile->pool;
142
0
        finfo->fname = thefile->fname;
143
0
        fill_out_finfo(finfo, &info, wanted);
144
0
        return (wanted & ~finfo->valid) ? APR_INCOMPLETE : APR_SUCCESS;
145
0
    }
146
0
    else {
147
0
        return errno;
148
0
    }
149
0
}
150
151
APR_DECLARE(apr_status_t) apr_file_info_get(apr_finfo_t *finfo,
152
                                            apr_int32_t wanted,
153
                                            apr_file_t *thefile)
154
1.26k
{
155
1.26k
    struct_stat info;
156
157
1.26k
    if (thefile->buffered) {
158
1.26k
        apr_status_t rv = apr_file_flush(thefile);
159
1.26k
        if (rv != APR_SUCCESS)
160
0
            return rv;
161
1.26k
    }
162
163
1.26k
    if (fstat(thefile->filedes, &info) == 0) {
164
1.26k
        finfo->pool = thefile->pool;
165
1.26k
        finfo->fname = thefile->fname;
166
1.26k
        fill_out_finfo(finfo, &info, wanted);
167
1.26k
        return (wanted & ~finfo->valid) ? APR_INCOMPLETE : APR_SUCCESS;
168
1.26k
    }
169
0
    else {
170
0
        return errno;
171
0
    }
172
1.26k
}
173
174
APR_DECLARE(apr_status_t) apr_file_perms_set(const char *fname,
175
                                             apr_fileperms_t perms)
176
0
{
177
0
    mode_t mode = apr_unix_perms2mode(perms);
178
179
0
    if (chmod(fname, mode) == -1)
180
0
        return errno;
181
0
    return APR_SUCCESS;
182
0
}
183
184
APR_DECLARE(apr_status_t) apr_file_attrs_set(const char *fname,
185
                                             apr_fileattrs_t attributes,
186
                                             apr_fileattrs_t attr_mask,
187
                                             apr_pool_t *pool)
188
0
{
189
0
    apr_status_t status;
190
0
    apr_finfo_t finfo;
191
192
    /* Don't do anything if we can't handle the requested attributes */
193
0
    if (!(attr_mask & (APR_FILE_ATTR_READONLY
194
0
                       | APR_FILE_ATTR_EXECUTABLE)))
195
0
        return APR_SUCCESS;
196
197
0
    status = apr_stat(&finfo, fname, APR_FINFO_PROT, pool);
198
0
    if (status)
199
0
        return status;
200
201
    /* ### TODO: should added bits be umask'd? */
202
0
    if (attr_mask & APR_FILE_ATTR_READONLY)
203
0
    {
204
0
        if (attributes & APR_FILE_ATTR_READONLY)
205
0
        {
206
0
            finfo.protection &= ~APR_FPROT_UWRITE;
207
0
            finfo.protection &= ~APR_FPROT_GWRITE;
208
0
            finfo.protection &= ~APR_FPROT_WWRITE;
209
0
        }
210
0
        else
211
0
        {
212
            /* ### umask this! */
213
0
            finfo.protection |= APR_FPROT_UWRITE;
214
0
            finfo.protection |= APR_FPROT_GWRITE;
215
0
            finfo.protection |= APR_FPROT_WWRITE;
216
0
        }
217
0
    }
218
219
0
    if (attr_mask & APR_FILE_ATTR_EXECUTABLE)
220
0
    {
221
0
        if (attributes & APR_FILE_ATTR_EXECUTABLE)
222
0
        {
223
            /* ### umask this! */
224
0
            finfo.protection |= APR_FPROT_UEXECUTE;
225
0
            finfo.protection |= APR_FPROT_GEXECUTE;
226
0
            finfo.protection |= APR_FPROT_WEXECUTE;
227
0
        }
228
0
        else
229
0
        {
230
0
            finfo.protection &= ~APR_FPROT_UEXECUTE;
231
0
            finfo.protection &= ~APR_FPROT_GEXECUTE;
232
0
            finfo.protection &= ~APR_FPROT_WEXECUTE;
233
0
        }
234
0
    }
235
236
0
    return apr_file_perms_set(fname, finfo.protection);
237
0
}
238
239
240
APR_DECLARE(apr_status_t) apr_file_mtime_set(const char *fname,
241
                                              apr_time_t mtime,
242
                                              apr_pool_t *pool)
243
0
{
244
0
    apr_status_t status;
245
0
    apr_finfo_t finfo;
246
247
0
    status = apr_stat(&finfo, fname, APR_FINFO_ATIME, pool);
248
0
    if (status) {
249
0
        return status;
250
0
    }
251
252
0
#ifdef HAVE_UTIMES
253
0
    {
254
0
      struct timeval tvp[2];
255
256
0
      tvp[0].tv_sec = apr_time_sec(finfo.atime);
257
0
      tvp[0].tv_usec = apr_time_usec(finfo.atime);
258
0
      tvp[1].tv_sec = apr_time_sec(mtime);
259
0
      tvp[1].tv_usec = apr_time_usec(mtime);
260
261
0
      if (utimes(fname, tvp) == -1) {
262
0
        return errno;
263
0
      }
264
0
    }
265
#elif defined(HAVE_UTIME)
266
    {
267
      struct utimbuf buf;
268
269
      buf.actime = (time_t) (finfo.atime / APR_USEC_PER_SEC);
270
      buf.modtime = (time_t) (mtime / APR_USEC_PER_SEC);
271
272
      if (utime(fname, &buf) == -1) {
273
        return errno;
274
      }
275
    }
276
#else
277
    return APR_ENOTIMPL;
278
#endif
279
280
0
    return APR_SUCCESS;
281
0
}
282
283
284
APR_DECLARE(apr_status_t) apr_stat(apr_finfo_t *finfo,
285
                                   const char *fname,
286
                                   apr_int32_t wanted, apr_pool_t *pool)
287
0
{
288
0
    struct_stat info;
289
0
    int srv;
290
291
0
    if (wanted & APR_FINFO_LINK)
292
0
        srv = lstat(fname, &info);
293
0
    else
294
0
        srv = stat(fname, &info);
295
296
0
    if (srv == 0) {
297
0
        finfo->pool = pool;
298
0
        finfo->fname = fname;
299
0
        fill_out_finfo(finfo, &info, wanted);
300
0
        if (wanted & APR_FINFO_LINK)
301
0
            wanted &= ~APR_FINFO_LINK;
302
0
        return (wanted & ~finfo->valid) ? APR_INCOMPLETE : APR_SUCCESS;
303
0
    }
304
0
    else {
305
#if !defined(ENOENT) || !defined(ENOTDIR)
306
#error ENOENT || ENOTDIR not defined; please see the
307
#error comments at this line in the source for a workaround.
308
        /*
309
         * If ENOENT || ENOTDIR is not defined in one of the your OS's
310
         * include files, APR cannot report a good reason why the stat()
311
         * of the file failed; there are cases where it can fail even though
312
         * the file exists.  This opens holes in Apache, for example, because
313
         * it becomes possible for someone to get a directory listing of a
314
         * directory even though there is an index (eg. index.html) file in
315
         * it.  If you do not have a problem with this, delete the above
316
         * #error lines and start the compile again.  If you need to do this,
317
         * please submit a bug report to http://www.apache.org/bug_report.html
318
         * letting us know that you needed to do this.  Please be sure to
319
         * include the operating system you are using.
320
         */
321
        /* WARNING: All errors will be handled as not found
322
         */
323
#if !defined(ENOENT)
324
        return APR_ENOENT;
325
#else
326
        /* WARNING: All errors but not found will be handled as not directory
327
         */
328
        if (errno != ENOENT)
329
            return APR_ENOENT;
330
        else
331
            return errno;
332
#endif
333
#else /* All was defined well, report the usual: */
334
0
        return errno;
335
0
#endif
336
0
    }
337
0
}
338
339