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 138251875Speter#ifdef O_CLOEXEC 139251875Speter /* Introduced in Linux 2.6.23. Silently ignored on earlier Linux kernels. 140251875Speter */ 141251875Speter if (!(flag & APR_FOPEN_NOCLEANUP)) { 142251875Speter oflags |= O_CLOEXEC; 143251875Speter} 144251875Speter#endif 145251875Speter 146251875Speter#if APR_HAS_LARGE_FILES && defined(_LARGEFILE64_SOURCE) 147251875Speter oflags |= O_LARGEFILE; 148251875Speter#elif defined(O_LARGEFILE) 149251875Speter if (flag & APR_FOPEN_LARGEFILE) { 150251875Speter oflags |= O_LARGEFILE; 151251875Speter } 152251875Speter#endif 153251875Speter 154251875Speter#if APR_HAS_THREADS 155251875Speter if ((flag & APR_FOPEN_BUFFERED) && (flag & APR_FOPEN_XTHREAD)) { 156251875Speter rv = apr_thread_mutex_create(&thlock, 157251875Speter APR_THREAD_MUTEX_DEFAULT, pool); 158251875Speter if (rv) { 159251875Speter return rv; 160251875Speter } 161251875Speter } 162251875Speter#endif 163251875Speter 164251875Speter if (perm == APR_OS_DEFAULT) { 165251875Speter fd = open(fname, oflags, 0666); 166251875Speter } 167251875Speter else { 168251875Speter fd = open(fname, oflags, apr_unix_perms2mode(perm)); 169251875Speter } 170251875Speter if (fd < 0) { 171251875Speter return errno; 172251875Speter } 173251875Speter if (!(flag & APR_FOPEN_NOCLEANUP)) { 174251875Speter#ifdef O_CLOEXEC 175251875Speter static int has_o_cloexec = 0; 176251875Speter if (!has_o_cloexec) 177251875Speter#endif 178251875Speter { 179251875Speter int flags; 180251875Speter 181251875Speter if ((flags = fcntl(fd, F_GETFD)) == -1) { 182251875Speter close(fd); 183251875Speter return errno; 184251875Speter } 185251875Speter if ((flags & FD_CLOEXEC) == 0) { 186251875Speter flags |= FD_CLOEXEC; 187251875Speter if (fcntl(fd, F_SETFD, flags) == -1) { 188251875Speter close(fd); 189251875Speter return errno; 190251875Speter } 191251875Speter } 192251875Speter#ifdef O_CLOEXEC 193251875Speter else { 194251875Speter has_o_cloexec = 1; 195251875Speter } 196251875Speter#endif 197251875Speter } 198251875Speter } 199251875Speter 200251875Speter (*new) = (apr_file_t *)apr_pcalloc(pool, sizeof(apr_file_t)); 201251875Speter (*new)->pool = pool; 202251875Speter (*new)->flags = flag; 203251875Speter (*new)->filedes = fd; 204251875Speter 205251875Speter (*new)->fname = apr_pstrdup(pool, fname); 206251875Speter 207251875Speter (*new)->blocking = BLK_ON; 208251875Speter (*new)->buffered = (flag & APR_FOPEN_BUFFERED) > 0; 209251875Speter 210251875Speter if ((*new)->buffered) { 211251875Speter (*new)->buffer = apr_palloc(pool, APR_FILE_DEFAULT_BUFSIZE); 212251875Speter (*new)->bufsize = APR_FILE_DEFAULT_BUFSIZE; 213251875Speter#if APR_HAS_THREADS 214251875Speter if ((*new)->flags & APR_FOPEN_XTHREAD) { 215251875Speter (*new)->thlock = thlock; 216251875Speter } 217251875Speter#endif 218251875Speter } 219251875Speter else { 220251875Speter (*new)->buffer = NULL; 221251875Speter } 222251875Speter 223251875Speter (*new)->is_pipe = 0; 224251875Speter (*new)->timeout = -1; 225251875Speter (*new)->ungetchar = -1; 226251875Speter (*new)->eof_hit = 0; 227251875Speter (*new)->filePtr = 0; 228251875Speter (*new)->bufpos = 0; 229251875Speter (*new)->dataRead = 0; 230251875Speter (*new)->direction = 0; 231251875Speter#ifndef WAITIO_USES_POLL 232251875Speter /* Start out with no pollset. apr_wait_for_io_or_timeout() will 233251875Speter * initialize the pollset if needed. 234251875Speter */ 235251875Speter (*new)->pollset = NULL; 236251875Speter#endif 237251875Speter if (!(flag & APR_FOPEN_NOCLEANUP)) { 238251875Speter apr_pool_cleanup_register((*new)->pool, (void *)(*new), 239251875Speter apr_unix_file_cleanup, 240251875Speter apr_unix_child_file_cleanup); 241251875Speter } 242251875Speter return APR_SUCCESS; 243251875Speter} 244251875Speter 245251875SpeterAPR_DECLARE(apr_status_t) apr_file_close(apr_file_t *file) 246251875Speter{ 247251875Speter return apr_pool_cleanup_run(file->pool, file, apr_unix_file_cleanup); 248251875Speter} 249251875Speter 250251875SpeterAPR_DECLARE(apr_status_t) apr_file_remove(const char *path, apr_pool_t *pool) 251251875Speter{ 252251875Speter if (unlink(path) == 0) { 253251875Speter return APR_SUCCESS; 254251875Speter } 255251875Speter else { 256251875Speter return errno; 257251875Speter } 258251875Speter} 259251875Speter 260251875SpeterAPR_DECLARE(apr_status_t) apr_file_rename(const char *from_path, 261251875Speter const char *to_path, 262251875Speter apr_pool_t *p) 263251875Speter{ 264251875Speter if (rename(from_path, to_path) != 0) { 265251875Speter return errno; 266251875Speter } 267251875Speter return APR_SUCCESS; 268251875Speter} 269251875Speter 270251875SpeterAPR_DECLARE(apr_status_t) apr_os_file_get(apr_os_file_t *thefile, 271251875Speter apr_file_t *file) 272251875Speter{ 273251875Speter *thefile = file->filedes; 274251875Speter return APR_SUCCESS; 275251875Speter} 276251875Speter 277251875SpeterAPR_DECLARE(apr_status_t) apr_os_file_put(apr_file_t **file, 278251875Speter apr_os_file_t *thefile, 279251875Speter apr_int32_t flags, apr_pool_t *pool) 280251875Speter{ 281251875Speter int *dafile = thefile; 282251875Speter 283251875Speter (*file) = apr_pcalloc(pool, sizeof(apr_file_t)); 284251875Speter (*file)->pool = pool; 285251875Speter (*file)->eof_hit = 0; 286251875Speter (*file)->blocking = BLK_UNKNOWN; /* in case it is a pipe */ 287251875Speter (*file)->timeout = -1; 288251875Speter (*file)->ungetchar = -1; /* no char avail */ 289251875Speter (*file)->filedes = *dafile; 290251875Speter (*file)->flags = flags | APR_FOPEN_NOCLEANUP; 291251875Speter (*file)->buffered = (flags & APR_FOPEN_BUFFERED) > 0; 292251875Speter 293251875Speter#ifndef WAITIO_USES_POLL 294251875Speter /* Start out with no pollset. apr_wait_for_io_or_timeout() will 295251875Speter * initialize the pollset if needed. 296251875Speter */ 297251875Speter (*file)->pollset = NULL; 298251875Speter#endif 299251875Speter 300251875Speter if ((*file)->buffered) { 301251875Speter (*file)->buffer = apr_palloc(pool, APR_FILE_DEFAULT_BUFSIZE); 302251875Speter (*file)->bufsize = APR_FILE_DEFAULT_BUFSIZE; 303251875Speter#if APR_HAS_THREADS 304251875Speter if ((*file)->flags & APR_FOPEN_XTHREAD) { 305251875Speter apr_status_t rv; 306251875Speter rv = apr_thread_mutex_create(&((*file)->thlock), 307251875Speter APR_THREAD_MUTEX_DEFAULT, pool); 308251875Speter if (rv) { 309251875Speter return rv; 310251875Speter } 311251875Speter } 312251875Speter#endif 313251875Speter } 314251875Speter return APR_SUCCESS; 315251875Speter} 316251875Speter 317251875SpeterAPR_DECLARE(apr_status_t) apr_file_eof(apr_file_t *fptr) 318251875Speter{ 319251875Speter if (fptr->eof_hit == 1) { 320251875Speter return APR_EOF; 321251875Speter } 322251875Speter return APR_SUCCESS; 323251875Speter} 324251875Speter 325251875SpeterAPR_DECLARE(apr_status_t) apr_file_open_flags_stderr(apr_file_t **thefile, 326251875Speter apr_int32_t flags, 327251875Speter apr_pool_t *pool) 328251875Speter{ 329251875Speter int fd = STDERR_FILENO; 330251875Speter 331251875Speter return apr_os_file_put(thefile, &fd, flags | APR_FOPEN_WRITE, pool); 332251875Speter} 333251875Speter 334251875SpeterAPR_DECLARE(apr_status_t) apr_file_open_flags_stdout(apr_file_t **thefile, 335251875Speter apr_int32_t flags, 336251875Speter apr_pool_t *pool) 337251875Speter{ 338251875Speter int fd = STDOUT_FILENO; 339251875Speter 340251875Speter return apr_os_file_put(thefile, &fd, flags | APR_FOPEN_WRITE, pool); 341251875Speter} 342251875Speter 343251875SpeterAPR_DECLARE(apr_status_t) apr_file_open_flags_stdin(apr_file_t **thefile, 344251875Speter apr_int32_t flags, 345251875Speter apr_pool_t *pool) 346251875Speter{ 347251875Speter int fd = STDIN_FILENO; 348251875Speter 349251875Speter return apr_os_file_put(thefile, &fd, flags | APR_FOPEN_READ, pool); 350251875Speter} 351251875Speter 352251875SpeterAPR_DECLARE(apr_status_t) apr_file_open_stderr(apr_file_t **thefile, 353251875Speter apr_pool_t *pool) 354251875Speter{ 355251875Speter return apr_file_open_flags_stderr(thefile, 0, pool); 356251875Speter} 357251875Speter 358251875SpeterAPR_DECLARE(apr_status_t) apr_file_open_stdout(apr_file_t **thefile, 359251875Speter apr_pool_t *pool) 360251875Speter{ 361251875Speter return apr_file_open_flags_stdout(thefile, 0, pool); 362251875Speter} 363251875Speter 364251875SpeterAPR_DECLARE(apr_status_t) apr_file_open_stdin(apr_file_t **thefile, 365251875Speter apr_pool_t *pool) 366251875Speter{ 367251875Speter return apr_file_open_flags_stdin(thefile, 0, pool); 368251875Speter} 369251875Speter 370251875SpeterAPR_IMPLEMENT_INHERIT_SET(file, flags, pool, apr_unix_file_cleanup) 371251875Speter 372251875Speter/* We need to do this by hand instead of using APR_IMPLEMENT_INHERIT_UNSET 373251875Speter * because the macro sets both cleanups to the same function, which is not 374251875Speter * suitable on Unix (see PR 41119). */ 375251875SpeterAPR_DECLARE(apr_status_t) apr_file_inherit_unset(apr_file_t *thefile) 376251875Speter{ 377251875Speter if (thefile->flags & APR_FOPEN_NOCLEANUP) { 378251875Speter return APR_EINVAL; 379251875Speter } 380251875Speter if (thefile->flags & APR_INHERIT) { 381251875Speter int flags; 382251875Speter 383251875Speter if ((flags = fcntl(thefile->filedes, F_GETFD)) == -1) 384251875Speter return errno; 385251875Speter 386251875Speter flags |= FD_CLOEXEC; 387251875Speter if (fcntl(thefile->filedes, F_SETFD, flags) == -1) 388251875Speter return errno; 389251875Speter 390251875Speter thefile->flags &= ~APR_INHERIT; 391251875Speter apr_pool_child_cleanup_set(thefile->pool, 392251875Speter (void *)thefile, 393251875Speter apr_unix_file_cleanup, 394251875Speter apr_unix_child_file_cleanup); 395251875Speter } 396251875Speter return APR_SUCCESS; 397251875Speter} 398251875Speter 399251875SpeterAPR_POOL_IMPLEMENT_ACCESSOR(file) 400251875Speter 401251875SpeterAPR_DECLARE(apr_status_t) apr_file_link(const char *from_path, 402251875Speter const char *to_path) 403251875Speter{ 404251875Speter if (link(from_path, to_path) == -1) { 405251875Speter return errno; 406251875Speter } 407251875Speter 408251875Speter return APR_SUCCESS; 409251875Speter} 410