Coverage Report

Created: 2023-03-26 06:28

/src/httpd/srclib/apr/file_io/unix/open.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_strings.h"
19
#include "apr_portable.h"
20
#include "apr_thread_mutex.h"
21
#include "apr_arch_inherit.h"
22
#include "apr_time.h"
23
24
#ifdef NETWARE
25
#include "nks/dirio.h"
26
#include "apr_hash.h"
27
#include "fsio.h"
28
#endif
29
30
static apr_status_t file_cleanup(apr_file_t *file, int is_child)
31
1.58k
{
32
1.58k
    apr_status_t rv = APR_SUCCESS;
33
1.58k
    int fd = file->filedes;
34
35
    /* Set file descriptor to -1 before close(), so that there is no
36
     * chance of returning an already closed FD from apr_os_file_get().
37
     */
38
1.58k
    file->filedes = -1;
39
40
1.58k
    if (close(fd) == 0) {
41
        /* Only the parent process should delete the file! */
42
1.58k
        if (!is_child && (file->flags & APR_FOPEN_DELONCLOSE)) {
43
0
            unlink(file->fname);
44
0
        }
45
1.58k
#if APR_HAS_THREADS
46
1.58k
        if (file->thlock) {
47
0
            rv = apr_thread_mutex_destroy(file->thlock);
48
0
        }
49
1.58k
#endif
50
1.58k
    }
51
0
    else {
52
        /* Restore, close() was not successful. */
53
0
        file->filedes = fd;
54
55
        /* Are there any error conditions other than EINTR or EBADF? */
56
0
        rv = errno;
57
0
    }
58
#ifndef WAITIO_USES_POLL
59
    if (file->pollset != NULL) {
60
        apr_status_t pollset_rv = apr_pollset_destroy(file->pollset);
61
        /* If the file close failed, return its error value,
62
         * not apr_pollset_destroy()'s.
63
         */
64
        if (rv == APR_SUCCESS) {
65
            rv = pollset_rv;
66
        }
67
    }
68
#endif /* !WAITIO_USES_POLL */
69
1.58k
    return rv;
70
1.58k
}
71
72
apr_status_t apr_unix_file_cleanup(void *thefile)
73
1.58k
{
74
1.58k
    apr_file_t *file = thefile;
75
1.58k
    apr_status_t flush_rv = APR_SUCCESS, rv = APR_SUCCESS;
76
77
1.58k
    if (file->buffered) {
78
1.26k
        flush_rv = apr_file_flush(file);
79
1.26k
    }
80
81
1.58k
    rv = file_cleanup(file, 0);
82
83
1.58k
    return rv != APR_SUCCESS ? rv : flush_rv;
84
1.58k
}
85
86
apr_status_t apr_unix_child_file_cleanup(void *thefile)
87
0
{
88
0
    return file_cleanup(thefile, 1);
89
0
}
90
91
APR_DECLARE(apr_status_t) apr_file_open(apr_file_t **new,
92
                                        const char *fname,
93
                                        apr_int32_t flag,
94
                                        apr_fileperms_t perm,
95
                                        apr_pool_t *pool)
96
1.26k
{
97
1.26k
    apr_os_file_t fd;
98
1.26k
    int oflags = 0;
99
1.26k
#if APR_HAS_THREADS
100
1.26k
    apr_thread_mutex_t *thlock = NULL;
101
1.26k
#endif
102
1.26k
    apr_status_t rv;
103
104
1.26k
    if ((flag & APR_FOPEN_READ) && (flag & APR_FOPEN_WRITE)) {
105
0
        oflags = O_RDWR;
106
0
    }
107
1.26k
    else if (flag & APR_FOPEN_READ) {
108
1.26k
        oflags = O_RDONLY;
109
1.26k
    }
110
0
    else if (flag & APR_FOPEN_WRITE) {
111
0
        oflags = O_WRONLY;
112
0
    }
113
0
    else {
114
0
        return APR_EACCES;
115
0
    }
116
117
1.26k
    if (flag & APR_FOPEN_CREATE) {
118
0
        oflags |= O_CREAT;
119
0
        if (flag & APR_FOPEN_EXCL) {
120
0
            oflags |= O_EXCL;
121
0
        }
122
0
    }
123
1.26k
    if ((flag & APR_FOPEN_EXCL) && !(flag & APR_FOPEN_CREATE)) {
124
0
        return APR_EACCES;
125
0
    }
126
127
1.26k
    if (flag & APR_FOPEN_APPEND) {
128
0
        oflags |= O_APPEND;
129
0
    }
130
1.26k
    if (flag & APR_FOPEN_TRUNCATE) {
131
0
        oflags |= O_TRUNC;
132
0
    }
133
#ifdef O_BINARY
134
    if (flag & APR_FOPEN_BINARY) {
135
        oflags |= O_BINARY;
136
    }
137
#endif
138
139
1.26k
    if (flag & APR_FOPEN_NONBLOCK) {
140
0
#ifdef O_NONBLOCK
141
0
        oflags |= O_NONBLOCK;
142
#else
143
        return APR_ENOTIMPL;
144
#endif
145
0
    }
146
147
1.26k
#ifdef O_CLOEXEC
148
    /* Introduced in Linux 2.6.23. Silently ignored on earlier Linux kernels.
149
     */
150
1.26k
    if (!(flag & APR_FOPEN_NOCLEANUP)) {
151
1.26k
        oflags |= O_CLOEXEC;
152
1.26k
}
153
1.26k
#endif
154
155
#if APR_HAS_LARGE_FILES && defined(_LARGEFILE64_SOURCE)
156
    oflags |= O_LARGEFILE;
157
#elif defined(O_LARGEFILE)
158
1.26k
    if (flag & APR_FOPEN_LARGEFILE) {
159
0
        oflags |= O_LARGEFILE;
160
0
    }
161
1.26k
#endif
162
163
1.26k
#if APR_HAS_THREADS
164
1.26k
    if ((flag & APR_FOPEN_BUFFERED) && (flag & APR_FOPEN_XTHREAD)) {
165
0
        rv = apr_thread_mutex_create(&thlock,
166
0
                                     APR_THREAD_MUTEX_DEFAULT, pool);
167
0
        if (rv) {
168
0
            return rv;
169
0
        }
170
0
    }
171
1.26k
#endif
172
173
1.26k
    if (perm == APR_FPROT_OS_DEFAULT) {
174
1.26k
        fd = open(fname, oflags, 0666);
175
1.26k
    }
176
0
    else {
177
0
        fd = open(fname, oflags, apr_unix_perms2mode(perm));
178
0
    }
179
1.26k
    if (fd < 0) {
180
0
       return errno;
181
0
    }
182
1.26k
    if (!(flag & APR_FOPEN_NOCLEANUP)) {
183
1.26k
#ifdef O_CLOEXEC
184
1.26k
        static int has_o_cloexec = 0;
185
1.26k
        if (!has_o_cloexec)
186
1
#endif
187
1
        {
188
1
            int flags;
189
190
1
            if ((flags = fcntl(fd, F_GETFD)) == -1) {
191
0
                close(fd);
192
0
                return errno;
193
0
            }
194
1
            if ((flags & FD_CLOEXEC) == 0) {
195
0
                flags |= FD_CLOEXEC;
196
0
                if (fcntl(fd, F_SETFD, flags) == -1) {
197
0
                    close(fd);
198
0
                    return errno;
199
0
                }
200
0
            }
201
1
#ifdef O_CLOEXEC
202
1
            else {
203
1
                has_o_cloexec = 1;
204
1
            }
205
1
#endif
206
1
        }
207
1.26k
    }
208
209
1.26k
    (*new) = (apr_file_t *)apr_pcalloc(pool, sizeof(apr_file_t));
210
1.26k
    (*new)->pool = pool;
211
1.26k
    (*new)->flags = flag;
212
1.26k
    (*new)->filedes = fd;
213
214
1.26k
    (*new)->fname = apr_pstrdup(pool, fname);
215
216
1.26k
    (*new)->blocking = BLK_ON;
217
1.26k
    (*new)->buffered = (flag & APR_FOPEN_BUFFERED) > 0;
218
219
1.26k
    if ((*new)->buffered) {
220
1.26k
        (*new)->buffer = apr_palloc(pool, APR_FILE_DEFAULT_BUFSIZE);
221
1.26k
        (*new)->bufsize = APR_FILE_DEFAULT_BUFSIZE;
222
1.26k
    }
223
0
    else {
224
0
        (*new)->buffer = NULL;
225
0
    }
226
227
1.26k
#if APR_HAS_THREADS
228
1.26k
    (*new)->thlock = thlock;
229
1.26k
#endif
230
231
1.26k
    (*new)->is_pipe = 0;
232
1.26k
    (*new)->timeout = -1;
233
1.26k
    (*new)->ungetchar = -1;
234
1.26k
    (*new)->eof_hit = 0;
235
1.26k
    (*new)->filePtr = 0;
236
1.26k
    (*new)->bufpos = 0;
237
1.26k
    (*new)->dataRead = 0;
238
1.26k
    (*new)->direction = 0;
239
#ifndef WAITIO_USES_POLL
240
    /* Start out with no pollset.  apr_wait_for_io_or_timeout() will
241
     * initialize the pollset if needed.
242
     */
243
    (*new)->pollset = NULL;
244
#endif
245
1.26k
    if (!(flag & APR_FOPEN_NOCLEANUP)) {
246
1.26k
        apr_pool_cleanup_register((*new)->pool, (void *)(*new),
247
1.26k
                                  apr_unix_file_cleanup,
248
1.26k
                                  apr_unix_child_file_cleanup);
249
1.26k
    }
250
251
1.26k
    if ((flag & APR_FOPEN_ROTATING) || (flag & APR_FOPEN_MANUAL_ROTATE)) {
252
0
        (*new)->rotating = (apr_rotating_info_t *)apr_pcalloc(pool,
253
0
                                                              sizeof(apr_rotating_info_t));
254
255
0
        rv =  apr_file_info_get(&(*new)->rotating->finfo,
256
0
                                APR_FINFO_DEV|APR_FINFO_INODE, *new);
257
0
        if (rv != APR_SUCCESS) {
258
0
            return rv;
259
0
        }
260
261
0
        if (flag & APR_FOPEN_MANUAL_ROTATE) {
262
0
            (*new)->rotating->manual = 1;
263
0
        }
264
0
        else {
265
0
            (*new)->rotating->manual = 0;
266
0
        }
267
0
        (*new)->rotating->timeout = 60;
268
0
        (*new)->rotating->lastcheck = apr_time_sec(apr_time_now());
269
0
        (*new)->rotating->oflags = oflags;
270
0
        (*new)->rotating->perm = perm;
271
0
    }
272
1.26k
    else {
273
1.26k
        (*new)->rotating = NULL;
274
1.26k
    }
275
276
1.26k
    return APR_SUCCESS;
277
1.26k
}
278
279
APR_DECLARE(apr_status_t) apr_file_close(apr_file_t *file)
280
0
{
281
0
    return apr_pool_cleanup_run(file->pool, file, apr_unix_file_cleanup);
282
0
}
283
284
APR_DECLARE(apr_status_t) apr_file_remove(const char *path, apr_pool_t *pool)
285
317
{
286
317
    if (unlink(path) == 0) {
287
317
        return APR_SUCCESS;
288
317
    }
289
0
    else {
290
0
        return errno;
291
0
    }
292
317
}
293
294
APR_DECLARE(apr_status_t) apr_file_rename(const char *from_path,
295
                                          const char *to_path,
296
                                          apr_pool_t *p)
297
0
{
298
0
    if (rename(from_path, to_path) != 0) {
299
0
        return errno;
300
0
    }
301
0
    return APR_SUCCESS;
302
0
}
303
304
APR_DECLARE(apr_status_t) apr_os_file_get(apr_os_file_t *thefile,
305
                                          apr_file_t *file)
306
0
{
307
0
    *thefile = file->filedes;
308
0
    return APR_SUCCESS;
309
0
}
310
311
APR_DECLARE(apr_status_t) apr_os_file_put(apr_file_t **file,
312
                                          apr_os_file_t *thefile,
313
                                          apr_int32_t flags, apr_pool_t *pool)
314
319
{
315
319
    int *dafile = thefile;
316
317
319
    (*file) = apr_pcalloc(pool, sizeof(apr_file_t));
318
319
    (*file)->pool = pool;
319
319
    (*file)->eof_hit = 0;
320
319
    (*file)->blocking = BLK_UNKNOWN; /* in case it is a pipe */
321
319
    (*file)->timeout = -1;
322
319
    (*file)->ungetchar = -1; /* no char avail */
323
319
    (*file)->filedes = *dafile;
324
319
    (*file)->flags = flags | APR_FOPEN_NOCLEANUP;
325
319
    (*file)->buffered = (flags & APR_FOPEN_BUFFERED) > 0;
326
327
#ifndef WAITIO_USES_POLL
328
    /* Start out with no pollset.  apr_wait_for_io_or_timeout() will
329
     * initialize the pollset if needed.
330
     */
331
    (*file)->pollset = NULL;
332
#endif
333
334
319
    if ((*file)->buffered) {
335
0
        (*file)->buffer = apr_palloc(pool, APR_FILE_DEFAULT_BUFSIZE);
336
0
        (*file)->bufsize = APR_FILE_DEFAULT_BUFSIZE;
337
0
#if APR_HAS_THREADS
338
0
        if ((*file)->flags & APR_FOPEN_XTHREAD) {
339
0
            apr_status_t rv;
340
0
            rv = apr_thread_mutex_create(&((*file)->thlock),
341
0
                                         APR_THREAD_MUTEX_DEFAULT, pool);
342
0
            if (rv) {
343
0
                return rv;
344
0
            }
345
0
        }
346
0
#endif
347
0
    }
348
319
    return APR_SUCCESS;
349
319
}
350
351
APR_DECLARE(apr_status_t) apr_file_eof(apr_file_t *fptr)
352
0
{
353
0
    if (fptr->eof_hit == 1) {
354
0
        return APR_EOF;
355
0
    }
356
0
    return APR_SUCCESS;
357
0
}
358
359
APR_DECLARE(apr_status_t) apr_file_open_flags_stderr(apr_file_t **thefile,
360
                                                     apr_int32_t flags,
361
                                                     apr_pool_t *pool)
362
2
{
363
2
    int fd = STDERR_FILENO;
364
365
2
    return apr_os_file_put(thefile, &fd, flags | APR_FOPEN_WRITE, pool);
366
2
}
367
368
APR_DECLARE(apr_status_t) apr_file_open_flags_stdout(apr_file_t **thefile,
369
                                                     apr_int32_t flags,
370
                                                     apr_pool_t *pool)
371
0
{
372
0
    int fd = STDOUT_FILENO;
373
374
0
    return apr_os_file_put(thefile, &fd, flags | APR_FOPEN_WRITE, pool);
375
0
}
376
377
APR_DECLARE(apr_status_t) apr_file_open_flags_stdin(apr_file_t **thefile,
378
                                                    apr_int32_t flags,
379
                                                    apr_pool_t *pool)
380
0
{
381
0
    int fd = STDIN_FILENO;
382
383
0
    return apr_os_file_put(thefile, &fd, flags | APR_FOPEN_READ, pool);
384
0
}
385
386
APR_DECLARE(apr_status_t) apr_file_open_stderr(apr_file_t **thefile,
387
                                               apr_pool_t *pool)
388
2
{
389
2
    return apr_file_open_flags_stderr(thefile, 0, pool);
390
2
}
391
392
APR_DECLARE(apr_status_t) apr_file_open_stdout(apr_file_t **thefile,
393
                                               apr_pool_t *pool)
394
0
{
395
0
    return apr_file_open_flags_stdout(thefile, 0, pool);
396
0
}
397
398
APR_DECLARE(apr_status_t) apr_file_open_stdin(apr_file_t **thefile,
399
                                              apr_pool_t *pool)
400
0
{
401
0
    return apr_file_open_flags_stdin(thefile, 0, pool);
402
0
}
403
404
APR_IMPLEMENT_INHERIT_SET(file, flags, pool, apr_unix_file_cleanup)
405
406
/* We need to do this by hand instead of using APR_IMPLEMENT_INHERIT_UNSET
407
 * because the macro sets both cleanups to the same function, which is not
408
 * suitable on Unix (see PR 41119). */
409
APR_DECLARE(apr_status_t) apr_file_inherit_unset(apr_file_t *thefile)
410
0
{
411
0
    if (thefile->flags & APR_FOPEN_NOCLEANUP) {
412
0
        return APR_EINVAL;
413
0
    }
414
0
    if (thefile->flags & APR_INHERIT) {
415
0
        int flags;
416
417
0
        if ((flags = fcntl(thefile->filedes, F_GETFD)) == -1)
418
0
            return errno;
419
420
0
        flags |= FD_CLOEXEC;
421
0
        if (fcntl(thefile->filedes, F_SETFD, flags) == -1)
422
0
            return errno;
423
424
0
        thefile->flags &= ~APR_INHERIT;
425
0
        apr_pool_child_cleanup_set(thefile->pool,
426
0
                                   (void *)thefile,
427
0
                                   apr_unix_file_cleanup,
428
0
                                   apr_unix_child_file_cleanup);
429
0
    }
430
0
    return APR_SUCCESS;
431
0
}
432
433
APR_POOL_IMPLEMENT_ACCESSOR(file)
434
435
APR_DECLARE(apr_status_t) apr_file_link(const char *from_path,
436
                                          const char *to_path)
437
0
{
438
0
    if (link(from_path, to_path) == -1) {
439
0
        return errno;
440
0
    }
441
442
0
    return APR_SUCCESS;
443
0
}