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