upload http
[bottlenecks.git] / rubbos / app / httpd-2.0.64 / srclib / apr / file_io / unix / filedup.c
1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2  * contributor license agreements.  See the NOTICE file distributed with
3  * this work for additional information regarding copyright ownership.
4  * The ASF licenses this file to You under the Apache License, Version 2.0
5  * (the "License"); you may not use this file except in compliance with
6  * the License.  You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include "apr_arch_file_io.h"
18 #include "apr_strings.h"
19 #include "apr_portable.h"
20 #include "apr_thread_mutex.h"
21 #include "apr_arch_inherit.h"
22
23 static apr_status_t _file_dup(apr_file_t **new_file, 
24                               apr_file_t *old_file, apr_pool_t *p,
25                               int which_dup)
26 {
27     int rv;
28     
29     if (which_dup == 2) {
30         if ((*new_file) == NULL) {
31             /* We can't dup2 unless we have a valid new_file */
32             return APR_EINVAL;
33         }
34         rv = dup2(old_file->filedes, (*new_file)->filedes);
35     } else {
36         rv = dup(old_file->filedes);
37     }
38
39     if (rv == -1)
40         return errno;
41     
42     if (which_dup == 1) {
43         (*new_file) = (apr_file_t *)apr_pcalloc(p, sizeof(apr_file_t));
44         (*new_file)->pool = p;
45         (*new_file)->filedes = rv;
46     }
47
48     (*new_file)->fname = apr_pstrdup(p, old_file->fname);
49     (*new_file)->buffered = old_file->buffered;
50
51     /* If the existing socket in a dup2 is already buffered, we
52      * have an existing and valid (hopefully) mutex, so we don't
53      * want to create it again as we could leak!
54      */
55 #if APR_HAS_THREADS
56     if ((*new_file)->buffered && !(*new_file)->thlock && old_file->thlock) {
57         apr_thread_mutex_create(&((*new_file)->thlock),
58                                 APR_THREAD_MUTEX_DEFAULT, p);
59     }
60 #endif
61     /* As above, only create the buffer if we haven't already
62      * got one.
63      */
64     if ((*new_file)->buffered && !(*new_file)->buffer) {
65         (*new_file)->buffer = apr_palloc(p, APR_FILE_BUFSIZE);
66     }
67
68     /* this is the way dup() works */
69     (*new_file)->blocking = old_file->blocking; 
70
71     /* make sure unget behavior is consistent */
72     (*new_file)->ungetchar = old_file->ungetchar;
73
74     /* apr_file_dup2() retains the original cleanup, reflecting 
75      * the existing inherit and nocleanup flags.  This means, 
76      * that apr_file_dup2() cannot be called against an apr_file_t
77      * already closed with apr_file_close, because the expected
78      * cleanup was already killed.
79      */
80     if (which_dup == 2) {
81         return APR_SUCCESS;
82     }
83
84     /* apr_file_dup() retains all old_file flags with the exceptions
85      * of APR_INHERIT and APR_FILE_NOCLEANUP.
86      * The user must call apr_file_inherit_set() on the dupped 
87      * apr_file_t when desired.
88      */
89     (*new_file)->flags = old_file->flags
90                        & ~(APR_INHERIT | APR_FILE_NOCLEANUP);
91
92     apr_pool_cleanup_register((*new_file)->pool, (void *)(*new_file),
93                               apr_unix_file_cleanup, 
94                               apr_unix_child_file_cleanup);
95
96     return APR_SUCCESS;
97 }
98
99 APR_DECLARE(apr_status_t) apr_file_dup(apr_file_t **new_file,
100                                        apr_file_t *old_file, apr_pool_t *p)
101 {
102     return _file_dup(new_file, old_file, p, 1);
103 }
104
105 APR_DECLARE(apr_status_t) apr_file_dup2(apr_file_t *new_file,
106                                         apr_file_t *old_file, apr_pool_t *p)
107 {
108     return _file_dup(&new_file, old_file, p, 2);
109 }
110
111 APR_DECLARE(apr_status_t) apr_file_setaside(apr_file_t **new_file,
112                                             apr_file_t *old_file,
113                                             apr_pool_t *p)
114 {
115     *new_file = (apr_file_t *)apr_palloc(p, sizeof(apr_file_t));
116     memcpy(*new_file, old_file, sizeof(apr_file_t));
117     (*new_file)->pool = p;
118     if (old_file->buffered) {
119         (*new_file)->buffer = apr_palloc(p, APR_FILE_BUFSIZE);
120         if (old_file->direction == 1) {
121             memcpy((*new_file)->buffer, old_file->buffer, old_file->bufpos);
122         }
123         else {
124             memcpy((*new_file)->buffer, old_file->buffer, old_file->dataRead);
125         }
126 #if APR_HAS_THREADS
127         if (old_file->thlock) {
128             apr_thread_mutex_create(&((*new_file)->thlock),
129                                     APR_THREAD_MUTEX_DEFAULT, p);
130             apr_thread_mutex_destroy(old_file->thlock);
131         }
132 #endif /* APR_HAS_THREADS */
133     }
134     if (old_file->fname) {
135         (*new_file)->fname = apr_pstrdup(p, old_file->fname);
136     }
137     if (!(old_file->flags & APR_FILE_NOCLEANUP)) {
138         apr_pool_cleanup_register(p, (void *)(*new_file), 
139                                   apr_unix_file_cleanup,
140                                   ((*new_file)->flags & APR_INHERIT)
141                                      ? apr_pool_cleanup_null
142                                      : apr_unix_child_file_cleanup);
143     }
144
145     old_file->filedes = -1;
146     apr_pool_cleanup_kill(old_file->pool, (void *)old_file,
147                           apr_unix_file_cleanup);
148     return APR_SUCCESS;
149 }