]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/apr/file_io/unix/filedup.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / 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 #ifdef HAVE_DUP3
29     int flags = 0;
30 #endif
31
32     if (which_dup == 2) {
33         if ((*new_file) == NULL) {
34             /* We can't dup2 unless we have a valid new_file */
35             return APR_EINVAL;
36         }
37 #ifdef HAVE_DUP3
38         if (!((*new_file)->flags & (APR_FOPEN_NOCLEANUP|APR_INHERIT)))
39             flags |= O_CLOEXEC;
40         rv = dup3(old_file->filedes, (*new_file)->filedes, flags);
41 #else
42         rv = dup2(old_file->filedes, (*new_file)->filedes);
43         if (!((*new_file)->flags & (APR_FOPEN_NOCLEANUP|APR_INHERIT))) {
44             int flags;
45
46             if (rv == -1)
47                 return errno;
48
49             if ((flags = fcntl((*new_file)->filedes, F_GETFD)) == -1)
50                 return errno;
51
52             flags |= FD_CLOEXEC;
53             if (fcntl((*new_file)->filedes, F_SETFD, flags) == -1)
54                 return errno;
55
56         }
57 #endif
58     } else {
59         rv = dup(old_file->filedes);
60     }
61
62     if (rv == -1)
63         return errno;
64     
65     if (which_dup == 1) {
66         (*new_file) = (apr_file_t *)apr_pcalloc(p, sizeof(apr_file_t));
67         (*new_file)->pool = p;
68         (*new_file)->filedes = rv;
69     }
70
71     (*new_file)->fname = apr_pstrdup(p, old_file->fname);
72     (*new_file)->buffered = old_file->buffered;
73
74     /* If the existing socket in a dup2 is already buffered, we
75      * have an existing and valid (hopefully) mutex, so we don't
76      * want to create it again as we could leak!
77      */
78 #if APR_HAS_THREADS
79     if ((*new_file)->buffered && !(*new_file)->thlock && old_file->thlock) {
80         apr_thread_mutex_create(&((*new_file)->thlock),
81                                 APR_THREAD_MUTEX_DEFAULT, p);
82     }
83 #endif
84     /* As above, only create the buffer if we haven't already
85      * got one.
86      */
87     if ((*new_file)->buffered && !(*new_file)->buffer) {
88         (*new_file)->buffer = apr_palloc(p, old_file->bufsize);
89         (*new_file)->bufsize = old_file->bufsize;
90     }
91
92     /* this is the way dup() works */
93     (*new_file)->blocking = old_file->blocking; 
94
95     /* make sure unget behavior is consistent */
96     (*new_file)->ungetchar = old_file->ungetchar;
97
98     /* apr_file_dup2() retains the original cleanup, reflecting 
99      * the existing inherit and nocleanup flags.  This means, 
100      * that apr_file_dup2() cannot be called against an apr_file_t
101      * already closed with apr_file_close, because the expected
102      * cleanup was already killed.
103      */
104     if (which_dup == 2) {
105         return APR_SUCCESS;
106     }
107
108     /* apr_file_dup() retains all old_file flags with the exceptions
109      * of APR_INHERIT and APR_FOPEN_NOCLEANUP.
110      * The user must call apr_file_inherit_set() on the dupped 
111      * apr_file_t when desired.
112      */
113     (*new_file)->flags = old_file->flags
114                        & ~(APR_INHERIT | APR_FOPEN_NOCLEANUP);
115
116     apr_pool_cleanup_register((*new_file)->pool, (void *)(*new_file),
117                               apr_unix_file_cleanup, 
118                               apr_unix_child_file_cleanup);
119 #ifndef WAITIO_USES_POLL
120     /* Start out with no pollset.  apr_wait_for_io_or_timeout() will
121      * initialize the pollset if needed.
122      */
123     (*new_file)->pollset = NULL;
124 #endif
125     return APR_SUCCESS;
126 }
127
128 APR_DECLARE(apr_status_t) apr_file_dup(apr_file_t **new_file,
129                                        apr_file_t *old_file, apr_pool_t *p)
130 {
131     return file_dup(new_file, old_file, p, 1);
132 }
133
134 APR_DECLARE(apr_status_t) apr_file_dup2(apr_file_t *new_file,
135                                         apr_file_t *old_file, apr_pool_t *p)
136 {
137     return file_dup(&new_file, old_file, p, 2);
138 }
139
140 APR_DECLARE(apr_status_t) apr_file_setaside(apr_file_t **new_file,
141                                             apr_file_t *old_file,
142                                             apr_pool_t *p)
143 {
144     *new_file = (apr_file_t *)apr_palloc(p, sizeof(apr_file_t));
145     memcpy(*new_file, old_file, sizeof(apr_file_t));
146     (*new_file)->pool = p;
147     if (old_file->buffered) {
148         (*new_file)->buffer = apr_palloc(p, old_file->bufsize);
149         (*new_file)->bufsize = old_file->bufsize;
150         if (old_file->direction == 1) {
151             memcpy((*new_file)->buffer, old_file->buffer, old_file->bufpos);
152         }
153         else {
154             memcpy((*new_file)->buffer, old_file->buffer, old_file->dataRead);
155         }
156 #if APR_HAS_THREADS
157         if (old_file->thlock) {
158             apr_thread_mutex_create(&((*new_file)->thlock),
159                                     APR_THREAD_MUTEX_DEFAULT, p);
160             apr_thread_mutex_destroy(old_file->thlock);
161         }
162 #endif /* APR_HAS_THREADS */
163     }
164     if (old_file->fname) {
165         (*new_file)->fname = apr_pstrdup(p, old_file->fname);
166     }
167     if (!(old_file->flags & APR_FOPEN_NOCLEANUP)) {
168         apr_pool_cleanup_register(p, (void *)(*new_file), 
169                                   apr_unix_file_cleanup,
170                                   ((*new_file)->flags & APR_INHERIT)
171                                      ? apr_pool_cleanup_null
172                                      : apr_unix_child_file_cleanup);
173     }
174
175     old_file->filedes = -1;
176     apr_pool_cleanup_kill(old_file->pool, (void *)old_file,
177                           apr_unix_file_cleanup);
178 #ifndef WAITIO_USES_POLL
179     (*new_file)->pollset = NULL;
180 #endif
181     return APR_SUCCESS;
182 }