1251875Speter/* Licensed to the Apache Software Foundation (ASF) under one or more 2251875Speter * contributor license agreements. See the NOTICE file distributed with 3251875Speter * this work for additional information regarding copyright ownership. 4251875Speter * The ASF licenses this file to You under the Apache License, Version 2.0 5251875Speter * (the "License"); you may not use this file except in compliance with 6251875Speter * the License. You may obtain a copy of the License at 7251875Speter * 8251875Speter * http://www.apache.org/licenses/LICENSE-2.0 9251875Speter * 10251875Speter * Unless required by applicable law or agreed to in writing, software 11251875Speter * distributed under the License is distributed on an "AS IS" BASIS, 12251875Speter * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13251875Speter * See the License for the specific language governing permissions and 14251875Speter * limitations under the License. 15251875Speter */ 16251875Speter 17251875Speter#include "apr_arch_file_io.h" 18251875Speter#include "apr_strings.h" 19251875Speter#include "apr_portable.h" 20251875Speter#include "apr_thread_mutex.h" 21251875Speter#include "apr_arch_inherit.h" 22251875Speter 23251875Speter#ifdef NETWARE 24251875Speter#include "nks/dirio.h" 25251875Speter#include "apr_hash.h" 26251875Speter#include "fsio.h" 27251875Speter#endif 28251875Speter 29251875Speterstatic apr_status_t file_cleanup(apr_file_t *file, int is_child) 30251875Speter{ 31251875Speter apr_status_t rv = APR_SUCCESS; 32251875Speter int fd = file->filedes; 33251875Speter 34251875Speter /* Set file descriptor to -1 before close(), so that there is no 35251875Speter * chance of returning an already closed FD from apr_os_file_get(). 36251875Speter */ 37251875Speter file->filedes = -1; 38251875Speter 39251875Speter if (close(fd) == 0) { 40251875Speter /* Only the parent process should delete the file! */ 41251875Speter if (!is_child && (file->flags & APR_FOPEN_DELONCLOSE)) { 42251875Speter unlink(file->fname); 43251875Speter } 44251875Speter#if APR_HAS_THREADS 45251875Speter if (file->thlock) { 46251875Speter rv = apr_thread_mutex_destroy(file->thlock); 47251875Speter } 48251875Speter#endif 49251875Speter } 50251875Speter else { 51251875Speter /* Restore, close() was not successful. */ 52251875Speter file->filedes = fd; 53251875Speter 54251875Speter /* Are there any error conditions other than EINTR or EBADF? */ 55251875Speter rv = errno; 56251875Speter } 57251875Speter#ifndef WAITIO_USES_POLL 58251875Speter if (file->pollset != NULL) { 59251875Speter apr_status_t pollset_rv = apr_pollset_destroy(file->pollset); 60251875Speter /* If the file close failed, return its error value, 61251875Speter * not apr_pollset_destroy()'s. 62251875Speter */ 63251875Speter if (rv == APR_SUCCESS) { 64251875Speter rv = pollset_rv; 65251875Speter } 66251875Speter } 67251875Speter#endif /* !WAITIO_USES_POLL */ 68251875Speter return rv; 69251875Speter} 70251875Speter 71251875Speterapr_status_t apr_unix_file_cleanup(void *thefile) 72251875Speter{ 73251875Speter apr_file_t *file = thefile; 74251875Speter apr_status_t flush_rv = APR_SUCCESS, rv = APR_SUCCESS; 75251875Speter 76251875Speter if (file->buffered) { 77251875Speter flush_rv = apr_file_flush(file); 78251875Speter } 79251875Speter 80251875Speter rv = file_cleanup(file, 0); 81251875Speter 82251875Speter return rv != APR_SUCCESS ? rv : flush_rv; 83251875Speter} 84251875Speter 85251875Speterapr_status_t apr_unix_child_file_cleanup(void *thefile) 86251875Speter{ 87251875Speter return file_cleanup(thefile, 1); 88251875Speter} 89251875Speter 90251875SpeterAPR_DECLARE(apr_status_t) apr_file_open(apr_file_t **new, 91251875Speter const char *fname, 92251875Speter apr_int32_t flag, 93251875Speter apr_fileperms_t perm, 94251875Speter apr_pool_t *pool) 95251875Speter{ 96251875Speter apr_os_file_t fd; 97251875Speter int oflags = 0; 98251875Speter#if APR_HAS_THREADS 99251875Speter apr_thread_mutex_t *thlock; 100251875Speter apr_status_t rv; 101251875Speter#endif 102251875Speter 103251875Speter if ((flag & APR_FOPEN_READ) && (flag & APR_FOPEN_WRITE)) { 104251875Speter oflags = O_RDWR; 105251875Speter } 106251875Speter else if (flag & APR_FOPEN_READ) { 107251875Speter oflags = O_RDONLY; 108251875Speter } 109251875Speter else if (flag & APR_FOPEN_WRITE) { 110251875Speter oflags = O_WRONLY; 111251875Speter } 112251875Speter else { 113251875Speter return APR_EACCES; 114251875Speter } 115251875Speter 116251875Speter if (flag & APR_FOPEN_CREATE) { 117251875Speter oflags |= O_CREAT; 118251875Speter if (flag & APR_FOPEN_EXCL) { 119251875Speter oflags |= O_EXCL; 120251875Speter } 121251875Speter } 122251875Speter if ((flag & APR_FOPEN_EXCL) && !(flag & APR_FOPEN_CREATE)) { 123251875Speter return APR_EACCES; 124251875Speter } 125251875Speter 126251875Speter if (flag & APR_FOPEN_APPEND) { 127251875Speter oflags |= O_APPEND; 128251875Speter } 129251875Speter if (flag & APR_FOPEN_TRUNCATE) { 130251875Speter oflags |= O_TRUNC; 131251875Speter } 132251875Speter#ifdef O_BINARY 133251875Speter if (flag & APR_FOPEN_BINARY) { 134251875Speter oflags |= O_BINARY; 135251875Speter } 136251875Speter#endif 137251875Speter 138266735Speter if (flag & APR_FOPEN_NONBLOCK) { 139266735Speter#ifdef O_NONBLOCK 140266735Speter oflags |= O_NONBLOCK; 141266735Speter#else 142266735Speter return APR_ENOTIMPL; 143266735Speter#endif 144266735Speter } 145266735Speter 146251875Speter#ifdef O_CLOEXEC 147251875Speter /* Introduced in Linux 2.6.23. Silently ignored on earlier Linux kernels. 148251875Speter */ 149251875Speter if (!(flag & APR_FOPEN_NOCLEANUP)) { 150251875Speter oflags |= O_CLOEXEC; 151251875Speter} 152251875Speter#endif 153251875Speter 154251875Speter#if APR_HAS_LARGE_FILES && defined(_LARGEFILE64_SOURCE) 155251875Speter oflags |= O_LARGEFILE; 156251875Speter#elif defined(O_LARGEFILE) 157251875Speter if (flag & APR_FOPEN_LARGEFILE) { 158251875Speter oflags |= O_LARGEFILE; 159251875Speter } 160251875Speter#endif 161251875Speter 162251875Speter#if APR_HAS_THREADS 163251875Speter if ((flag & APR_FOPEN_BUFFERED) && (flag & APR_FOPEN_XTHREAD)) { 164251875Speter rv = apr_thread_mutex_create(&thlock, 165251875Speter APR_THREAD_MUTEX_DEFAULT, pool); 166251875Speter if (rv) { 167251875Speter return rv; 168251875Speter } 169251875Speter } 170251875Speter#endif 171251875Speter 172251875Speter if (perm == APR_OS_DEFAULT) { 173251875Speter fd = open(fname, oflags, 0666); 174251875Speter } 175251875Speter else { 176251875Speter fd = open(fname, oflags, apr_unix_perms2mode(perm)); 177251875Speter } 178251875Speter if (fd < 0) { 179251875Speter return errno; 180251875Speter } 181251875Speter if (!(flag & APR_FOPEN_NOCLEANUP)) { 182251875Speter#ifdef O_CLOEXEC 183251875Speter static int has_o_cloexec = 0; 184251875Speter if (!has_o_cloexec) 185251875Speter#endif 186251875Speter { 187251875Speter int flags; 188251875Speter 189251875Speter if ((flags = fcntl(fd, F_GETFD)) == -1) { 190251875Speter close(fd); 191251875Speter return errno; 192251875Speter } 193251875Speter if ((flags & FD_CLOEXEC) == 0) { 194251875Speter flags |= FD_CLOEXEC; 195251875Speter if (fcntl(fd, F_SETFD, flags) == -1) { 196251875Speter close(fd); 197251875Speter return errno; 198251875Speter } 199251875Speter } 200251875Speter#ifdef O_CLOEXEC 201251875Speter else { 202251875Speter has_o_cloexec = 1; 203251875Speter } 204251875Speter#endif 205251875Speter } 206251875Speter } 207251875Speter 208251875Speter (*new) = (apr_file_t *)apr_pcalloc(pool, sizeof(apr_file_t)); 209251875Speter (*new)->pool = pool; 210251875Speter (*new)->flags = flag; 211251875Speter (*new)->filedes = fd; 212251875Speter 213251875Speter (*new)->fname = apr_pstrdup(pool, fname); 214251875Speter 215251875Speter (*new)->blocking = BLK_ON; 216251875Speter (*new)->buffered = (flag & APR_FOPEN_BUFFERED) > 0; 217251875Speter 218251875Speter if ((*new)->buffered) { 219251875Speter (*new)->buffer = apr_palloc(pool, APR_FILE_DEFAULT_BUFSIZE); 220251875Speter (*new)->bufsize = APR_FILE_DEFAULT_BUFSIZE; 221251875Speter#if APR_HAS_THREADS 222251875Speter if ((*new)->flags & APR_FOPEN_XTHREAD) { 223251875Speter (*new)->thlock = thlock; 224251875Speter } 225251875Speter#endif 226251875Speter } 227251875Speter else { 228251875Speter (*new)->buffer = NULL; 229251875Speter } 230251875Speter 231251875Speter (*new)->is_pipe = 0; 232251875Speter (*new)->timeout = -1; 233251875Speter (*new)->ungetchar = -1; 234251875Speter (*new)->eof_hit = 0; 235251875Speter (*new)->filePtr = 0; 236251875Speter (*new)->bufpos = 0; 237251875Speter (*new)->dataRead = 0; 238251875Speter (*new)->direction = 0; 239251875Speter#ifndef WAITIO_USES_POLL 240251875Speter /* Start out with no pollset. apr_wait_for_io_or_timeout() will 241251875Speter * initialize the pollset if needed. 242251875Speter */ 243251875Speter (*new)->pollset = NULL; 244251875Speter#endif 245251875Speter if (!(flag & APR_FOPEN_NOCLEANUP)) { 246251875Speter apr_pool_cleanup_register((*new)->pool, (void *)(*new), 247251875Speter apr_unix_file_cleanup, 248251875Speter apr_unix_child_file_cleanup); 249251875Speter } 250251875Speter return APR_SUCCESS; 251251875Speter} 252251875Speter 253251875SpeterAPR_DECLARE(apr_status_t) apr_file_close(apr_file_t *file) 254251875Speter{ 255251875Speter return apr_pool_cleanup_run(file->pool, file, apr_unix_file_cleanup); 256251875Speter} 257251875Speter 258251875SpeterAPR_DECLARE(apr_status_t) apr_file_remove(const char *path, apr_pool_t *pool) 259251875Speter{ 260251875Speter if (unlink(path) == 0) { 261251875Speter return APR_SUCCESS; 262251875Speter } 263251875Speter else { 264251875Speter return errno; 265251875Speter } 266251875Speter} 267251875Speter 268251875SpeterAPR_DECLARE(apr_status_t) apr_file_rename(const char *from_path, 269251875Speter const char *to_path, 270251875Speter apr_pool_t *p) 271251875Speter{ 272251875Speter if (rename(from_path, to_path) != 0) { 273251875Speter return errno; 274251875Speter } 275251875Speter return APR_SUCCESS; 276251875Speter} 277251875Speter 278251875SpeterAPR_DECLARE(apr_status_t) apr_os_file_get(apr_os_file_t *thefile, 279251875Speter apr_file_t *file) 280251875Speter{ 281251875Speter *thefile = file->filedes; 282251875Speter return APR_SUCCESS; 283251875Speter} 284251875Speter 285251875SpeterAPR_DECLARE(apr_status_t) apr_os_file_put(apr_file_t **file, 286251875Speter apr_os_file_t *thefile, 287251875Speter apr_int32_t flags, apr_pool_t *pool) 288251875Speter{ 289251875Speter int *dafile = thefile; 290251875Speter 291251875Speter (*file) = apr_pcalloc(pool, sizeof(apr_file_t)); 292251875Speter (*file)->pool = pool; 293251875Speter (*file)->eof_hit = 0; 294251875Speter (*file)->blocking = BLK_UNKNOWN; /* in case it is a pipe */ 295251875Speter (*file)->timeout = -1; 296251875Speter (*file)->ungetchar = -1; /* no char avail */ 297251875Speter (*file)->filedes = *dafile; 298251875Speter (*file)->flags = flags | APR_FOPEN_NOCLEANUP; 299251875Speter (*file)->buffered = (flags & APR_FOPEN_BUFFERED) > 0; 300251875Speter 301251875Speter#ifndef WAITIO_USES_POLL 302251875Speter /* Start out with no pollset. apr_wait_for_io_or_timeout() will 303251875Speter * initialize the pollset if needed. 304251875Speter */ 305251875Speter (*file)->pollset = NULL; 306251875Speter#endif 307251875Speter 308251875Speter if ((*file)->buffered) { 309251875Speter (*file)->buffer = apr_palloc(pool, APR_FILE_DEFAULT_BUFSIZE); 310251875Speter (*file)->bufsize = APR_FILE_DEFAULT_BUFSIZE; 311251875Speter#if APR_HAS_THREADS 312251875Speter if ((*file)->flags & APR_FOPEN_XTHREAD) { 313251875Speter apr_status_t rv; 314251875Speter rv = apr_thread_mutex_create(&((*file)->thlock), 315251875Speter APR_THREAD_MUTEX_DEFAULT, pool); 316251875Speter if (rv) { 317251875Speter return rv; 318251875Speter } 319251875Speter } 320251875Speter#endif 321251875Speter } 322251875Speter return APR_SUCCESS; 323251875Speter} 324251875Speter 325251875SpeterAPR_DECLARE(apr_status_t) apr_file_eof(apr_file_t *fptr) 326251875Speter{ 327251875Speter if (fptr->eof_hit == 1) { 328251875Speter return APR_EOF; 329251875Speter } 330251875Speter return APR_SUCCESS; 331251875Speter} 332251875Speter 333251875SpeterAPR_DECLARE(apr_status_t) apr_file_open_flags_stderr(apr_file_t **thefile, 334251875Speter apr_int32_t flags, 335251875Speter apr_pool_t *pool) 336251875Speter{ 337251875Speter int fd = STDERR_FILENO; 338251875Speter 339251875Speter return apr_os_file_put(thefile, &fd, flags | APR_FOPEN_WRITE, pool); 340251875Speter} 341251875Speter 342251875SpeterAPR_DECLARE(apr_status_t) apr_file_open_flags_stdout(apr_file_t **thefile, 343251875Speter apr_int32_t flags, 344251875Speter apr_pool_t *pool) 345251875Speter{ 346251875Speter int fd = STDOUT_FILENO; 347251875Speter 348251875Speter return apr_os_file_put(thefile, &fd, flags | APR_FOPEN_WRITE, pool); 349251875Speter} 350251875Speter 351251875SpeterAPR_DECLARE(apr_status_t) apr_file_open_flags_stdin(apr_file_t **thefile, 352251875Speter apr_int32_t flags, 353251875Speter apr_pool_t *pool) 354251875Speter{ 355251875Speter int fd = STDIN_FILENO; 356251875Speter 357251875Speter return apr_os_file_put(thefile, &fd, flags | APR_FOPEN_READ, pool); 358251875Speter} 359251875Speter 360251875SpeterAPR_DECLARE(apr_status_t) apr_file_open_stderr(apr_file_t **thefile, 361251875Speter apr_pool_t *pool) 362251875Speter{ 363251875Speter return apr_file_open_flags_stderr(thefile, 0, pool); 364251875Speter} 365251875Speter 366251875SpeterAPR_DECLARE(apr_status_t) apr_file_open_stdout(apr_file_t **thefile, 367251875Speter apr_pool_t *pool) 368251875Speter{ 369251875Speter return apr_file_open_flags_stdout(thefile, 0, pool); 370251875Speter} 371251875Speter 372251875SpeterAPR_DECLARE(apr_status_t) apr_file_open_stdin(apr_file_t **thefile, 373251875Speter apr_pool_t *pool) 374251875Speter{ 375251875Speter return apr_file_open_flags_stdin(thefile, 0, pool); 376251875Speter} 377251875Speter 378251875SpeterAPR_IMPLEMENT_INHERIT_SET(file, flags, pool, apr_unix_file_cleanup) 379251875Speter 380251875Speter/* We need to do this by hand instead of using APR_IMPLEMENT_INHERIT_UNSET 381251875Speter * because the macro sets both cleanups to the same function, which is not 382251875Speter * suitable on Unix (see PR 41119). */ 383251875SpeterAPR_DECLARE(apr_status_t) apr_file_inherit_unset(apr_file_t *thefile) 384251875Speter{ 385251875Speter if (thefile->flags & APR_FOPEN_NOCLEANUP) { 386251875Speter return APR_EINVAL; 387251875Speter } 388251875Speter if (thefile->flags & APR_INHERIT) { 389251875Speter int flags; 390251875Speter 391251875Speter if ((flags = fcntl(thefile->filedes, F_GETFD)) == -1) 392251875Speter return errno; 393251875Speter 394251875Speter flags |= FD_CLOEXEC; 395251875Speter if (fcntl(thefile->filedes, F_SETFD, flags) == -1) 396251875Speter return errno; 397251875Speter 398251875Speter thefile->flags &= ~APR_INHERIT; 399251875Speter apr_pool_child_cleanup_set(thefile->pool, 400251875Speter (void *)thefile, 401251875Speter apr_unix_file_cleanup, 402251875Speter apr_unix_child_file_cleanup); 403251875Speter } 404251875Speter return APR_SUCCESS; 405251875Speter} 406251875Speter 407251875SpeterAPR_POOL_IMPLEMENT_ACCESSOR(file) 408251875Speter 409251875SpeterAPR_DECLARE(apr_status_t) apr_file_link(const char *from_path, 410251875Speter const char *to_path) 411251875Speter{ 412251875Speter if (link(from_path, to_path) == -1) { 413251875Speter return errno; 414251875Speter } 415251875Speter 416251875Speter return APR_SUCCESS; 417251875Speter} 418