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_file_io.h" |
19 |
#include "apr_general.h" |
20 |
#include "apr_strings.h" |
21 |
#include <string.h> |
22 |
#include "apr_arch_inherit.h" |
23 |
#include <io.h> /* for [_open/_get]_osfhandle */ |
24 |
|
25 |
|
26 |
APR_DECLARE(apr_status_t) apr_file_dup(apr_file_t **new_file, |
27 |
apr_file_t *old_file, apr_pool_t *p) |
28 |
{ |
29 |
#ifdef _WIN32_WCE |
30 |
return APR_ENOTIMPL; |
31 |
#else |
32 |
HANDLE hproc = GetCurrentProcess(); |
33 |
HANDLE newhand = NULL; |
34 |
|
35 |
if (!DuplicateHandle(hproc, old_file->filehand, |
36 |
hproc, &newhand, 0, FALSE, |
37 |
DUPLICATE_SAME_ACCESS)) { |
38 |
return apr_get_os_error(); |
39 |
} |
40 |
|
41 |
(*new_file) = (apr_file_t *) apr_pcalloc(p, sizeof(apr_file_t)); |
42 |
(*new_file)->filehand = newhand; |
43 |
(*new_file)->flags = old_file->flags & ~(APR_STD_FLAGS | APR_INHERIT); |
44 |
(*new_file)->pool = p; |
45 |
(*new_file)->fname = apr_pstrdup(p, old_file->fname); |
46 |
(*new_file)->append = old_file->append; |
47 |
(*new_file)->buffered = FALSE; |
48 |
(*new_file)->ungetchar = old_file->ungetchar; |
49 |
|
50 |
#if APR_HAS_THREADS |
51 |
if (old_file->mutex) { |
52 |
apr_thread_mutex_create(&((*new_file)->mutex), |
53 |
APR_THREAD_MUTEX_DEFAULT, p); |
54 |
} |
55 |
#endif |
56 |
|
57 |
apr_pool_cleanup_register((*new_file)->pool, (void *)(*new_file), file_cleanup, |
58 |
apr_pool_cleanup_null); |
59 |
|
60 |
#if APR_FILES_AS_SOCKETS |
61 |
/* Create a pollset with room for one descriptor. */ |
62 |
/* ### check return codes */ |
63 |
(void) apr_pollset_create(&(*new_file)->pollset, 1, p, 0); |
64 |
#endif |
65 |
return APR_SUCCESS; |
66 |
#endif /* !defined(_WIN32_WCE) */ |
67 |
} |
68 |
|
69 |
APR_DECLARE(apr_status_t) apr_file_dup2(apr_file_t *new_file, |
70 |
apr_file_t *old_file, apr_pool_t *p) |
71 |
{ |
72 |
#ifdef _WIN32_WCE |
73 |
return APR_ENOTIMPL; |
74 |
#else |
75 |
HANDLE hproc = GetCurrentProcess(); |
76 |
HANDLE newhand = NULL; |
77 |
apr_int32_t newflags; |
78 |
int fd; |
79 |
|
80 |
if (new_file->flags & APR_STD_FLAGS) |
81 |
{ |
82 |
if ((new_file->flags & APR_STD_FLAGS) == APR_STDERR_FLAG) |
83 |
{ |
84 |
/* Flush stderr and unset its buffer, then commit the fd-based buffer. |
85 |
* This is typically a noop for Win2K/XP since services with NULL std |
86 |
* handles [but valid FILE *'s, oddly enough], but is required |
87 |
* for NT 4.0 and to use this code outside of services. |
88 |
*/ |
89 |
fflush(stderr); |
90 |
setvbuf(stderr, NULL, _IONBF, 0); |
91 |
if (!_isatty(2)) { |
92 |
_commit(2 /* stderr */); |
93 |
} |
94 |
|
95 |
/* Clone a handle can _close() without harming the source handle, |
96 |
* open an MSVCRT-based pseudo-fd for the file handle, then dup2 |
97 |
* and close our temporary pseudo-fd once it's been duplicated. |
98 |
* This will incidently keep the FILE-based stderr in sync. |
99 |
* Note the apparently redundant _O_BINARY coersions are required. |
100 |
* Note the _dup2 will close the previous std Win32 handle. |
101 |
*/ |
102 |
if (!DuplicateHandle(hproc, old_file->filehand, hproc, &newhand, |
103 |
0, FALSE, DUPLICATE_SAME_ACCESS)) { |
104 |
return apr_get_os_error(); |
105 |
} |
106 |
fd = _open_osfhandle((INT_PTR)newhand, _O_WRONLY | _O_BINARY); |
107 |
_dup2(fd, 2); |
108 |
_close(fd); |
109 |
_setmode(2, _O_BINARY); |
110 |
|
111 |
/* hPipeWrite was _close()'ed above, and _dup2()'ed |
112 |
* to fd 2 creating a new, inherited Win32 handle. |
113 |
* Recover that real handle from fd 2. Note that |
114 |
* SetStdHandle(STD_ERROR_HANDLE, _get_osfhandle(2)) |
115 |
* is implicit in the dup2() call above |
116 |
*/ |
117 |
newhand = (HANDLE)_get_osfhandle(2); |
118 |
} |
119 |
else if ((new_file->flags & APR_STD_FLAGS) == APR_STDOUT_FLAG) { |
120 |
/* For the process flow see the stderr case above */ |
121 |
fflush(stdout); |
122 |
setvbuf(stdout, NULL, _IONBF, 0); |
123 |
if (!_isatty(1)) { |
124 |
_commit(1 /* stdout */); |
125 |
} |
126 |
|
127 |
if (!DuplicateHandle(hproc, old_file->filehand, hproc, &newhand, |
128 |
0, FALSE, DUPLICATE_SAME_ACCESS)) { |
129 |
return apr_get_os_error(); |
130 |
} |
131 |
fd = _open_osfhandle((INT_PTR)newhand, _O_WRONLY | _O_BINARY); |
132 |
_dup2(fd, 1); |
133 |
_close(fd); |
134 |
_setmode(1, _O_BINARY); |
135 |
newhand = (HANDLE)_get_osfhandle(1); |
136 |
} |
137 |
else if ((new_file->flags & APR_STD_FLAGS) == APR_STDIN_FLAG) { |
138 |
/* For the process flow see the stderr case above */ |
139 |
fflush(stdin); |
140 |
setvbuf(stdin, NULL, _IONBF, 0); |
141 |
|
142 |
if (!DuplicateHandle(hproc, old_file->filehand, hproc, &newhand, |
143 |
0, FALSE, DUPLICATE_SAME_ACCESS)) { |
144 |
return apr_get_os_error(); |
145 |
} |
146 |
fd = _open_osfhandle((INT_PTR)newhand, _O_RDONLY | _O_BINARY); |
147 |
_dup2(fd, 0); |
148 |
_close(fd); |
149 |
_setmode(0, _O_BINARY); |
150 |
newhand = (HANDLE)_get_osfhandle(0); |
151 |
} |
152 |
newflags = (new_file->flags & APR_STD_FLAGS) |
153 |
| (old_file->flags & ~APR_STD_FLAGS) | APR_INHERIT; |
154 |
|
155 |
/* No need to close the old file, _dup2() above did that for us */ |
156 |
} |
157 |
else { |
158 |
if (!DuplicateHandle(hproc, old_file->filehand, |
159 |
hproc, &newhand, 0, |
160 |
FALSE, DUPLICATE_SAME_ACCESS)) { |
161 |
return apr_get_os_error(); |
162 |
} |
163 |
newflags = old_file->flags & ~(APR_STD_FLAGS | APR_INHERIT); |
164 |
|
165 |
if (new_file->filehand |
166 |
&& (new_file->filehand != INVALID_HANDLE_VALUE)) { |
167 |
CloseHandle(new_file->filehand); |
168 |
} |
169 |
} |
170 |
|
171 |
new_file->flags = newflags; |
172 |
new_file->filehand = newhand; |
173 |
new_file->fname = apr_pstrdup(new_file->pool, old_file->fname); |
174 |
new_file->append = old_file->append; |
175 |
new_file->buffered = FALSE; |
176 |
new_file->ungetchar = old_file->ungetchar; |
177 |
|
178 |
#if APR_HAS_THREADS |
179 |
if (old_file->mutex) { |
180 |
apr_thread_mutex_create(&(new_file->mutex), |
181 |
APR_THREAD_MUTEX_DEFAULT, p); |
182 |
} |
183 |
#endif |
184 |
|
185 |
return APR_SUCCESS; |
186 |
#endif /* !defined(_WIN32_WCE) */ |
187 |
} |
188 |
|
189 |
APR_DECLARE(apr_status_t) apr_file_setaside(apr_file_t **new_file, |
190 |
apr_file_t *old_file, |
191 |
apr_pool_t *p) |
192 |
{ |
193 |
*new_file = (apr_file_t *)apr_pmemdup(p, old_file, sizeof(apr_file_t)); |
194 |
(*new_file)->pool = p; |
195 |
if (old_file->buffered) { |
196 |
(*new_file)->buffer = apr_palloc(p, old_file->bufsize); |
197 |
(*new_file)->bufsize = old_file->bufsize; |
198 |
if (old_file->direction == 1) { |
199 |
memcpy((*new_file)->buffer, old_file->buffer, old_file->bufpos); |
200 |
} |
201 |
else { |
202 |
memcpy((*new_file)->buffer, old_file->buffer, old_file->dataRead); |
203 |
} |
204 |
} |
205 |
if (old_file->mutex) { |
206 |
apr_thread_mutex_create(&((*new_file)->mutex), |
207 |
APR_THREAD_MUTEX_DEFAULT, p); |
208 |
apr_thread_mutex_destroy(old_file->mutex); |
209 |
} |
210 |
if (old_file->fname) { |
211 |
(*new_file)->fname = apr_pstrdup(p, old_file->fname); |
212 |
} |
213 |
if (!(old_file->flags & APR_FOPEN_NOCLEANUP)) { |
214 |
apr_pool_cleanup_register(p, (void *)(*new_file), |
215 |
file_cleanup, |
216 |
file_cleanup); |
217 |
} |
218 |
|
219 |
old_file->filehand = INVALID_HANDLE_VALUE; |
220 |
apr_pool_cleanup_kill(old_file->pool, (void *)old_file, |
221 |
file_cleanup); |
222 |
|
223 |
#if APR_FILES_AS_SOCKETS |
224 |
/* Create a pollset with room for one descriptor. */ |
225 |
/* ### check return codes */ |
226 |
(void) apr_pollset_create(&(*new_file)->pollset, 1, p, 0); |
227 |
#endif |
228 |
return APR_SUCCESS; |
229 |
} |