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_lib.h" 20#include "apr_portable.h" 21#include "apr_strings.h" 22#include "apr_arch_inherit.h" 23#include <string.h> 24 25apr_status_t apr_file_cleanup(void *thefile) 26{ 27 apr_file_t *file = thefile; 28 return apr_file_close(file); 29} 30 31 32 33APR_DECLARE(apr_status_t) apr_file_open(apr_file_t **new, const char *fname, apr_int32_t flag, apr_fileperms_t perm, apr_pool_t *pool) 34{ 35 int oflags = 0; 36 int mflags = OPEN_FLAGS_FAIL_ON_ERROR|OPEN_SHARE_DENYNONE|OPEN_FLAGS_NOINHERIT; 37 int rv; 38 ULONG action; 39 apr_file_t *dafile = (apr_file_t *)apr_palloc(pool, sizeof(apr_file_t)); 40 41 dafile->pool = pool; 42 dafile->isopen = FALSE; 43 dafile->eof_hit = FALSE; 44 dafile->buffer = NULL; 45 dafile->flags = flag; 46 dafile->blocking = BLK_ON; 47 48 if ((flag & APR_FOPEN_READ) && (flag & APR_FOPEN_WRITE)) { 49 mflags |= OPEN_ACCESS_READWRITE; 50 } else if (flag & APR_FOPEN_READ) { 51 mflags |= OPEN_ACCESS_READONLY; 52 } else if (flag & APR_FOPEN_WRITE) { 53 mflags |= OPEN_ACCESS_WRITEONLY; 54 } else { 55 dafile->filedes = -1; 56 return APR_EACCES; 57 } 58 59 dafile->buffered = (flag & APR_FOPEN_BUFFERED) > 0; 60 61 if (dafile->buffered) { 62 dafile->buffer = apr_palloc(pool, APR_FILE_DEFAULT_BUFSIZE); 63 dafile->bufsize = APR_FILE_DEFAULT_BUFSIZE; 64 rv = apr_thread_mutex_create(&dafile->mutex, 0, pool); 65 66 if (rv) 67 return rv; 68 } 69 70 if (flag & APR_FOPEN_CREATE) { 71 oflags |= OPEN_ACTION_CREATE_IF_NEW; 72 73 if (!(flag & APR_FOPEN_EXCL) && !(flag & APR_FOPEN_TRUNCATE)) { 74 oflags |= OPEN_ACTION_OPEN_IF_EXISTS; 75 } 76 } 77 78 if ((flag & APR_FOPEN_EXCL) && !(flag & APR_FOPEN_CREATE)) 79 return APR_EACCES; 80 81 if (flag & APR_FOPEN_TRUNCATE) { 82 oflags |= OPEN_ACTION_REPLACE_IF_EXISTS; 83 } else if ((oflags & 0xFF) == 0) { 84 oflags |= OPEN_ACTION_OPEN_IF_EXISTS; 85 } 86 87 rv = DosOpen(fname, &(dafile->filedes), &action, 0, 0, oflags, mflags, NULL); 88 89 if (rv == 0 && (flag & APR_FOPEN_APPEND)) { 90 ULONG newptr; 91 rv = DosSetFilePtr(dafile->filedes, 0, FILE_END, &newptr ); 92 93 if (rv) 94 DosClose(dafile->filedes); 95 } 96 97 if (rv != 0) 98 return APR_FROM_OS_ERROR(rv); 99 100 dafile->isopen = TRUE; 101 dafile->fname = apr_pstrdup(pool, fname); 102 dafile->filePtr = 0; 103 dafile->bufpos = 0; 104 dafile->dataRead = 0; 105 dafile->direction = 0; 106 dafile->pipe = FALSE; 107 108 if (!(flag & APR_FOPEN_NOCLEANUP)) { 109 apr_pool_cleanup_register(dafile->pool, dafile, apr_file_cleanup, apr_file_cleanup); 110 } 111 112 *new = dafile; 113 return APR_SUCCESS; 114} 115 116 117 118APR_DECLARE(apr_status_t) apr_file_close(apr_file_t *file) 119{ 120 ULONG rc; 121 apr_status_t status; 122 123 if (file && file->isopen) { 124 /* XXX: flush here is not mutex protected */ 125 status = apr_file_flush(file); 126 rc = DosClose(file->filedes); 127 128 if (rc == 0) { 129 file->isopen = FALSE; 130 131 if (file->flags & APR_FOPEN_DELONCLOSE) { 132 status = APR_FROM_OS_ERROR(DosDelete(file->fname)); 133 } 134 /* else we return the status of the flush attempt 135 * when all else succeeds 136 */ 137 } else { 138 return APR_FROM_OS_ERROR(rc); 139 } 140 } 141 142 if (file->buffered) 143 apr_thread_mutex_destroy(file->mutex); 144 145 return status; 146} 147 148 149 150APR_DECLARE(apr_status_t) apr_file_remove(const char *path, apr_pool_t *pool) 151{ 152 ULONG rc = DosDelete(path); 153 return APR_FROM_OS_ERROR(rc); 154} 155 156 157 158APR_DECLARE(apr_status_t) apr_file_rename(const char *from_path, const char *to_path, 159 apr_pool_t *p) 160{ 161 ULONG rc = DosMove(from_path, to_path); 162 163 if (rc == ERROR_ACCESS_DENIED || rc == ERROR_ALREADY_EXISTS) { 164 rc = DosDelete(to_path); 165 166 if (rc == 0 || rc == ERROR_FILE_NOT_FOUND) { 167 rc = DosMove(from_path, to_path); 168 } 169 } 170 171 return APR_FROM_OS_ERROR(rc); 172} 173 174 175 176APR_DECLARE(apr_status_t) apr_os_file_get(apr_os_file_t *thefile, apr_file_t *file) 177{ 178 *thefile = file->filedes; 179 return APR_SUCCESS; 180} 181 182 183 184APR_DECLARE(apr_status_t) apr_os_file_put(apr_file_t **file, apr_os_file_t *thefile, apr_int32_t flags, apr_pool_t *pool) 185{ 186 apr_os_file_t *dafile = thefile; 187 188 (*file) = apr_palloc(pool, sizeof(apr_file_t)); 189 (*file)->pool = pool; 190 (*file)->filedes = *dafile; 191 (*file)->isopen = TRUE; 192 (*file)->eof_hit = FALSE; 193 (*file)->flags = flags; 194 (*file)->pipe = FALSE; 195 (*file)->buffered = (flags & APR_FOPEN_BUFFERED) > 0; 196 197 if ((*file)->buffered) { 198 apr_status_t rv; 199 200 (*file)->buffer = apr_palloc(pool, APR_FILE_DEFAULT_BUFSIZE); 201 (*file)->bufsize = APR_FILE_DEFAULT_BUFSIZE; 202 rv = apr_thread_mutex_create(&(*file)->mutex, 0, pool); 203 204 if (rv) 205 return rv; 206 } 207 208 return APR_SUCCESS; 209} 210 211 212APR_DECLARE(apr_status_t) apr_file_eof(apr_file_t *fptr) 213{ 214 if (!fptr->isopen || fptr->eof_hit == 1) { 215 return APR_EOF; 216 } 217 return APR_SUCCESS; 218} 219 220 221APR_DECLARE(apr_status_t) apr_file_open_flags_stderr(apr_file_t **thefile, 222 apr_int32_t flags, 223 apr_pool_t *pool) 224{ 225 apr_os_file_t fd = 2; 226 227 return apr_os_file_put(thefile, &fd, flags | APR_FOPEN_WRITE, pool); 228} 229 230 231APR_DECLARE(apr_status_t) apr_file_open_flags_stdout(apr_file_t **thefile, 232 apr_int32_t flags, 233 apr_pool_t *pool) 234{ 235 apr_os_file_t fd = 1; 236 237 return apr_os_file_put(thefile, &fd, flags | APR_FOPEN_WRITE, pool); 238} 239 240 241APR_DECLARE(apr_status_t) apr_file_open_flags_stdin(apr_file_t **thefile, 242 apr_int32_t flags, 243 apr_pool_t *pool) 244{ 245 apr_os_file_t fd = 0; 246 247 return apr_os_file_put(thefile, &fd, flags | APR_FOPEN_READ, pool); 248} 249 250 251APR_DECLARE(apr_status_t) apr_file_open_stderr(apr_file_t **thefile, apr_pool_t *pool) 252{ 253 return apr_file_open_flags_stderr(thefile, 0, pool); 254} 255 256 257APR_DECLARE(apr_status_t) apr_file_open_stdout(apr_file_t **thefile, apr_pool_t *pool) 258{ 259 return apr_file_open_flags_stdout(thefile, 0, pool); 260} 261 262 263APR_DECLARE(apr_status_t) apr_file_open_stdin(apr_file_t **thefile, apr_pool_t *pool) 264{ 265 return apr_file_open_flags_stdin(thefile, 0, pool); 266} 267 268APR_POOL_IMPLEMENT_ACCESSOR(file); 269 270 271 272APR_DECLARE(apr_status_t) apr_file_inherit_set(apr_file_t *thefile) 273{ 274 int rv; 275 ULONG state; 276 277 rv = DosQueryFHState(thefile->filedes, &state); 278 279 if (rv == 0 && (state & OPEN_FLAGS_NOINHERIT) != 0) { 280 rv = DosSetFHState(thefile->filedes, state & ~OPEN_FLAGS_NOINHERIT); 281 } 282 283 return APR_FROM_OS_ERROR(rv); 284} 285 286 287 288APR_DECLARE(apr_status_t) apr_file_inherit_unset(apr_file_t *thefile) 289{ 290 int rv; 291 ULONG state; 292 293 rv = DosQueryFHState(thefile->filedes, &state); 294 295 if (rv == 0 && (state & OPEN_FLAGS_NOINHERIT) == 0) { 296 rv = DosSetFHState(thefile->filedes, state | OPEN_FLAGS_NOINHERIT); 297 } 298 299 return APR_FROM_OS_ERROR(rv); 300} 301