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