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