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#define INCL_DOS 18#define INCL_DOSERRORS 19 20#include "apr_arch_file_io.h" 21#include "apr_file_io.h" 22#include "apr_lib.h" 23#include "apr_strings.h" 24 25#include <malloc.h> 26 27APR_DECLARE(apr_status_t) apr_file_read(apr_file_t *thefile, void *buf, apr_size_t *nbytes) 28{ 29 ULONG rc = 0; 30 ULONG bytesread; 31 32 if (!thefile->isopen) { 33 *nbytes = 0; 34 return APR_EBADF; 35 } 36 37 if (thefile->buffered) { 38 char *pos = (char *)buf; 39 ULONG blocksize; 40 ULONG size = *nbytes; 41 42 apr_thread_mutex_lock(thefile->mutex); 43 44 if (thefile->direction == 1) { 45 int rv = apr_file_flush(thefile); 46 47 if (rv != APR_SUCCESS) { 48 apr_thread_mutex_unlock(thefile->mutex); 49 return rv; 50 } 51 52 thefile->bufpos = 0; 53 thefile->direction = 0; 54 thefile->dataRead = 0; 55 } 56 57 while (rc == 0 && size > 0) { 58 if (thefile->bufpos >= thefile->dataRead) { 59 ULONG bytesread; 60 rc = DosRead(thefile->filedes, thefile->buffer, 61 thefile->bufsize, &bytesread); 62 63 if (bytesread == 0) { 64 if (rc == 0) 65 thefile->eof_hit = TRUE; 66 break; 67 } 68 69 thefile->dataRead = bytesread; 70 thefile->filePtr += thefile->dataRead; 71 thefile->bufpos = 0; 72 } 73 74 blocksize = size > thefile->dataRead - thefile->bufpos ? thefile->dataRead - thefile->bufpos : size; 75 memcpy(pos, thefile->buffer + thefile->bufpos, blocksize); 76 thefile->bufpos += blocksize; 77 pos += blocksize; 78 size -= blocksize; 79 } 80 81 *nbytes = rc == 0 ? pos - (char *)buf : 0; 82 apr_thread_mutex_unlock(thefile->mutex); 83 84 if (*nbytes == 0 && rc == 0 && thefile->eof_hit) { 85 return APR_EOF; 86 } 87 88 return APR_FROM_OS_ERROR(rc); 89 } else { 90 if (thefile->pipe) 91 DosResetEventSem(thefile->pipeSem, &rc); 92 93 rc = DosRead(thefile->filedes, buf, *nbytes, &bytesread); 94 95 if (rc == ERROR_NO_DATA && thefile->timeout != 0) { 96 int rcwait = DosWaitEventSem(thefile->pipeSem, thefile->timeout >= 0 ? thefile->timeout / 1000 : SEM_INDEFINITE_WAIT); 97 98 if (rcwait == 0) { 99 rc = DosRead(thefile->filedes, buf, *nbytes, &bytesread); 100 } 101 else if (rcwait == ERROR_TIMEOUT) { 102 *nbytes = 0; 103 return APR_TIMEUP; 104 } 105 } 106 107 if (rc) { 108 *nbytes = 0; 109 return APR_FROM_OS_ERROR(rc); 110 } 111 112 *nbytes = bytesread; 113 114 if (bytesread == 0) { 115 thefile->eof_hit = TRUE; 116 return APR_EOF; 117 } 118 119 return APR_SUCCESS; 120 } 121} 122 123 124 125APR_DECLARE(apr_status_t) apr_file_write(apr_file_t *thefile, const void *buf, apr_size_t *nbytes) 126{ 127 ULONG rc = 0; 128 ULONG byteswritten; 129 130 if (!thefile->isopen) { 131 *nbytes = 0; 132 return APR_EBADF; 133 } 134 135 if (thefile->buffered) { 136 char *pos = (char *)buf; 137 int blocksize; 138 int size = *nbytes; 139 140 apr_thread_mutex_lock(thefile->mutex); 141 142 if ( thefile->direction == 0 ) { 143 /* Position file pointer for writing at the offset we are logically reading from */ 144 ULONG offset = thefile->filePtr - thefile->dataRead + thefile->bufpos; 145 if (offset != thefile->filePtr) 146 DosSetFilePtr(thefile->filedes, offset, FILE_BEGIN, &thefile->filePtr ); 147 thefile->bufpos = thefile->dataRead = 0; 148 thefile->direction = 1; 149 } 150 151 while (rc == 0 && size > 0) { 152 if (thefile->bufpos == thefile->bufsize) /* write buffer is full */ 153 /* XXX bug; - rc is double-transformed os->apr below */ 154 rc = apr_file_flush(thefile); 155 156 blocksize = size > thefile->bufsize - thefile->bufpos ? thefile->bufsize - thefile->bufpos : size; 157 memcpy(thefile->buffer + thefile->bufpos, pos, blocksize); 158 thefile->bufpos += blocksize; 159 pos += blocksize; 160 size -= blocksize; 161 } 162 163 apr_thread_mutex_unlock(thefile->mutex); 164 return APR_FROM_OS_ERROR(rc); 165 } else { 166 if (thefile->flags & APR_FOPEN_APPEND) { 167 FILELOCK all = { 0, 0x7fffffff }; 168 ULONG newpos; 169 rc = DosSetFileLocks(thefile->filedes, NULL, &all, -1, 0); 170 171 if (rc == 0) { 172 rc = DosSetFilePtr(thefile->filedes, 0, FILE_END, &newpos); 173 174 if (rc == 0) { 175 rc = DosWrite(thefile->filedes, buf, *nbytes, &byteswritten); 176 } 177 178 DosSetFileLocks(thefile->filedes, &all, NULL, -1, 0); 179 } 180 } else { 181 rc = DosWrite(thefile->filedes, buf, *nbytes, &byteswritten); 182 } 183 184 if (rc) { 185 *nbytes = 0; 186 return APR_FROM_OS_ERROR(rc); 187 } 188 189 *nbytes = byteswritten; 190 return APR_SUCCESS; 191 } 192} 193 194 195 196#ifdef HAVE_WRITEV 197 198APR_DECLARE(apr_status_t) apr_file_writev(apr_file_t *thefile, const struct iovec *vec, apr_size_t nvec, apr_size_t *nbytes) 199{ 200 int bytes; 201 202 if (thefile->buffered) { 203 apr_status_t rv = apr_file_flush(thefile); 204 if (rv != APR_SUCCESS) { 205 return rv; 206 } 207 } 208 209 if ((bytes = writev(thefile->filedes, vec, nvec)) < 0) { 210 *nbytes = 0; 211 return errno; 212 } 213 else { 214 *nbytes = bytes; 215 return APR_SUCCESS; 216 } 217} 218#endif 219 220 221 222APR_DECLARE(apr_status_t) apr_file_putc(char ch, apr_file_t *thefile) 223{ 224 ULONG rc; 225 ULONG byteswritten; 226 227 if (!thefile->isopen) { 228 return APR_EBADF; 229 } 230 231 rc = DosWrite(thefile->filedes, &ch, 1, &byteswritten); 232 233 if (rc) { 234 return APR_FROM_OS_ERROR(rc); 235 } 236 237 return APR_SUCCESS; 238} 239 240 241 242APR_DECLARE(apr_status_t) apr_file_ungetc(char ch, apr_file_t *thefile) 243{ 244 apr_off_t offset = -1; 245 return apr_file_seek(thefile, APR_CUR, &offset); 246} 247 248 249APR_DECLARE(apr_status_t) apr_file_getc(char *ch, apr_file_t *thefile) 250{ 251 ULONG rc; 252 apr_size_t bytesread; 253 254 if (!thefile->isopen) { 255 return APR_EBADF; 256 } 257 258 bytesread = 1; 259 rc = apr_file_read(thefile, ch, &bytesread); 260 261 if (rc) { 262 return rc; 263 } 264 265 if (bytesread == 0) { 266 thefile->eof_hit = TRUE; 267 return APR_EOF; 268 } 269 270 return APR_SUCCESS; 271} 272 273 274 275APR_DECLARE(apr_status_t) apr_file_puts(const char *str, apr_file_t *thefile) 276{ 277 apr_size_t len; 278 279 len = strlen(str); 280 return apr_file_write(thefile, str, &len); 281} 282 283 284APR_DECLARE(apr_status_t) apr_file_flush(apr_file_t *thefile) 285{ 286 if (thefile->buffered) { 287 ULONG written = 0; 288 int rc = 0; 289 290 if (thefile->direction == 1 && thefile->bufpos) { 291 rc = DosWrite(thefile->filedes, thefile->buffer, thefile->bufpos, &written); 292 thefile->filePtr += written; 293 294 if (rc == 0) 295 thefile->bufpos = 0; 296 } 297 298 return APR_FROM_OS_ERROR(rc); 299 } else { 300 /* There isn't anything to do if we aren't buffering the output 301 * so just return success. 302 */ 303 return APR_SUCCESS; 304 } 305} 306 307APR_DECLARE(apr_status_t) apr_file_sync(apr_file_t *thefile) 308{ 309 return APR_ENOTIMPL; 310} 311 312APR_DECLARE(apr_status_t) apr_file_datasync(apr_file_t *thefile) 313{ 314 return APR_ENOTIMPL; 315} 316 317APR_DECLARE(apr_status_t) apr_file_gets(char *str, int len, apr_file_t *thefile) 318{ 319 apr_size_t readlen; 320 apr_status_t rv = APR_SUCCESS; 321 int i; 322 323 for (i = 0; i < len-1; i++) { 324 readlen = 1; 325 rv = apr_file_read(thefile, str+i, &readlen); 326 327 if (rv != APR_SUCCESS) { 328 break; 329 } 330 331 if (readlen != 1) { 332 rv = APR_EOF; 333 break; 334 } 335 336 if (str[i] == '\n') { 337 i++; 338 break; 339 } 340 } 341 str[i] = 0; 342 if (i > 0) { 343 /* we stored chars; don't report EOF or any other errors; 344 * the app will find out about that on the next call 345 */ 346 return APR_SUCCESS; 347 } 348 return rv; 349} 350 351 352 353APR_DECLARE_NONSTD(int) apr_file_printf(apr_file_t *fptr, 354 const char *format, ...) 355{ 356 int cc; 357 va_list ap; 358 char *buf; 359 int len; 360 361 buf = malloc(HUGE_STRING_LEN); 362 if (buf == NULL) { 363 return 0; 364 } 365 va_start(ap, format); 366 len = apr_vsnprintf(buf, HUGE_STRING_LEN, format, ap); 367 cc = apr_file_puts(buf, fptr); 368 va_end(ap); 369 free(buf); 370 return (cc == APR_SUCCESS) ? len : -1; 371} 372 373 374 375apr_status_t apr_file_check_read(apr_file_t *fd) 376{ 377 int rc; 378 379 if (!fd->pipe) 380 return APR_SUCCESS; /* Not a pipe, assume no waiting */ 381 382 rc = DosWaitEventSem(fd->pipeSem, SEM_IMMEDIATE_RETURN); 383 384 if (rc == ERROR_TIMEOUT) 385 return APR_TIMEUP; 386 387 return APR_FROM_OS_ERROR(rc); 388} 389