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_lib.h"
20#include "apr_portable.h"
21#include "apr_strings.h"
22#include "apr_arch_inherit.h"
23#include <string.h>
24
25apr_status_t apr_file_cleanup(void *thefile)
26{
27    apr_file_t *file = thefile;
28    return apr_file_close(file);
29}
30
31
32
33APR_DECLARE(apr_status_t) apr_file_open(apr_file_t **new, const char *fname, apr_int32_t flag,  apr_fileperms_t perm, apr_pool_t *pool)
34{
35    int oflags = 0;
36    int mflags = OPEN_FLAGS_FAIL_ON_ERROR|OPEN_SHARE_DENYNONE|OPEN_FLAGS_NOINHERIT;
37    int rv;
38    ULONG action;
39    apr_file_t *dafile = (apr_file_t *)apr_palloc(pool, sizeof(apr_file_t));
40
41    dafile->pool = pool;
42    dafile->isopen = FALSE;
43    dafile->eof_hit = FALSE;
44    dafile->buffer = NULL;
45    dafile->flags = flag;
46    dafile->blocking = BLK_ON;
47
48    if ((flag & APR_FOPEN_READ) && (flag & APR_FOPEN_WRITE)) {
49        mflags |= OPEN_ACCESS_READWRITE;
50    } else if (flag & APR_FOPEN_READ) {
51        mflags |= OPEN_ACCESS_READONLY;
52    } else if (flag & APR_FOPEN_WRITE) {
53        mflags |= OPEN_ACCESS_WRITEONLY;
54    } else {
55        dafile->filedes = -1;
56        return APR_EACCES;
57    }
58
59    dafile->buffered = (flag & APR_FOPEN_BUFFERED) > 0;
60
61    if (dafile->buffered) {
62        dafile->buffer = apr_palloc(pool, APR_FILE_DEFAULT_BUFSIZE);
63        dafile->bufsize = APR_FILE_DEFAULT_BUFSIZE;
64        rv = apr_thread_mutex_create(&dafile->mutex, 0, pool);
65
66        if (rv)
67            return rv;
68    }
69
70    if (flag & APR_FOPEN_CREATE) {
71        oflags |= OPEN_ACTION_CREATE_IF_NEW;
72
73        if (!(flag & APR_FOPEN_EXCL) && !(flag & APR_FOPEN_TRUNCATE)) {
74            oflags |= OPEN_ACTION_OPEN_IF_EXISTS;
75        }
76    }
77
78    if ((flag & APR_FOPEN_EXCL) && !(flag & APR_FOPEN_CREATE))
79        return APR_EACCES;
80
81    if (flag & APR_FOPEN_TRUNCATE) {
82        oflags |= OPEN_ACTION_REPLACE_IF_EXISTS;
83    } else if ((oflags & 0xFF) == 0) {
84        oflags |= OPEN_ACTION_OPEN_IF_EXISTS;
85    }
86
87    rv = DosOpen(fname, &(dafile->filedes), &action, 0, 0, oflags, mflags, NULL);
88
89    if (rv == 0 && (flag & APR_FOPEN_APPEND)) {
90        ULONG newptr;
91        rv = DosSetFilePtr(dafile->filedes, 0, FILE_END, &newptr );
92
93        if (rv)
94            DosClose(dafile->filedes);
95    }
96
97    if (rv != 0)
98        return APR_FROM_OS_ERROR(rv);
99
100    dafile->isopen = TRUE;
101    dafile->fname = apr_pstrdup(pool, fname);
102    dafile->filePtr = 0;
103    dafile->bufpos = 0;
104    dafile->dataRead = 0;
105    dafile->direction = 0;
106    dafile->pipe = FALSE;
107
108    if (!(flag & APR_FOPEN_NOCLEANUP)) {
109        apr_pool_cleanup_register(dafile->pool, dafile, apr_file_cleanup, apr_file_cleanup);
110    }
111
112    *new = dafile;
113    return APR_SUCCESS;
114}
115
116
117
118APR_DECLARE(apr_status_t) apr_file_close(apr_file_t *file)
119{
120    ULONG rc;
121    apr_status_t status;
122
123    if (file && file->isopen) {
124        /* XXX: flush here is not mutex protected */
125        status = apr_file_flush(file);
126        rc = DosClose(file->filedes);
127
128        if (rc == 0) {
129            file->isopen = FALSE;
130
131            if (file->flags & APR_FOPEN_DELONCLOSE) {
132                status = APR_FROM_OS_ERROR(DosDelete(file->fname));
133            }
134            /* else we return the status of the flush attempt
135             * when all else succeeds
136             */
137        } else {
138            return APR_FROM_OS_ERROR(rc);
139        }
140    }
141
142    if (file->buffered)
143        apr_thread_mutex_destroy(file->mutex);
144
145    return status;
146}
147
148
149
150APR_DECLARE(apr_status_t) apr_file_remove(const char *path, apr_pool_t *pool)
151{
152    ULONG rc = DosDelete(path);
153    return APR_FROM_OS_ERROR(rc);
154}
155
156
157
158APR_DECLARE(apr_status_t) apr_file_rename(const char *from_path, const char *to_path,
159                                   apr_pool_t *p)
160{
161    ULONG rc = DosMove(from_path, to_path);
162
163    if (rc == ERROR_ACCESS_DENIED || rc == ERROR_ALREADY_EXISTS) {
164        rc = DosDelete(to_path);
165
166        if (rc == 0 || rc == ERROR_FILE_NOT_FOUND) {
167            rc = DosMove(from_path, to_path);
168        }
169    }
170
171    return APR_FROM_OS_ERROR(rc);
172}
173
174
175
176APR_DECLARE(apr_status_t) apr_os_file_get(apr_os_file_t *thefile, apr_file_t *file)
177{
178    *thefile = file->filedes;
179    return APR_SUCCESS;
180}
181
182
183
184APR_DECLARE(apr_status_t) apr_os_file_put(apr_file_t **file, apr_os_file_t *thefile, apr_int32_t flags, apr_pool_t *pool)
185{
186    apr_os_file_t *dafile = thefile;
187
188    (*file) = apr_palloc(pool, sizeof(apr_file_t));
189    (*file)->pool = pool;
190    (*file)->filedes = *dafile;
191    (*file)->isopen = TRUE;
192    (*file)->eof_hit = FALSE;
193    (*file)->flags = flags;
194    (*file)->pipe = FALSE;
195    (*file)->buffered = (flags & APR_FOPEN_BUFFERED) > 0;
196
197    if ((*file)->buffered) {
198        apr_status_t rv;
199
200        (*file)->buffer = apr_palloc(pool, APR_FILE_DEFAULT_BUFSIZE);
201        (*file)->bufsize = APR_FILE_DEFAULT_BUFSIZE;
202        rv = apr_thread_mutex_create(&(*file)->mutex, 0, pool);
203
204        if (rv)
205            return rv;
206    }
207
208    return APR_SUCCESS;
209}
210
211
212APR_DECLARE(apr_status_t) apr_file_eof(apr_file_t *fptr)
213{
214    if (!fptr->isopen || fptr->eof_hit == 1) {
215        return APR_EOF;
216    }
217    return APR_SUCCESS;
218}
219
220
221APR_DECLARE(apr_status_t) apr_file_open_flags_stderr(apr_file_t **thefile,
222                                                     apr_int32_t flags,
223                                                     apr_pool_t *pool)
224{
225    apr_os_file_t fd = 2;
226
227    return apr_os_file_put(thefile, &fd, flags | APR_FOPEN_WRITE, pool);
228}
229
230
231APR_DECLARE(apr_status_t) apr_file_open_flags_stdout(apr_file_t **thefile,
232                                                     apr_int32_t flags,
233                                                     apr_pool_t *pool)
234{
235    apr_os_file_t fd = 1;
236
237    return apr_os_file_put(thefile, &fd, flags | APR_FOPEN_WRITE, pool);
238}
239
240
241APR_DECLARE(apr_status_t) apr_file_open_flags_stdin(apr_file_t **thefile,
242                                                    apr_int32_t flags,
243                                                    apr_pool_t *pool)
244{
245    apr_os_file_t fd = 0;
246
247    return apr_os_file_put(thefile, &fd, flags | APR_FOPEN_READ, pool);
248}
249
250
251APR_DECLARE(apr_status_t) apr_file_open_stderr(apr_file_t **thefile, apr_pool_t *pool)
252{
253    return apr_file_open_flags_stderr(thefile, 0, pool);
254}
255
256
257APR_DECLARE(apr_status_t) apr_file_open_stdout(apr_file_t **thefile, apr_pool_t *pool)
258{
259    return apr_file_open_flags_stdout(thefile, 0, pool);
260}
261
262
263APR_DECLARE(apr_status_t) apr_file_open_stdin(apr_file_t **thefile, apr_pool_t *pool)
264{
265    return apr_file_open_flags_stdin(thefile, 0, pool);
266}
267
268APR_POOL_IMPLEMENT_ACCESSOR(file);
269
270
271
272APR_DECLARE(apr_status_t) apr_file_inherit_set(apr_file_t *thefile)
273{
274    int rv;
275    ULONG state;
276
277    rv = DosQueryFHState(thefile->filedes, &state);
278
279    if (rv == 0 && (state & OPEN_FLAGS_NOINHERIT) != 0) {
280        rv = DosSetFHState(thefile->filedes, state & ~OPEN_FLAGS_NOINHERIT);
281    }
282
283    return APR_FROM_OS_ERROR(rv);
284}
285
286
287
288APR_DECLARE(apr_status_t) apr_file_inherit_unset(apr_file_t *thefile)
289{
290    int rv;
291    ULONG state;
292
293    rv = DosQueryFHState(thefile->filedes, &state);
294
295    if (rv == 0 && (state & OPEN_FLAGS_NOINHERIT) == 0) {
296        rv = DosSetFHState(thefile->filedes, state | OPEN_FLAGS_NOINHERIT);
297    }
298
299    return APR_FROM_OS_ERROR(rv);
300}
301