		/* Copyright 2000-2004 The Apache Software Foundation
		 *
		 * Licensed under the Apache License, Version 2.0 (the "License");
		 * you may not use this file except in compliance with the License.
		 * You may obtain a copy of the License at
		 *
		 *     http://www.apache.org/licenses/LICENSE-2.0
		 *
		 * Unless required by applicable law or agreed to in writing, software
		 * distributed under the License is distributed on an "AS IS" BASIS,
		 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
		 * See the License for the specific language governing permissions and
		 * limitations under the License.
		 */
		
		#include "apr_arch_file_io.h"
		#include "apr_strings.h"
		#include "apr_portable.h"
		#include "apr_thread_mutex.h"
		#include "apr_arch_inherit.h"
		
		static apr_status_t file_dup(apr_file_t **new_file, 
		                             apr_file_t *old_file, apr_pool_t *p,
		                             int which_dup)
          11    {
          11        int rv;
		    
          11        if (which_dup == 2) {
           7            if ((*new_file) == NULL) {
		            /* We can't dup2 unless we have a valid new_file */
      ######                return APR_EINVAL;
		        }
           7            rv = dup2(old_file->filedes, (*new_file)->filedes);
		    } else {
           4            rv = dup(old_file->filedes);
		    }
		
          11        if (rv == -1)
      ######            return errno;
		    
          11        if (which_dup == 1) {
           4            (*new_file) = (apr_file_t *)apr_pcalloc(p, sizeof(apr_file_t));
           4            (*new_file)->pool = p;
           4            (*new_file)->filedes = rv;
		    }
		
          11        (*new_file)->fname = apr_pstrdup(p, old_file->fname);
          11        (*new_file)->buffered = old_file->buffered;
		
		    /* If the existing socket in a dup2 is already buffered, we
		     * have an existing and valid (hopefully) mutex, so we don't
		     * want to create it again as we could leak!
		     */
		#if APR_HAS_THREADS
          11        if ((*new_file)->buffered && !(*new_file)->thlock && old_file->thlock) {
      ######            apr_thread_mutex_create(&((*new_file)->thlock),
		                                APR_THREAD_MUTEX_DEFAULT, p);
		    }
		#endif
		    /* As above, only create the buffer if we haven't already
		     * got one.
		     */
          11        if ((*new_file)->buffered && !(*new_file)->buffer) {
      ######            (*new_file)->buffer = apr_palloc(p, APR_FILE_BUFSIZE);
		    }
		
		    /* this is the way dup() works */
          11        (*new_file)->blocking = old_file->blocking; 
		
		    /* make sure unget behavior is consistent */
          11        (*new_file)->ungetchar = old_file->ungetchar;
		
		    /* apr_file_dup2() retains the original cleanup, reflecting 
		     * the existing inherit and nocleanup flags.  This means, 
		     * that apr_file_dup2() cannot be called against an apr_file_t
		     * already closed with apr_file_close, because the expected
		     * cleanup was already killed.
		     */
          11        if (which_dup == 2) {
           7            return APR_SUCCESS;
		    }
		
		    /* apr_file_dup() retains all old_file flags with the exceptions
		     * of APR_INHERIT and APR_FILE_NOCLEANUP.
		     * The user must call apr_file_inherit_set() on the dupped 
		     * apr_file_t when desired.
		     */
           4        (*new_file)->flags = old_file->flags
		                       & ~(APR_INHERIT | APR_FILE_NOCLEANUP);
		
           4        apr_pool_cleanup_register((*new_file)->pool, (void *)(*new_file),
		                              apr_unix_file_cleanup, 
		                              apr_unix_file_cleanup);
		#ifndef WAITIO_USES_POLL
		    /* Create a pollset with room for one descriptor. */
		    /* ### check return codes */
		    (void) apr_pollset_create(&(*new_file)->pollset, 1, p, 0);
		#endif
           4        return APR_SUCCESS;
		}
		
		APR_DECLARE(apr_status_t) apr_file_dup(apr_file_t **new_file,
		                                       apr_file_t *old_file, apr_pool_t *p)
           4    {
           4        return file_dup(new_file, old_file, p, 1);
		}
		
		APR_DECLARE(apr_status_t) apr_file_dup2(apr_file_t *new_file,
		                                        apr_file_t *old_file, apr_pool_t *p)
           7    {
           7        return file_dup(&new_file, old_file, p, 2);
		}
		
		APR_DECLARE(apr_status_t) apr_file_setaside(apr_file_t **new_file,
		                                            apr_file_t *old_file,
		                                            apr_pool_t *p)
      ######    {
      ######        *new_file = (apr_file_t *)apr_palloc(p, sizeof(apr_file_t));
      ######        memcpy(*new_file, old_file, sizeof(apr_file_t));
      ######        (*new_file)->pool = p;
      ######        if (old_file->buffered) {
      ######            (*new_file)->buffer = apr_palloc(p, APR_FILE_BUFSIZE);
      ######            if (old_file->direction == 1) {
      ######                memcpy((*new_file)->buffer, old_file->buffer, old_file->bufpos);
		        }
		        else {
      ######                memcpy((*new_file)->buffer, old_file->buffer, old_file->dataRead);
		        }
		#if APR_HAS_THREADS
      ######            if (old_file->thlock) {
      ######                apr_thread_mutex_create(&((*new_file)->thlock),
		                                    APR_THREAD_MUTEX_DEFAULT, p);
      ######                apr_thread_mutex_destroy(old_file->thlock);
		        }
		#endif /* APR_HAS_THREADS */
		    }
      ######        if (old_file->fname) {
      ######            (*new_file)->fname = apr_pstrdup(p, old_file->fname);
		    }
      ######        if (!(old_file->flags & APR_FILE_NOCLEANUP)) {
      ######            apr_pool_cleanup_register(p, (void *)(*new_file), 
		                                  apr_unix_file_cleanup,
		                                  ((*new_file)->flags & APR_INHERIT)
		                                     ? apr_pool_cleanup_null
		                                     : apr_unix_file_cleanup);
		    }
		
      ######        old_file->filedes = -1;
      ######        apr_pool_cleanup_kill(old_file->pool, (void *)old_file,
		                          apr_unix_file_cleanup);
		#ifndef WAITIO_USES_POLL
		    /* Create a pollset with room for one descriptor. */
		    /* ### check return codes */
		    (void) apr_pollset_create(&(*new_file)->pollset, 1, p, 0);
		#endif
      ######        return APR_SUCCESS;
		}
