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