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 23251875Speterstatic apr_status_t file_dup(apr_file_t **new_file, 24251875Speter apr_file_t *old_file, apr_pool_t *p, 25251875Speter int which_dup) 26251875Speter{ 27251875Speter int rv; 28251875Speter#ifdef HAVE_DUP3 29251875Speter int flags = 0; 30251875Speter#endif 31251875Speter 32251875Speter if (which_dup == 2) { 33251875Speter if ((*new_file) == NULL) { 34251875Speter /* We can't dup2 unless we have a valid new_file */ 35251875Speter return APR_EINVAL; 36251875Speter } 37251875Speter#ifdef HAVE_DUP3 38251875Speter if (!((*new_file)->flags & (APR_FOPEN_NOCLEANUP|APR_INHERIT))) 39251875Speter flags |= O_CLOEXEC; 40251875Speter rv = dup3(old_file->filedes, (*new_file)->filedes, flags); 41251875Speter#else 42251875Speter rv = dup2(old_file->filedes, (*new_file)->filedes); 43251875Speter if (!((*new_file)->flags & (APR_FOPEN_NOCLEANUP|APR_INHERIT))) { 44251875Speter int flags; 45251875Speter 46251875Speter if (rv == -1) 47251875Speter return errno; 48251875Speter 49251875Speter if ((flags = fcntl((*new_file)->filedes, F_GETFD)) == -1) 50251875Speter return errno; 51251875Speter 52251875Speter flags |= FD_CLOEXEC; 53251875Speter if (fcntl((*new_file)->filedes, F_SETFD, flags) == -1) 54251875Speter return errno; 55251875Speter 56251875Speter } 57251875Speter#endif 58251875Speter } else { 59251875Speter rv = dup(old_file->filedes); 60251875Speter } 61251875Speter 62251875Speter if (rv == -1) 63251875Speter return errno; 64251875Speter 65251875Speter if (which_dup == 1) { 66251875Speter (*new_file) = (apr_file_t *)apr_pcalloc(p, sizeof(apr_file_t)); 67251875Speter (*new_file)->pool = p; 68251875Speter (*new_file)->filedes = rv; 69251875Speter } 70251875Speter 71251875Speter (*new_file)->fname = apr_pstrdup(p, old_file->fname); 72251875Speter (*new_file)->buffered = old_file->buffered; 73251875Speter 74251875Speter /* If the existing socket in a dup2 is already buffered, we 75251875Speter * have an existing and valid (hopefully) mutex, so we don't 76251875Speter * want to create it again as we could leak! 77251875Speter */ 78251875Speter#if APR_HAS_THREADS 79251875Speter if ((*new_file)->buffered && !(*new_file)->thlock && old_file->thlock) { 80251875Speter apr_thread_mutex_create(&((*new_file)->thlock), 81251875Speter APR_THREAD_MUTEX_DEFAULT, p); 82251875Speter } 83251875Speter#endif 84251875Speter /* As above, only create the buffer if we haven't already 85251875Speter * got one. 86251875Speter */ 87251875Speter if ((*new_file)->buffered && !(*new_file)->buffer) { 88251875Speter (*new_file)->buffer = apr_palloc(p, old_file->bufsize); 89251875Speter (*new_file)->bufsize = old_file->bufsize; 90251875Speter } 91251875Speter 92251875Speter /* this is the way dup() works */ 93251875Speter (*new_file)->blocking = old_file->blocking; 94251875Speter 95251875Speter /* make sure unget behavior is consistent */ 96251875Speter (*new_file)->ungetchar = old_file->ungetchar; 97251875Speter 98251875Speter /* apr_file_dup2() retains the original cleanup, reflecting 99251875Speter * the existing inherit and nocleanup flags. This means, 100251875Speter * that apr_file_dup2() cannot be called against an apr_file_t 101251875Speter * already closed with apr_file_close, because the expected 102251875Speter * cleanup was already killed. 103251875Speter */ 104251875Speter if (which_dup == 2) { 105251875Speter return APR_SUCCESS; 106251875Speter } 107251875Speter 108251875Speter /* apr_file_dup() retains all old_file flags with the exceptions 109251875Speter * of APR_INHERIT and APR_FOPEN_NOCLEANUP. 110251875Speter * The user must call apr_file_inherit_set() on the dupped 111251875Speter * apr_file_t when desired. 112251875Speter */ 113251875Speter (*new_file)->flags = old_file->flags 114251875Speter & ~(APR_INHERIT | APR_FOPEN_NOCLEANUP); 115251875Speter 116251875Speter apr_pool_cleanup_register((*new_file)->pool, (void *)(*new_file), 117251875Speter apr_unix_file_cleanup, 118251875Speter apr_unix_child_file_cleanup); 119251875Speter#ifndef WAITIO_USES_POLL 120251875Speter /* Start out with no pollset. apr_wait_for_io_or_timeout() will 121251875Speter * initialize the pollset if needed. 122251875Speter */ 123251875Speter (*new_file)->pollset = NULL; 124251875Speter#endif 125251875Speter return APR_SUCCESS; 126251875Speter} 127251875Speter 128251875SpeterAPR_DECLARE(apr_status_t) apr_file_dup(apr_file_t **new_file, 129251875Speter apr_file_t *old_file, apr_pool_t *p) 130251875Speter{ 131251875Speter return file_dup(new_file, old_file, p, 1); 132251875Speter} 133251875Speter 134251875SpeterAPR_DECLARE(apr_status_t) apr_file_dup2(apr_file_t *new_file, 135251875Speter apr_file_t *old_file, apr_pool_t *p) 136251875Speter{ 137251875Speter return file_dup(&new_file, old_file, p, 2); 138251875Speter} 139251875Speter 140251875SpeterAPR_DECLARE(apr_status_t) apr_file_setaside(apr_file_t **new_file, 141251875Speter apr_file_t *old_file, 142251875Speter apr_pool_t *p) 143251875Speter{ 144251875Speter *new_file = (apr_file_t *)apr_palloc(p, sizeof(apr_file_t)); 145251875Speter memcpy(*new_file, old_file, sizeof(apr_file_t)); 146251875Speter (*new_file)->pool = p; 147251875Speter if (old_file->buffered) { 148251875Speter (*new_file)->buffer = apr_palloc(p, old_file->bufsize); 149251875Speter (*new_file)->bufsize = old_file->bufsize; 150251875Speter if (old_file->direction == 1) { 151251875Speter memcpy((*new_file)->buffer, old_file->buffer, old_file->bufpos); 152251875Speter } 153251875Speter else { 154251875Speter memcpy((*new_file)->buffer, old_file->buffer, old_file->dataRead); 155251875Speter } 156251875Speter#if APR_HAS_THREADS 157251875Speter if (old_file->thlock) { 158251875Speter apr_thread_mutex_create(&((*new_file)->thlock), 159251875Speter APR_THREAD_MUTEX_DEFAULT, p); 160251875Speter apr_thread_mutex_destroy(old_file->thlock); 161251875Speter } 162251875Speter#endif /* APR_HAS_THREADS */ 163251875Speter } 164251875Speter if (old_file->fname) { 165251875Speter (*new_file)->fname = apr_pstrdup(p, old_file->fname); 166251875Speter } 167251875Speter if (!(old_file->flags & APR_FOPEN_NOCLEANUP)) { 168251875Speter apr_pool_cleanup_register(p, (void *)(*new_file), 169251875Speter apr_unix_file_cleanup, 170251875Speter ((*new_file)->flags & APR_INHERIT) 171251875Speter ? apr_pool_cleanup_null 172251875Speter : apr_unix_child_file_cleanup); 173251875Speter } 174251875Speter 175251875Speter old_file->filedes = -1; 176251875Speter apr_pool_cleanup_kill(old_file->pool, (void *)old_file, 177251875Speter apr_unix_file_cleanup); 178251875Speter#ifndef WAITIO_USES_POLL 179251875Speter (*new_file)->pollset = NULL; 180251875Speter#endif 181251875Speter return APR_SUCCESS; 182251875Speter} 183