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 223-229
Link Here
|
223 |
if (*len) { |
225 |
if (*len) { |
224 |
rv = APR_SUCCESS; |
226 |
rv = APR_SUCCESS; |
225 |
} |
227 |
} |
226 |
apr_thread_mutex_unlock(thefile->mutex); |
228 |
if (thefile->flags & APR_XTHREAD) |
|
|
229 |
apr_thread_mutex_unlock(thefile->mutex); |
227 |
} else { |
230 |
} else { |
228 |
/* Unbuffered i/o */ |
231 |
/* Unbuffered i/o */ |
229 |
apr_size_t nbytes; |
232 |
apr_size_t nbytes; |
Lines 236-267
Link Here
|
236 |
return rv; |
239 |
return rv; |
237 |
} |
240 |
} |
238 |
|
241 |
|
|
|
242 |
static apr_status_t apr_file_write_locked(apr_file_t *thefile, const void *buf, apr_size_t nbytes) |
243 |
{ |
244 |
DWORD numbytes, written = 0; |
245 |
apr_status_t rc = APR_SUCCESS; |
246 |
char *buffer = buf; |
247 |
|
248 |
do { |
249 |
if (nbytes > APR_DWORD_MAX) { |
250 |
numbytes = APR_DWORD_MAX; |
251 |
} |
252 |
else { |
253 |
numbytes = (DWORD)nbytes; |
254 |
} |
255 |
|
256 |
if (!WriteFile(thefile->filehand, buffer, numbytes, &written, NULL)) { |
257 |
rc = apr_get_os_error(); |
258 |
thefile->filePtr += written; |
259 |
break; |
260 |
} |
261 |
|
262 |
thefile->filePtr += written; |
263 |
nbytes -= written; |
264 |
buffer += written; |
265 |
|
266 |
} while (nbytes > 0); |
267 |
|
268 |
return rc; |
269 |
} |
270 |
|
271 |
|
239 |
APR_DECLARE(apr_status_t) apr_file_write(apr_file_t *thefile, const void *buf, apr_size_t *nbytes) |
272 |
APR_DECLARE(apr_status_t) apr_file_write(apr_file_t *thefile, const void *buf, apr_size_t *nbytes) |
240 |
{ |
273 |
{ |
241 |
apr_status_t rv; |
274 |
apr_status_t rv; |
242 |
DWORD bwrote; |
275 |
DWORD bwrote; |
|
|
276 |
apr_size_t size = *nbytes; |
243 |
|
277 |
|
244 |
/* If the file is open for xthread support, allocate and |
278 |
/* 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 |
*/ |
279 |
*/ |
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) { |
280 |
if (thefile->buffered) { |
259 |
char *pos = (char *)buf; |
281 |
char *pos = (char *)buf; |
260 |
apr_size_t blocksize; |
282 |
apr_size_t blocksize; |
261 |
apr_size_t size = *nbytes; |
|
|
262 |
|
283 |
|
263 |
apr_thread_mutex_lock(thefile->mutex); |
284 |
if (size < 16 && |
|
|
285 |
!(thefile->flags & APR_XTHREAD) && |
286 |
thefile->direction == 1 && |
287 |
thefile->bufpos + size <= thefile->bufsize) { |
264 |
|
288 |
|
|
|
289 |
char *dest = thefile->buffer + thefile->bufpos; |
290 |
thefile->bufpos += size; |
291 |
|
292 |
const char *end = pos + size; |
293 |
for (; pos != end; ++pos, ++dest) |
294 |
*dest = *pos; |
295 |
|
296 |
return APR_SUCCESS; |
297 |
} |
298 |
|
299 |
if (thefile->flags & APR_XTHREAD) |
300 |
apr_thread_mutex_lock(thefile->mutex); |
301 |
|
265 |
if (thefile->direction == 0) { |
302 |
if (thefile->direction == 0) { |
266 |
// Position file pointer for writing at the offset we are logically reading from |
303 |
// Position file pointer for writing at the offset we are logically reading from |
267 |
apr_off_t offset = thefile->filePtr - thefile->dataRead + thefile->bufpos; |
304 |
apr_off_t offset = thefile->filePtr - thefile->dataRead + thefile->bufpos; |
Lines 274-380
Link Here
|
274 |
} |
311 |
} |
275 |
|
312 |
|
276 |
rv = 0; |
313 |
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 |
|
314 |
|
281 |
blocksize = size > thefile->bufsize - thefile->bufpos ? |
315 |
/* Large chunks shall not be buffered. They would cause at least one |
282 |
thefile->bufsize - thefile->bufpos : size; |
316 |
* cache flush just "for themselves". So, we can pass them directly |
283 |
memcpy(thefile->buffer + thefile->bufpos, pos, blocksize); |
317 |
* to the OS instead of copying them around and poking the OS for |
284 |
thefile->bufpos += blocksize; |
318 |
* every 4k of data in the buffer. */ |
285 |
pos += blocksize; |
319 |
if (size > thefile->bufsize) { |
286 |
size -= blocksize; |
320 |
rv = apr_file_flush(thefile); |
|
|
321 |
if (rv == APR_SUCCESS) |
322 |
apr_file_write_locked(thefile, buf, size); |
287 |
} |
323 |
} |
|
|
324 |
else { |
325 |
while (rv == 0 && size > 0) { |
326 |
if (thefile->bufpos == thefile->bufsize) // write buffer is full |
327 |
rv = apr_file_flush(thefile); |
288 |
|
328 |
|
289 |
apr_thread_mutex_unlock(thefile->mutex); |
329 |
blocksize = size > thefile->bufsize - thefile->bufpos ? |
|
|
330 |
thefile->bufsize - thefile->bufpos : size; |
331 |
memcpy(thefile->buffer + thefile->bufpos, pos, blocksize); |
332 |
thefile->bufpos += blocksize; |
333 |
pos += blocksize; |
334 |
size -= blocksize; |
335 |
} |
336 |
} |
337 |
|
338 |
if (thefile->flags & APR_XTHREAD) |
339 |
apr_thread_mutex_unlock(thefile->mutex); |
340 |
|
290 |
return rv; |
341 |
return rv; |
291 |
} else { |
342 |
} |
292 |
if (!thefile->pipe) { |
343 |
|
293 |
apr_off_t offset = 0; |
344 |
/* If the file is open for xthread support, allocate and |
294 |
apr_status_t rc; |
345 |
* initialize the overlapped and io completion event (hEvent). |
295 |
if (thefile->append) { |
346 |
* Threads should NOT share an apr_file_t or its hEvent. |
296 |
/* apr_file_lock will mutex the file across processes. |
347 |
*/ |
297 |
* The call to apr_thread_mutex_lock is added to avoid |
348 |
if ((thefile->flags & APR_XTHREAD) && !thefile->pOverlapped ) { |
298 |
* a race condition between LockFile and WriteFile |
349 |
thefile->pOverlapped = (OVERLAPPED*) apr_pcalloc(thefile->pool, |
299 |
* that occasionally leads to deadlocked threads. |
350 |
sizeof(OVERLAPPED)); |
300 |
*/ |
351 |
thefile->pOverlapped->hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); |
|
|
352 |
if (!thefile->pOverlapped->hEvent) { |
353 |
rv = apr_get_os_error(); |
354 |
return rv; |
355 |
} |
356 |
} |
357 |
|
358 |
if (!thefile->pipe) { |
359 |
apr_off_t offset = 0; |
360 |
apr_status_t rc; |
361 |
if (thefile->append) { |
362 |
/* apr_file_lock will mutex the file across processes. |
363 |
* The call to apr_thread_mutex_lock is added to avoid |
364 |
* a race condition between LockFile and WriteFile |
365 |
* that occasionally leads to deadlocked threads. |
366 |
*/ |
367 |
if (thefile->flags & APR_XTHREAD) |
301 |
apr_thread_mutex_lock(thefile->mutex); |
368 |
apr_thread_mutex_lock(thefile->mutex); |
302 |
rc = apr_file_lock(thefile, APR_FLOCK_EXCLUSIVE); |
369 |
|
303 |
if (rc != APR_SUCCESS) { |
370 |
rc = apr_file_lock(thefile, APR_FLOCK_EXCLUSIVE); |
|
|
371 |
if (rc != APR_SUCCESS) { |
372 |
if (thefile->flags & APR_XTHREAD) |
304 |
apr_thread_mutex_unlock(thefile->mutex); |
373 |
apr_thread_mutex_unlock(thefile->mutex); |
305 |
return rc; |
374 |
return rc; |
306 |
} |
375 |
} |
307 |
rc = apr_file_seek(thefile, APR_END, &offset); |
376 |
rc = apr_file_seek(thefile, APR_END, &offset); |
308 |
if (rc != APR_SUCCESS) { |
377 |
if (rc != APR_SUCCESS) { |
|
|
378 |
if (thefile->flags & APR_XTHREAD) |
309 |
apr_thread_mutex_unlock(thefile->mutex); |
379 |
apr_thread_mutex_unlock(thefile->mutex); |
310 |
return rc; |
380 |
return rc; |
311 |
} |
|
|
312 |
} |
381 |
} |
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 |
} |
382 |
} |
324 |
else { |
383 |
if (thefile->pOverlapped) { |
325 |
rv = WriteFile(thefile->filehand, buf, (DWORD)*nbytes, &bwrote, |
384 |
thefile->pOverlapped->Offset = (DWORD)thefile->filePtr; |
326 |
thefile->pOverlapped); |
385 |
thefile->pOverlapped->OffsetHigh = (DWORD)(thefile->filePtr >> 32); |
327 |
} |
386 |
} |
328 |
if (rv) { |
387 |
rv = WriteFile(thefile->filehand, buf, (DWORD)*nbytes, &bwrote, |
329 |
*nbytes = bwrote; |
388 |
thefile->pOverlapped); |
330 |
rv = APR_SUCCESS; |
389 |
if (thefile->append) { |
|
|
390 |
apr_file_unlock(thefile); |
391 |
if (thefile->flags & APR_XTHREAD) |
392 |
apr_thread_mutex_unlock(thefile->mutex); |
331 |
} |
393 |
} |
332 |
else { |
394 |
} |
333 |
(*nbytes) = 0; |
395 |
else { |
334 |
rv = apr_get_os_error(); |
396 |
rv = WriteFile(thefile->filehand, buf, (DWORD)*nbytes, &bwrote, |
|
|
397 |
thefile->pOverlapped); |
398 |
} |
399 |
if (rv) { |
400 |
*nbytes = bwrote; |
401 |
rv = APR_SUCCESS; |
402 |
} |
403 |
else { |
404 |
(*nbytes) = 0; |
405 |
rv = apr_get_os_error(); |
335 |
|
406 |
|
336 |
/* XXX: This must be corrected, per the apr_file_read logic!!! */ |
407 |
/* XXX: This must be corrected, per the apr_file_read logic!!! */ |
337 |
if (rv == APR_FROM_OS_ERROR(ERROR_IO_PENDING)) { |
408 |
if (rv == APR_FROM_OS_ERROR(ERROR_IO_PENDING)) { |
338 |
|
|
|
339 |
DWORD timeout_ms; |
340 |
|
409 |
|
341 |
if (thefile->timeout == 0) { |
410 |
DWORD timeout_ms; |
342 |
timeout_ms = 0; |
411 |
|
343 |
} |
412 |
if (thefile->timeout == 0) { |
344 |
else if (thefile->timeout < 0) { |
413 |
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 |
} |
414 |
} |
|
|
415 |
else if (thefile->timeout < 0) { |
416 |
timeout_ms = INFINITE; |
417 |
} |
418 |
else { |
419 |
timeout_ms = (DWORD)(thefile->timeout / 1000); |
420 |
} |
421 |
|
422 |
rv = WaitForSingleObject(thefile->pOverlapped->hEvent, timeout_ms); |
423 |
switch (rv) { |
424 |
case WAIT_OBJECT_0: |
425 |
GetOverlappedResult(thefile->filehand, thefile->pOverlapped, |
426 |
&bwrote, TRUE); |
427 |
*nbytes = bwrote; |
428 |
rv = APR_SUCCESS; |
429 |
break; |
430 |
case WAIT_TIMEOUT: |
431 |
rv = (timeout_ms == 0) ? APR_EAGAIN : APR_TIMEUP; |
432 |
break; |
433 |
case WAIT_FAILED: |
434 |
rv = apr_get_os_error(); |
435 |
break; |
436 |
default: |
437 |
break; |
438 |
} |
439 |
if (rv != APR_SUCCESS) { |
440 |
if (apr_os_level >= APR_WIN_98) |
441 |
CancelIo(thefile->filehand); |
442 |
} |
373 |
} |
443 |
} |
374 |
if (rv == APR_SUCCESS && thefile->pOverlapped && !thefile->pipe) { |
|
|
375 |
thefile->filePtr += *nbytes; |
376 |
} |
377 |
} |
444 |
} |
|
|
445 |
if (rv == APR_SUCCESS && thefile->pOverlapped && !thefile->pipe) { |
446 |
thefile->filePtr += *nbytes; |
447 |
} |
448 |
|
378 |
return rv; |
449 |
return rv; |
379 |
} |
450 |
} |
380 |
/* ToDo: Write for it anyway and test the oslevel! |
451 |
/* ToDo: Write for it anyway and test the oslevel! |
Lines 405-413
Link Here
|
405 |
|
476 |
|
406 |
APR_DECLARE(apr_status_t) apr_file_putc(char ch, apr_file_t *thefile) |
477 |
APR_DECLARE(apr_status_t) apr_file_putc(char ch, apr_file_t *thefile) |
407 |
{ |
478 |
{ |
408 |
apr_size_t len = 1; |
479 |
if (!(thefile->flags & APR_XTHREAD) && |
|
|
480 |
thefile->buffered && |
481 |
thefile->direction == 1 && |
482 |
thefile->bufpos < thefile->bufsize) { |
409 |
|
483 |
|
410 |
return apr_file_write(thefile, &ch, &len); |
484 |
thefile->buffer [thefile->bufpos++] = ch; |
|
|
485 |
|
486 |
return APR_SUCCESS; |
487 |
} |
488 |
else { |
489 |
apr_size_t len = 1; |
490 |
return apr_file_write(thefile, &ch, &len); |
491 |
} |
411 |
} |
492 |
} |
412 |
|
493 |
|
413 |
APR_DECLARE(apr_status_t) apr_file_ungetc(char ch, apr_file_t *thefile) |
494 |
APR_DECLARE(apr_status_t) apr_file_ungetc(char ch, apr_file_t *thefile) |
Lines 421-426
Link Here
|
421 |
apr_status_t rc; |
502 |
apr_status_t rc; |
422 |
apr_size_t bread; |
503 |
apr_size_t bread; |
423 |
|
504 |
|
|
|
505 |
if (thefile->ungetchar != -1) { |
506 |
ch = (char)thefile->ungetchar; |
507 |
thefile->ungetchar = -1; |
508 |
return APR_SUCCESS; |
509 |
} |
510 |
|
511 |
if (!(thefile->flags & APR_XTHREAD) && |
512 |
thefile->buffered && |
513 |
thefile->direction == 0 && |
514 |
thefile->bufpos < thefile->dataRead) { |
515 |
*ch = thefile->buffer[thefile->bufpos++]; |
516 |
return APR_SUCCESS; |
517 |
} |
518 |
|
424 |
bread = 1; |
519 |
bread = 1; |
425 |
rc = apr_file_read(thefile, ch, &bread); |
520 |
rc = apr_file_read(thefile, ch, &bread); |
426 |
|
521 |
|
Lines 473-519
Link Here
|
473 |
|
568 |
|
474 |
APR_DECLARE(apr_status_t) apr_file_flush(apr_file_t *thefile) |
569 |
APR_DECLARE(apr_status_t) apr_file_flush(apr_file_t *thefile) |
475 |
{ |
570 |
{ |
476 |
if (thefile->buffered) { |
571 |
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 |
|
572 |
|
482 |
if (thefile->direction == 1 && thefile->bufpos) { |
573 |
if (thefile->buffered && thefile->direction == 1 && thefile->bufpos) { |
483 |
buffer = thefile->buffer; |
574 |
rc = apr_file_write_locked(thefile, thefile->buffer, thefile->bufpos); |
484 |
bytesleft = thefile->bufpos; |
575 |
if (rc == 0) |
485 |
|
576 |
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 |
} |
577 |
} |
512 |
|
578 |
|
513 |
/* There isn't anything to do if we aren't buffering the output |
579 |
return rc; |
514 |
* so just return success. |
|
|
515 |
*/ |
516 |
return APR_SUCCESS; |
517 |
} |
580 |
} |
518 |
|
581 |
|
519 |
struct apr_file_printf_data { |
582 |
struct apr_file_printf_data { |