Lines 181-192
Link Here
|
181 |
apr_size_t blocksize; |
181 |
apr_size_t blocksize; |
182 |
apr_size_t size = *len; |
182 |
apr_size_t size = *len; |
183 |
|
183 |
|
184 |
apr_thread_mutex_lock(thefile->mutex); |
184 |
if (thefile->flags & APR_XTHREAD) |
|
|
185 |
apr_thread_mutex_lock(thefile->mutex); |
185 |
|
186 |
|
186 |
if (thefile->direction == 1) { |
187 |
if (thefile->direction == 1) { |
187 |
rv = apr_file_flush(thefile); |
188 |
rv = apr_file_flush(thefile); |
188 |
if (rv != APR_SUCCESS) { |
189 |
if (rv != APR_SUCCESS) { |
189 |
apr_thread_mutex_unlock(thefile->mutex); |
190 |
if (thefile->flags & APR_XTHREAD) |
|
|
191 |
apr_thread_mutex_unlock(thefile->mutex); |
190 |
return rv; |
192 |
return rv; |
191 |
} |
193 |
} |
192 |
thefile->bufpos = 0; |
194 |
thefile->bufpos = 0; |
Lines 195-229
Link Here
|
195 |
} |
197 |
} |
196 |
|
198 |
|
197 |
rv = 0; |
199 |
rv = 0; |
198 |
while (rv == 0 && size > 0) { |
200 |
if (size > thefile->bufsize) { |
199 |
if (thefile->bufpos >= thefile->dataRead) { |
201 |
apr_size_t read; |
200 |
apr_size_t read; |
202 |
|
201 |
rv = read_with_timeout(thefile, thefile->buffer, |
203 |
blocksize = thefile->dataRead - thefile->bufpos; |
202 |
thefile->bufsize, &read); |
204 |
if (blocksize > 0) { |
203 |
if (read == 0) { |
205 |
memcpy(pos, thefile->buffer + thefile->bufpos, blocksize); |
204 |
if (rv == APR_EOF) |
206 |
thefile->bufpos += blocksize; |
205 |
thefile->eof_hit = TRUE; |
207 |
pos += blocksize; |
206 |
break; |
208 |
size -= blocksize; |
207 |
} |
|
|
208 |
else { |
209 |
thefile->dataRead = read; |
210 |
thefile->filePtr += thefile->dataRead; |
211 |
thefile->bufpos = 0; |
212 |
} |
213 |
} |
209 |
} |
214 |
|
210 |
|
215 |
blocksize = size > thefile->dataRead - thefile->bufpos ? thefile->dataRead - thefile->bufpos : size; |
211 |
rv = read_with_timeout(thefile, pos, size, &read); |
216 |
memcpy(pos, thefile->buffer + thefile->bufpos, blocksize); |
212 |
if (read == 0 && rv == APR_EOF) |
217 |
thefile->bufpos += blocksize; |
213 |
thefile->eof_hit = TRUE; |
218 |
pos += blocksize; |
214 |
|
219 |
size -= blocksize; |
215 |
thefile->filePtr += read; |
|
|
216 |
pos += read; |
220 |
} |
217 |
} |
|
|
218 |
else { |
219 |
while (rv == 0 && size > 0) { |
220 |
if (thefile->bufpos >= thefile->dataRead) { |
221 |
apr_size_t read; |
222 |
rv = read_with_timeout(thefile, thefile->buffer, |
223 |
thefile->bufsize, &read); |
224 |
if (read == 0) { |
225 |
if (rv == APR_EOF) |
226 |
thefile->eof_hit = TRUE; |
227 |
break; |
228 |
} |
229 |
else { |
230 |
thefile->dataRead = read; |
231 |
thefile->filePtr += thefile->dataRead; |
232 |
thefile->bufpos = 0; |
233 |
} |
234 |
} |
221 |
|
235 |
|
|
|
236 |
blocksize = size > thefile->dataRead - thefile->bufpos |
237 |
? thefile->dataRead - thefile->bufpos |
238 |
: size; |
239 |
memcpy(pos, thefile->buffer + thefile->bufpos, blocksize); |
240 |
thefile->bufpos += blocksize; |
241 |
pos += blocksize; |
242 |
size -= blocksize; |
243 |
} |
244 |
} |
245 |
|
222 |
*len = pos - (char *)buf; |
246 |
*len = pos - (char *)buf; |
223 |
if (*len) { |
247 |
if (*len) { |
224 |
rv = APR_SUCCESS; |
248 |
rv = APR_SUCCESS; |
225 |
} |
249 |
} |
226 |
apr_thread_mutex_unlock(thefile->mutex); |
250 |
if (thefile->flags & APR_XTHREAD) |
|
|
251 |
apr_thread_mutex_unlock(thefile->mutex); |
227 |
} else { |
252 |
} else { |
228 |
/* Unbuffered i/o */ |
253 |
/* Unbuffered i/o */ |
229 |
apr_size_t nbytes; |
254 |
apr_size_t nbytes; |
Lines 236-267
Link Here
|
236 |
return rv; |
261 |
return rv; |
237 |
} |
262 |
} |
238 |
|
263 |
|
|
|
264 |
static apr_status_t apr_file_write_locked(apr_file_t *thefile, const void *buf, apr_size_t nbytes) |
265 |
{ |
266 |
DWORD numbytes, written = 0; |
267 |
apr_status_t rc = APR_SUCCESS; |
268 |
const char *buffer = buf; |
269 |
|
270 |
do { |
271 |
if (nbytes > APR_DWORD_MAX) { |
272 |
numbytes = APR_DWORD_MAX; |
273 |
} |
274 |
else { |
275 |
numbytes = (DWORD)nbytes; |
276 |
} |
277 |
|
278 |
if (!WriteFile(thefile->filehand, buffer, numbytes, &written, NULL)) { |
279 |
rc = apr_get_os_error(); |
280 |
thefile->filePtr += written; |
281 |
break; |
282 |
} |
283 |
|
284 |
thefile->filePtr += written; |
285 |
nbytes -= written; |
286 |
buffer += written; |
287 |
|
288 |
} while (nbytes > 0); |
289 |
|
290 |
return rc; |
291 |
} |
292 |
|
293 |
|
239 |
APR_DECLARE(apr_status_t) apr_file_write(apr_file_t *thefile, const void *buf, apr_size_t *nbytes) |
294 |
APR_DECLARE(apr_status_t) apr_file_write(apr_file_t *thefile, const void *buf, apr_size_t *nbytes) |
240 |
{ |
295 |
{ |
241 |
apr_status_t rv; |
296 |
apr_status_t rv; |
242 |
DWORD bwrote; |
297 |
DWORD bwrote; |
|
|
298 |
apr_size_t size = *nbytes; |
243 |
|
299 |
|
244 |
/* If the file is open for xthread support, allocate and |
300 |
/* Our buffered I/O implementation does not use overlapped I/O. |
245 |
* initialize the overlapped and io completion event (hEvent). |
|
|
246 |
* Threads should NOT share an apr_file_t or its hEvent. |
247 |
*/ |
301 |
*/ |
248 |
if ((thefile->flags & APR_XTHREAD) && !thefile->pOverlapped ) { |
|
|
249 |
thefile->pOverlapped = (OVERLAPPED*) apr_pcalloc(thefile->pool, |
250 |
sizeof(OVERLAPPED)); |
251 |
thefile->pOverlapped->hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); |
252 |
if (!thefile->pOverlapped->hEvent) { |
253 |
rv = apr_get_os_error(); |
254 |
return rv; |
255 |
} |
256 |
} |
257 |
|
258 |
if (thefile->buffered) { |
302 |
if (thefile->buffered) { |
259 |
char *pos = (char *)buf; |
303 |
char *pos = (char *)buf; |
260 |
apr_size_t blocksize; |
304 |
apr_size_t blocksize; |
261 |
apr_size_t size = *nbytes; |
|
|
262 |
|
305 |
|
263 |
apr_thread_mutex_lock(thefile->mutex); |
306 |
if (size < 16 && |
|
|
307 |
!(thefile->flags & APR_XTHREAD) && |
308 |
thefile->direction == 1 && |
309 |
thefile->bufpos + size <= thefile->bufsize) { |
264 |
|
310 |
|
|
|
311 |
char *dest = thefile->buffer + thefile->bufpos; |
312 |
const char *end = pos + size; |
313 |
|
314 |
thefile->bufpos += size; |
315 |
for (; pos != end; ++pos, ++dest) |
316 |
*dest = *pos; |
317 |
|
318 |
return APR_SUCCESS; |
319 |
} |
320 |
|
321 |
if (thefile->flags & APR_XTHREAD) |
322 |
apr_thread_mutex_lock(thefile->mutex); |
323 |
|
265 |
if (thefile->direction == 0) { |
324 |
if (thefile->direction == 0) { |
266 |
// Position file pointer for writing at the offset we are logically reading from |
325 |
// Position file pointer for writing at the offset we are logically reading from |
267 |
apr_off_t offset = thefile->filePtr - thefile->dataRead + thefile->bufpos; |
326 |
apr_off_t offset = thefile->filePtr - thefile->dataRead + thefile->bufpos; |
Lines 274-380
Link Here
|
274 |
} |
333 |
} |
275 |
|
334 |
|
276 |
rv = 0; |
335 |
rv = 0; |
277 |
while (rv == 0 && size > 0) { |
|
|
278 |
if (thefile->bufpos == thefile->bufsize) // write buffer is full |
279 |
rv = apr_file_flush(thefile); |
280 |
|
336 |
|
281 |
blocksize = size > thefile->bufsize - thefile->bufpos ? |
337 |
/* Large chunks shall not be buffered. They would cause at least one |
282 |
thefile->bufsize - thefile->bufpos : size; |
338 |
* cache flush just "for themselves". So, we can pass them directly |
283 |
memcpy(thefile->buffer + thefile->bufpos, pos, blocksize); |
339 |
* to the OS instead of copying them around and poking the OS for |
284 |
thefile->bufpos += blocksize; |
340 |
* every 4k of data in the buffer. */ |
285 |
pos += blocksize; |
341 |
if (size > thefile->bufsize) { |
286 |
size -= blocksize; |
342 |
rv = apr_file_flush(thefile); |
|
|
343 |
if (rv == APR_SUCCESS) |
344 |
apr_file_write_locked(thefile, buf, size); |
287 |
} |
345 |
} |
|
|
346 |
else { |
347 |
while (rv == 0 && size > 0) { |
348 |
if (thefile->bufpos == thefile->bufsize) // write buffer is full |
349 |
rv = apr_file_flush(thefile); |
288 |
|
350 |
|
289 |
apr_thread_mutex_unlock(thefile->mutex); |
351 |
blocksize = size > thefile->bufsize - thefile->bufpos ? |
|
|
352 |
thefile->bufsize - thefile->bufpos : size; |
353 |
memcpy(thefile->buffer + thefile->bufpos, pos, blocksize); |
354 |
thefile->bufpos += blocksize; |
355 |
pos += blocksize; |
356 |
size -= blocksize; |
357 |
} |
358 |
} |
359 |
|
360 |
if (thefile->flags & APR_XTHREAD) |
361 |
apr_thread_mutex_unlock(thefile->mutex); |
362 |
|
290 |
return rv; |
363 |
return rv; |
291 |
} else { |
364 |
} |
292 |
if (!thefile->pipe) { |
365 |
|
293 |
apr_off_t offset = 0; |
366 |
/* If the file is open for xthread support, allocate and |
294 |
apr_status_t rc; |
367 |
* initialize the overlapped and io completion event (hEvent). |
295 |
if (thefile->append) { |
368 |
* Threads should NOT share an apr_file_t or its hEvent. |
296 |
/* apr_file_lock will mutex the file across processes. |
369 |
*/ |
297 |
* The call to apr_thread_mutex_lock is added to avoid |
370 |
if ((thefile->flags & APR_XTHREAD) && !thefile->pOverlapped ) { |
298 |
* a race condition between LockFile and WriteFile |
371 |
thefile->pOverlapped = (OVERLAPPED*) apr_pcalloc(thefile->pool, |
299 |
* that occasionally leads to deadlocked threads. |
372 |
sizeof(OVERLAPPED)); |
300 |
*/ |
373 |
thefile->pOverlapped->hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); |
|
|
374 |
if (!thefile->pOverlapped->hEvent) { |
375 |
rv = apr_get_os_error(); |
376 |
return rv; |
377 |
} |
378 |
} |
379 |
|
380 |
if (!thefile->pipe) { |
381 |
apr_off_t offset = 0; |
382 |
apr_status_t rc; |
383 |
if (thefile->append) { |
384 |
/* apr_file_lock will mutex the file across processes. |
385 |
* The call to apr_thread_mutex_lock is added to avoid |
386 |
* a race condition between LockFile and WriteFile |
387 |
* that occasionally leads to deadlocked threads. |
388 |
*/ |
389 |
if (thefile->flags & APR_XTHREAD) |
301 |
apr_thread_mutex_lock(thefile->mutex); |
390 |
apr_thread_mutex_lock(thefile->mutex); |
302 |
rc = apr_file_lock(thefile, APR_FLOCK_EXCLUSIVE); |
391 |
|
303 |
if (rc != APR_SUCCESS) { |
392 |
rc = apr_file_lock(thefile, APR_FLOCK_EXCLUSIVE); |
|
|
393 |
if (rc != APR_SUCCESS) { |
394 |
if (thefile->flags & APR_XTHREAD) |
304 |
apr_thread_mutex_unlock(thefile->mutex); |
395 |
apr_thread_mutex_unlock(thefile->mutex); |
305 |
return rc; |
396 |
return rc; |
306 |
} |
397 |
} |
307 |
rc = apr_file_seek(thefile, APR_END, &offset); |
398 |
rc = apr_file_seek(thefile, APR_END, &offset); |
308 |
if (rc != APR_SUCCESS) { |
399 |
if (rc != APR_SUCCESS) { |
|
|
400 |
if (thefile->flags & APR_XTHREAD) |
309 |
apr_thread_mutex_unlock(thefile->mutex); |
401 |
apr_thread_mutex_unlock(thefile->mutex); |
310 |
return rc; |
402 |
return rc; |
311 |
} |
|
|
312 |
} |
403 |
} |
313 |
if (thefile->pOverlapped) { |
|
|
314 |
thefile->pOverlapped->Offset = (DWORD)thefile->filePtr; |
315 |
thefile->pOverlapped->OffsetHigh = (DWORD)(thefile->filePtr >> 32); |
316 |
} |
317 |
rv = WriteFile(thefile->filehand, buf, (DWORD)*nbytes, &bwrote, |
318 |
thefile->pOverlapped); |
319 |
if (thefile->append) { |
320 |
apr_file_unlock(thefile); |
321 |
apr_thread_mutex_unlock(thefile->mutex); |
322 |
} |
323 |
} |
404 |
} |
324 |
else { |
405 |
if (thefile->pOverlapped) { |
325 |
rv = WriteFile(thefile->filehand, buf, (DWORD)*nbytes, &bwrote, |
406 |
thefile->pOverlapped->Offset = (DWORD)thefile->filePtr; |
326 |
thefile->pOverlapped); |
407 |
thefile->pOverlapped->OffsetHigh = (DWORD)(thefile->filePtr >> 32); |
327 |
} |
408 |
} |
328 |
if (rv) { |
409 |
rv = WriteFile(thefile->filehand, buf, (DWORD)*nbytes, &bwrote, |
329 |
*nbytes = bwrote; |
410 |
thefile->pOverlapped); |
330 |
rv = APR_SUCCESS; |
411 |
if (thefile->append) { |
|
|
412 |
apr_file_unlock(thefile); |
413 |
if (thefile->flags & APR_XTHREAD) |
414 |
apr_thread_mutex_unlock(thefile->mutex); |
331 |
} |
415 |
} |
332 |
else { |
416 |
} |
333 |
(*nbytes) = 0; |
417 |
else { |
334 |
rv = apr_get_os_error(); |
418 |
rv = WriteFile(thefile->filehand, buf, (DWORD)*nbytes, &bwrote, |
|
|
419 |
thefile->pOverlapped); |
420 |
} |
421 |
if (rv) { |
422 |
*nbytes = bwrote; |
423 |
rv = APR_SUCCESS; |
424 |
} |
425 |
else { |
426 |
(*nbytes) = 0; |
427 |
rv = apr_get_os_error(); |
335 |
|
428 |
|
336 |
/* XXX: This must be corrected, per the apr_file_read logic!!! */ |
429 |
/* XXX: This must be corrected, per the apr_file_read logic!!! */ |
337 |
if (rv == APR_FROM_OS_ERROR(ERROR_IO_PENDING)) { |
430 |
if (rv == APR_FROM_OS_ERROR(ERROR_IO_PENDING)) { |
338 |
|
|
|
339 |
DWORD timeout_ms; |
340 |
|
431 |
|
341 |
if (thefile->timeout == 0) { |
432 |
DWORD timeout_ms; |
342 |
timeout_ms = 0; |
433 |
|
343 |
} |
434 |
if (thefile->timeout == 0) { |
344 |
else if (thefile->timeout < 0) { |
435 |
timeout_ms = 0; |
345 |
timeout_ms = INFINITE; |
|
|
346 |
} |
347 |
else { |
348 |
timeout_ms = (DWORD)(thefile->timeout / 1000); |
349 |
} |
350 |
|
351 |
rv = WaitForSingleObject(thefile->pOverlapped->hEvent, timeout_ms); |
352 |
switch (rv) { |
353 |
case WAIT_OBJECT_0: |
354 |
GetOverlappedResult(thefile->filehand, thefile->pOverlapped, |
355 |
&bwrote, TRUE); |
356 |
*nbytes = bwrote; |
357 |
rv = APR_SUCCESS; |
358 |
break; |
359 |
case WAIT_TIMEOUT: |
360 |
rv = (timeout_ms == 0) ? APR_EAGAIN : APR_TIMEUP; |
361 |
break; |
362 |
case WAIT_FAILED: |
363 |
rv = apr_get_os_error(); |
364 |
break; |
365 |
default: |
366 |
break; |
367 |
} |
368 |
if (rv != APR_SUCCESS) { |
369 |
if (apr_os_level >= APR_WIN_98) |
370 |
CancelIo(thefile->filehand); |
371 |
} |
372 |
} |
436 |
} |
|
|
437 |
else if (thefile->timeout < 0) { |
438 |
timeout_ms = INFINITE; |
439 |
} |
440 |
else { |
441 |
timeout_ms = (DWORD)(thefile->timeout / 1000); |
442 |
} |
443 |
|
444 |
rv = WaitForSingleObject(thefile->pOverlapped->hEvent, timeout_ms); |
445 |
switch (rv) { |
446 |
case WAIT_OBJECT_0: |
447 |
GetOverlappedResult(thefile->filehand, thefile->pOverlapped, |
448 |
&bwrote, TRUE); |
449 |
*nbytes = bwrote; |
450 |
rv = APR_SUCCESS; |
451 |
break; |
452 |
case WAIT_TIMEOUT: |
453 |
rv = (timeout_ms == 0) ? APR_EAGAIN : APR_TIMEUP; |
454 |
break; |
455 |
case WAIT_FAILED: |
456 |
rv = apr_get_os_error(); |
457 |
break; |
458 |
default: |
459 |
break; |
460 |
} |
461 |
if (rv != APR_SUCCESS) { |
462 |
if (apr_os_level >= APR_WIN_98) |
463 |
CancelIo(thefile->filehand); |
464 |
} |
373 |
} |
465 |
} |
374 |
if (rv == APR_SUCCESS && thefile->pOverlapped && !thefile->pipe) { |
|
|
375 |
thefile->filePtr += *nbytes; |
376 |
} |
377 |
} |
466 |
} |
|
|
467 |
if (rv == APR_SUCCESS && thefile->pOverlapped && !thefile->pipe) { |
468 |
thefile->filePtr += *nbytes; |
469 |
} |
470 |
|
378 |
return rv; |
471 |
return rv; |
379 |
} |
472 |
} |
380 |
/* ToDo: Write for it anyway and test the oslevel! |
473 |
/* ToDo: Write for it anyway and test the oslevel! |
Lines 405-413
Link Here
|
405 |
|
498 |
|
406 |
APR_DECLARE(apr_status_t) apr_file_putc(char ch, apr_file_t *thefile) |
499 |
APR_DECLARE(apr_status_t) apr_file_putc(char ch, apr_file_t *thefile) |
407 |
{ |
500 |
{ |
408 |
apr_size_t len = 1; |
501 |
if (!(thefile->flags & APR_XTHREAD) && |
|
|
502 |
thefile->buffered && |
503 |
thefile->direction == 1 && |
504 |
thefile->bufpos < thefile->bufsize) { |
409 |
|
505 |
|
410 |
return apr_file_write(thefile, &ch, &len); |
506 |
thefile->buffer [thefile->bufpos++] = ch; |
|
|
507 |
|
508 |
return APR_SUCCESS; |
509 |
} |
510 |
else { |
511 |
apr_size_t len = 1; |
512 |
return apr_file_write(thefile, &ch, &len); |
513 |
} |
411 |
} |
514 |
} |
412 |
|
515 |
|
413 |
APR_DECLARE(apr_status_t) apr_file_ungetc(char ch, apr_file_t *thefile) |
516 |
APR_DECLARE(apr_status_t) apr_file_ungetc(char ch, apr_file_t *thefile) |
Lines 421-426
Link Here
|
421 |
apr_status_t rc; |
524 |
apr_status_t rc; |
422 |
apr_size_t bread; |
525 |
apr_size_t bread; |
423 |
|
526 |
|
|
|
527 |
if (thefile->ungetchar != -1) { |
528 |
*ch = (char)thefile->ungetchar; |
529 |
thefile->ungetchar = -1; |
530 |
return APR_SUCCESS; |
531 |
} |
532 |
|
533 |
if (!(thefile->flags & APR_XTHREAD) && |
534 |
thefile->buffered && |
535 |
thefile->direction == 0 && |
536 |
thefile->bufpos < thefile->dataRead) { |
537 |
*ch = thefile->buffer[thefile->bufpos++]; |
538 |
return APR_SUCCESS; |
539 |
} |
540 |
|
424 |
bread = 1; |
541 |
bread = 1; |
425 |
rc = apr_file_read(thefile, ch, &bread); |
542 |
rc = apr_file_read(thefile, ch, &bread); |
426 |
|
543 |
|
Lines 473-519
Link Here
|
473 |
|
590 |
|
474 |
APR_DECLARE(apr_status_t) apr_file_flush(apr_file_t *thefile) |
591 |
APR_DECLARE(apr_status_t) apr_file_flush(apr_file_t *thefile) |
475 |
{ |
592 |
{ |
476 |
if (thefile->buffered) { |
593 |
apr_status_t rc = 0; |
477 |
DWORD numbytes, written = 0; |
|
|
478 |
apr_status_t rc = 0; |
479 |
char *buffer; |
480 |
apr_size_t bytesleft; |
481 |
|
594 |
|
482 |
if (thefile->direction == 1 && thefile->bufpos) { |
595 |
if (thefile->buffered && thefile->direction == 1 && thefile->bufpos) { |
483 |
buffer = thefile->buffer; |
596 |
rc = apr_file_write_locked(thefile, thefile->buffer, thefile->bufpos); |
484 |
bytesleft = thefile->bufpos; |
597 |
if (rc == 0) |
485 |
|
598 |
thefile->bufpos = 0; |
486 |
do { |
|
|
487 |
if (bytesleft > APR_DWORD_MAX) { |
488 |
numbytes = APR_DWORD_MAX; |
489 |
} |
490 |
else { |
491 |
numbytes = (DWORD)bytesleft; |
492 |
} |
493 |
|
494 |
if (!WriteFile(thefile->filehand, buffer, numbytes, &written, NULL)) { |
495 |
rc = apr_get_os_error(); |
496 |
thefile->filePtr += written; |
497 |
break; |
498 |
} |
499 |
|
500 |
thefile->filePtr += written; |
501 |
bytesleft -= written; |
502 |
buffer += written; |
503 |
|
504 |
} while (bytesleft > 0); |
505 |
|
506 |
if (rc == 0) |
507 |
thefile->bufpos = 0; |
508 |
} |
509 |
|
510 |
return rc; |
511 |
} |
599 |
} |
512 |
|
600 |
|
513 |
/* There isn't anything to do if we aren't buffering the output |
601 |
return rc; |
514 |
* so just return success. |
|
|
515 |
*/ |
516 |
return APR_SUCCESS; |
517 |
} |
602 |
} |
518 |
|
603 |
|
519 |
struct apr_file_printf_data { |
604 |
struct apr_file_printf_data { |