1184610Salfred/* Licensed to the Apache Software Foundation (ASF) under one or more
2184610Salfred * contributor license agreements.  See the NOTICE file distributed with
3184610Salfred * this work for additional information regarding copyright ownership.
4184610Salfred * The ASF licenses this file to You under the Apache License, Version 2.0
5184610Salfred * (the "License"); you may not use this file except in compliance with
6184610Salfred * the License.  You may obtain a copy of the License at
7184610Salfred *
8184610Salfred *     http://www.apache.org/licenses/LICENSE-2.0
9184610Salfred *
10184610Salfred * Unless required by applicable law or agreed to in writing, software
11184610Salfred * distributed under the License is distributed on an "AS IS" BASIS,
12184610Salfred * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13184610Salfred * See the License for the specific language governing permissions and
14184610Salfred * limitations under the License.
15184610Salfred */
16184610Salfred
17184610Salfred#include "apr_arch_file_io.h"
18184610Salfred#include "apr_strings.h"
19184610Salfred#include "apr_portable.h"
20184610Salfred#include "apr_thread_mutex.h"
21184610Salfred#include "apr_arch_inherit.h"
22184610Salfred
23184610Salfred#ifdef NETWARE
24184610Salfred#include "nks/dirio.h"
25184610Salfred#include "apr_hash.h"
26184610Salfred#include "fsio.h"
27184610Salfred#endif
28184610Salfred
29184610Salfredstatic apr_status_t file_cleanup(apr_file_t *file, int is_child)
30184610Salfred{
31184610Salfred    apr_status_t rv = APR_SUCCESS;
32184610Salfred    int fd = file->filedes;
33184610Salfred
34184610Salfred    /* Set file descriptor to -1 before close(), so that there is no
35184610Salfred     * chance of returning an already closed FD from apr_os_file_get().
36184610Salfred     */
37184610Salfred    file->filedes = -1;
38184610Salfred
39184610Salfred    if (close(fd) == 0) {
40184610Salfred        /* Only the parent process should delete the file! */
41184610Salfred        if (!is_child && (file->flags & APR_FOPEN_DELONCLOSE)) {
42184610Salfred            unlink(file->fname);
43184610Salfred        }
44184610Salfred#if APR_HAS_THREADS
45184610Salfred        if (file->thlock) {
46184610Salfred            rv = apr_thread_mutex_destroy(file->thlock);
47184610Salfred        }
48184610Salfred#endif
49184610Salfred    }
50184610Salfred    else {
51184610Salfred        /* Restore, close() was not successful. */
52184610Salfred        file->filedes = fd;
53184610Salfred
54184610Salfred        /* Are there any error conditions other than EINTR or EBADF? */
55184610Salfred        rv = errno;
56184610Salfred    }
57184610Salfred#ifndef WAITIO_USES_POLL
58184610Salfred    if (file->pollset != NULL) {
59184610Salfred        apr_status_t pollset_rv = apr_pollset_destroy(file->pollset);
60184610Salfred        /* If the file close failed, return its error value,
61184610Salfred         * not apr_pollset_destroy()'s.
62184610Salfred         */
63184610Salfred        if (rv == APR_SUCCESS) {
64184610Salfred            rv = pollset_rv;
65184610Salfred        }
66185087Salfred    }
67184610Salfred#endif /* !WAITIO_USES_POLL */
68184610Salfred    return rv;
69184610Salfred}
70184610Salfred
71184610Salfredapr_status_t apr_unix_file_cleanup(void *thefile)
72184610Salfred{
73184610Salfred    apr_file_t *file = thefile;
74184610Salfred    apr_status_t flush_rv = APR_SUCCESS, rv = APR_SUCCESS;
75184610Salfred
76184610Salfred    if (file->buffered) {
77184610Salfred        flush_rv = apr_file_flush(file);
78184610Salfred    }
79184610Salfred
80184610Salfred    rv = file_cleanup(file, 0);
81184610Salfred
82184610Salfred    return rv != APR_SUCCESS ? rv : flush_rv;
83184610Salfred}
84184610Salfred
85184610Salfredapr_status_t apr_unix_child_file_cleanup(void *thefile)
86184610Salfred{
87184610Salfred    return file_cleanup(thefile, 1);
88184610Salfred}
89184610Salfred
90184610SalfredAPR_DECLARE(apr_status_t) apr_file_open(apr_file_t **new,
91184610Salfred                                        const char *fname,
92184610Salfred                                        apr_int32_t flag,
93184610Salfred                                        apr_fileperms_t perm,
94184610Salfred                                        apr_pool_t *pool)
95184610Salfred{
96184610Salfred    apr_os_file_t fd;
97184610Salfred    int oflags = 0;
98184610Salfred#if APR_HAS_THREADS
99184610Salfred    apr_thread_mutex_t *thlock;
100184610Salfred    apr_status_t rv;
101184610Salfred#endif
102184610Salfred
103184610Salfred    if ((flag & APR_FOPEN_READ) && (flag & APR_FOPEN_WRITE)) {
104184610Salfred        oflags = O_RDWR;
105184610Salfred    }
106184610Salfred    else if (flag & APR_FOPEN_READ) {
107184610Salfred        oflags = O_RDONLY;
108184610Salfred    }
109184610Salfred    else if (flag & APR_FOPEN_WRITE) {
110184610Salfred        oflags = O_WRONLY;
111184610Salfred    }
112184610Salfred    else {
113184610Salfred        return APR_EACCES;
114184610Salfred    }
115184610Salfred
116184610Salfred    if (flag & APR_FOPEN_CREATE) {
117184610Salfred        oflags |= O_CREAT;
118184610Salfred        if (flag & APR_FOPEN_EXCL) {
119184610Salfred            oflags |= O_EXCL;
120184610Salfred        }
121184610Salfred    }
122184610Salfred    if ((flag & APR_FOPEN_EXCL) && !(flag & APR_FOPEN_CREATE)) {
123184610Salfred        return APR_EACCES;
124184610Salfred    }
125184610Salfred
126184610Salfred    if (flag & APR_FOPEN_APPEND) {
127184610Salfred        oflags |= O_APPEND;
128184610Salfred    }
129184610Salfred    if (flag & APR_FOPEN_TRUNCATE) {
130184610Salfred        oflags |= O_TRUNC;
131184610Salfred    }
132184610Salfred#ifdef O_BINARY
133184610Salfred    if (flag & APR_FOPEN_BINARY) {
134184610Salfred        oflags |= O_BINARY;
135184610Salfred    }
136184610Salfred#endif
137184610Salfred
138184610Salfred#ifdef O_CLOEXEC
139184610Salfred    /* Introduced in Linux 2.6.23. Silently ignored on earlier Linux kernels.
140184610Salfred     */
141184610Salfred    if (!(flag & APR_FOPEN_NOCLEANUP)) {
142184610Salfred        oflags |= O_CLOEXEC;
143184610Salfred}
144184610Salfred#endif
145184610Salfred
146184610Salfred#if APR_HAS_LARGE_FILES && defined(_LARGEFILE64_SOURCE)
147184610Salfred    oflags |= O_LARGEFILE;
148184610Salfred#elif defined(O_LARGEFILE)
149184610Salfred    if (flag & APR_FOPEN_LARGEFILE) {
150184610Salfred        oflags |= O_LARGEFILE;
151184610Salfred    }
152184610Salfred#endif
153184610Salfred
154184610Salfred#if APR_HAS_THREADS
155184610Salfred    if ((flag & APR_FOPEN_BUFFERED) && (flag & APR_FOPEN_XTHREAD)) {
156184610Salfred        rv = apr_thread_mutex_create(&thlock,
157184610Salfred                                     APR_THREAD_MUTEX_DEFAULT, pool);
158184610Salfred        if (rv) {
159184610Salfred            return rv;
160184610Salfred        }
161184610Salfred    }
162184610Salfred#endif
163184610Salfred
164184610Salfred    if (perm == APR_OS_DEFAULT) {
165184610Salfred        fd = open(fname, oflags, 0666);
166184610Salfred    }
167184610Salfred    else {
168184610Salfred        fd = open(fname, oflags, apr_unix_perms2mode(perm));
169184610Salfred    }
170184610Salfred    if (fd < 0) {
171184610Salfred       return errno;
172184610Salfred    }
173184610Salfred    if (!(flag & APR_FOPEN_NOCLEANUP)) {
174184610Salfred#ifdef O_CLOEXEC
175184610Salfred        static int has_o_cloexec = 0;
176184610Salfred        if (!has_o_cloexec)
177184610Salfred#endif
178184610Salfred        {
179184610Salfred            int flags;
180184610Salfred
181184610Salfred            if ((flags = fcntl(fd, F_GETFD)) == -1) {
182184610Salfred                close(fd);
183184610Salfred                return errno;
184184610Salfred            }
185184610Salfred            if ((flags & FD_CLOEXEC) == 0) {
186184610Salfred                flags |= FD_CLOEXEC;
187184610Salfred                if (fcntl(fd, F_SETFD, flags) == -1) {
188184610Salfred                    close(fd);
189184610Salfred                    return errno;
190184610Salfred                }
191184610Salfred            }
192184610Salfred#ifdef O_CLOEXEC
193184610Salfred            else {
194184610Salfred                has_o_cloexec = 1;
195184610Salfred            }
196184610Salfred#endif
197184610Salfred        }
198184610Salfred    }
199184610Salfred
200184610Salfred    (*new) = (apr_file_t *)apr_pcalloc(pool, sizeof(apr_file_t));
201184610Salfred    (*new)->pool = pool;
202184610Salfred    (*new)->flags = flag;
203184610Salfred    (*new)->filedes = fd;
204184610Salfred
205184610Salfred    (*new)->fname = apr_pstrdup(pool, fname);
206184610Salfred
207184610Salfred    (*new)->blocking = BLK_ON;
208184610Salfred    (*new)->buffered = (flag & APR_FOPEN_BUFFERED) > 0;
209184610Salfred
210184610Salfred    if ((*new)->buffered) {
211184610Salfred        (*new)->buffer = apr_palloc(pool, APR_FILE_DEFAULT_BUFSIZE);
212184610Salfred        (*new)->bufsize = APR_FILE_DEFAULT_BUFSIZE;
213184610Salfred#if APR_HAS_THREADS
214184610Salfred        if ((*new)->flags & APR_FOPEN_XTHREAD) {
215184610Salfred            (*new)->thlock = thlock;
216184610Salfred        }
217184610Salfred#endif
218184610Salfred    }
219184610Salfred    else {
220184610Salfred        (*new)->buffer = NULL;
221184610Salfred    }
222184610Salfred
223184610Salfred    (*new)->is_pipe = 0;
224184610Salfred    (*new)->timeout = -1;
225184610Salfred    (*new)->ungetchar = -1;
226184610Salfred    (*new)->eof_hit = 0;
227184610Salfred    (*new)->filePtr = 0;
228184610Salfred    (*new)->bufpos = 0;
229184610Salfred    (*new)->dataRead = 0;
230184610Salfred    (*new)->direction = 0;
231184610Salfred#ifndef WAITIO_USES_POLL
232184610Salfred    /* Start out with no pollset.  apr_wait_for_io_or_timeout() will
233184610Salfred     * initialize the pollset if needed.
234184610Salfred     */
235184610Salfred    (*new)->pollset = NULL;
236184610Salfred#endif
237184610Salfred    if (!(flag & APR_FOPEN_NOCLEANUP)) {
238184610Salfred        apr_pool_cleanup_register((*new)->pool, (void *)(*new),
239184610Salfred                                  apr_unix_file_cleanup,
240184610Salfred                                  apr_unix_child_file_cleanup);
241184610Salfred    }
242184610Salfred    return APR_SUCCESS;
243184610Salfred}
244184610Salfred
245184610SalfredAPR_DECLARE(apr_status_t) apr_file_close(apr_file_t *file)
246184610Salfred{
247184610Salfred    return apr_pool_cleanup_run(file->pool, file, apr_unix_file_cleanup);
248184610Salfred}
249184610Salfred
250184610SalfredAPR_DECLARE(apr_status_t) apr_file_remove(const char *path, apr_pool_t *pool)
251184610Salfred{
252184610Salfred    if (unlink(path) == 0) {
253184610Salfred        return APR_SUCCESS;
254184610Salfred    }
255184610Salfred    else {
256184610Salfred        return errno;
257184610Salfred    }
258184610Salfred}
259184610Salfred
260184610SalfredAPR_DECLARE(apr_status_t) apr_file_rename(const char *from_path,
261184610Salfred                                          const char *to_path,
262184610Salfred                                          apr_pool_t *p)
263184610Salfred{
264184610Salfred    if (rename(from_path, to_path) != 0) {
265184610Salfred        return errno;
266184610Salfred    }
267229122Shselasky    return APR_SUCCESS;
268229122Shselasky}
269229122Shselasky
270229122ShselaskyAPR_DECLARE(apr_status_t) apr_os_file_get(apr_os_file_t *thefile,
271229122Shselasky                                          apr_file_t *file)
272229122Shselasky{
273229122Shselasky    *thefile = file->filedes;
274229122Shselasky    return APR_SUCCESS;
275229122Shselasky}
276229122Shselasky
277229122ShselaskyAPR_DECLARE(apr_status_t) apr_os_file_put(apr_file_t **file,
278229122Shselasky                                          apr_os_file_t *thefile,
279229122Shselasky                                          apr_int32_t flags, apr_pool_t *pool)
280229122Shselasky{
281229122Shselasky    int *dafile = thefile;
282229122Shselasky
283229122Shselasky    (*file) = apr_pcalloc(pool, sizeof(apr_file_t));
284229122Shselasky    (*file)->pool = pool;
285229122Shselasky    (*file)->eof_hit = 0;
286229122Shselasky    (*file)->blocking = BLK_UNKNOWN; /* in case it is a pipe */
287229122Shselasky    (*file)->timeout = -1;
288229122Shselasky    (*file)->ungetchar = -1; /* no char avail */
289229122Shselasky    (*file)->filedes = *dafile;
290229122Shselasky    (*file)->flags = flags | APR_FOPEN_NOCLEANUP;
291229122Shselasky    (*file)->buffered = (flags & APR_FOPEN_BUFFERED) > 0;
292229122Shselasky
293229122Shselasky#ifndef WAITIO_USES_POLL
294229122Shselasky    /* Start out with no pollset.  apr_wait_for_io_or_timeout() will
295229122Shselasky     * initialize the pollset if needed.
296229122Shselasky     */
297229122Shselasky    (*file)->pollset = NULL;
298229122Shselasky#endif
299229122Shselasky
300229122Shselasky    if ((*file)->buffered) {
301229122Shselasky        (*file)->buffer = apr_palloc(pool, APR_FILE_DEFAULT_BUFSIZE);
302229122Shselasky        (*file)->bufsize = APR_FILE_DEFAULT_BUFSIZE;
303229122Shselasky#if APR_HAS_THREADS
304184610Salfred        if ((*file)->flags & APR_FOPEN_XTHREAD) {
305184610Salfred            apr_status_t rv;
306184610Salfred            rv = apr_thread_mutex_create(&((*file)->thlock),
307184610Salfred                                         APR_THREAD_MUTEX_DEFAULT, pool);
308184610Salfred            if (rv) {
309184610Salfred                return rv;
310184610Salfred            }
311184610Salfred        }
312184610Salfred#endif
313184610Salfred    }
314184610Salfred    return APR_SUCCESS;
315184610Salfred}
316184610Salfred
317184610SalfredAPR_DECLARE(apr_status_t) apr_file_eof(apr_file_t *fptr)
318184610Salfred{
319184610Salfred    if (fptr->eof_hit == 1) {
320184610Salfred        return APR_EOF;
321184610Salfred    }
322184610Salfred    return APR_SUCCESS;
323184610Salfred}
324184610Salfred
325184610SalfredAPR_DECLARE(apr_status_t) apr_file_open_flags_stderr(apr_file_t **thefile,
326184610Salfred                                                     apr_int32_t flags,
327184610Salfred                                                     apr_pool_t *pool)
328184610Salfred{
329184610Salfred    int fd = STDERR_FILENO;
330184610Salfred
331184610Salfred    return apr_os_file_put(thefile, &fd, flags | APR_FOPEN_WRITE, pool);
332184610Salfred}
333184610Salfred
334184610SalfredAPR_DECLARE(apr_status_t) apr_file_open_flags_stdout(apr_file_t **thefile,
335184610Salfred                                                     apr_int32_t flags,
336184610Salfred                                                     apr_pool_t *pool)
337184610Salfred{
338184610Salfred    int fd = STDOUT_FILENO;
339184610Salfred
340184610Salfred    return apr_os_file_put(thefile, &fd, flags | APR_FOPEN_WRITE, pool);
341184610Salfred}
342184610Salfred
343184610SalfredAPR_DECLARE(apr_status_t) apr_file_open_flags_stdin(apr_file_t **thefile,
344184610Salfred                                                    apr_int32_t flags,
345184610Salfred                                                    apr_pool_t *pool)
346184610Salfred{
347184610Salfred    int fd = STDIN_FILENO;
348184610Salfred
349184610Salfred    return apr_os_file_put(thefile, &fd, flags | APR_FOPEN_READ, pool);
350184610Salfred}
351184610Salfred
352184610SalfredAPR_DECLARE(apr_status_t) apr_file_open_stderr(apr_file_t **thefile,
353184610Salfred                                               apr_pool_t *pool)
354184610Salfred{
355184610Salfred    return apr_file_open_flags_stderr(thefile, 0, pool);
356184610Salfred}
357184610Salfred
358184610SalfredAPR_DECLARE(apr_status_t) apr_file_open_stdout(apr_file_t **thefile,
359184610Salfred                                               apr_pool_t *pool)
360184610Salfred{
361184610Salfred    return apr_file_open_flags_stdout(thefile, 0, pool);
362184610Salfred}
363184610Salfred
364184610SalfredAPR_DECLARE(apr_status_t) apr_file_open_stdin(apr_file_t **thefile,
365184610Salfred                                              apr_pool_t *pool)
366184610Salfred{
367184610Salfred    return apr_file_open_flags_stdin(thefile, 0, pool);
368184610Salfred}
369184610Salfred
370184610SalfredAPR_IMPLEMENT_INHERIT_SET(file, flags, pool, apr_unix_file_cleanup)
371184610Salfred
372184610Salfred/* We need to do this by hand instead of using APR_IMPLEMENT_INHERIT_UNSET
373229122Shselasky * because the macro sets both cleanups to the same function, which is not
374229122Shselasky * suitable on Unix (see PR 41119). */
375229122ShselaskyAPR_DECLARE(apr_status_t) apr_file_inherit_unset(apr_file_t *thefile)
376229122Shselasky{
377229122Shselasky    if (thefile->flags & APR_FOPEN_NOCLEANUP) {
378229122Shselasky        return APR_EINVAL;
379229122Shselasky    }
380229122Shselasky    if (thefile->flags & APR_INHERIT) {
381229122Shselasky        int flags;
382184610Salfred
383184610Salfred        if ((flags = fcntl(thefile->filedes, F_GETFD)) == -1)
384229122Shselasky            return errno;
385229122Shselasky
386229122Shselasky        flags |= FD_CLOEXEC;
387229122Shselasky        if (fcntl(thefile->filedes, F_SETFD, flags) == -1)
388229122Shselasky            return errno;
389229122Shselasky
390229122Shselasky        thefile->flags &= ~APR_INHERIT;
391229122Shselasky        apr_pool_child_cleanup_set(thefile->pool,
392229122Shselasky                                   (void *)thefile,
393184610Salfred                                   apr_unix_file_cleanup,
394184610Salfred                                   apr_unix_child_file_cleanup);
395184610Salfred    }
396184610Salfred    return APR_SUCCESS;
397184610Salfred}
398184610Salfred
399184610SalfredAPR_POOL_IMPLEMENT_ACCESSOR(file)
400229122Shselasky
401229122ShselaskyAPR_DECLARE(apr_status_t) apr_file_link(const char *from_path,
402229122Shselasky                                          const char *to_path)
403229122Shselasky{
404184610Salfred    if (link(from_path, to_path) == -1) {
405184610Salfred        return errno;
406184610Salfred    }
407184610Salfred
408184610Salfred    return APR_SUCCESS;
409184610Salfred}
410184610Salfred