View | Details | Raw Unified | Return to bug 49085
Collapse All | Expand All

(-)file_io/unix/readwrite.c (-13 / +85 lines)
Lines 153-158 Link Here
153
        int blocksize;
153
        int blocksize;
154
        int size = *nbytes;
154
        int size = *nbytes;
155
155
156
        if (size < 16 &&
157
            !(thefile->flags & APR_XTHREAD) && 
158
            thefile->direction == 1 &&
159
            thefile->bufpos + size <= thefile->bufsize) {
160
161
            char *dest = thefile->buffer + thefile->bufpos;
162
            thefile->bufpos += size;
163
164
            const char *end = (const char *)buf + size;
165
            for (; pos != end; ++pos, ++dest)
166
                *dest = *pos;
167
168
            return APR_SUCCESS;
169
        }
170
156
        file_lock(thefile);
171
        file_lock(thefile);
157
172
158
        if ( thefile->direction == 0 ) {
173
        if ( thefile->direction == 0 ) {
Lines 167-184 Link Here
167
        }
182
        }
168
183
169
        rv = 0;
184
        rv = 0;
170
        while (rv == 0 && size > 0) {
171
            if (thefile->bufpos == thefile->bufsize)   /* write buffer is full*/
172
                rv = apr_file_flush_locked(thefile);
173
185
174
            blocksize = size > thefile->bufsize - thefile->bufpos ? 
186
        /* Large chunks shall not be buffered. They would cause at least one
175
                        thefile->bufsize - thefile->bufpos : size;
187
         * cache flush just "for themselves". So, we can pass them directly 
176
            memcpy(thefile->buffer + thefile->bufpos, pos, blocksize);                      
188
         * to the OS instead of copying them around and poking the OS for
177
            thefile->bufpos += blocksize;
189
         * every 4k of data in the buffer. */
178
            pos += blocksize;
190
        if (size > thefile->bufsize) {
179
            size -= blocksize;
191
            rv = apr_file_flush_locked(thefile);
192
            if (rv == APR_SUCCESS) {
193
                apr_ssize_t written;
194
195
                do {
196
                    written = write(thefile->filedes, buf, size);
197
                } while (written == -1 && errno == EINTR);
198
                if (written == -1)
199
                    rv = errno;
200
                else
201
                    thefile->filePtr += written;
202
            }
180
        }
203
        }
204
        else {
205
            while (rv == 0 && size > 0) {
206
                if (thefile->bufpos == thefile->bufsize)   /* write buffer is full */
207
                    rv = apr_file_flush_locked(thefile);
181
208
209
                blocksize = size > thefile->bufsize - thefile->bufpos ? 
210
                                         thefile->bufsize - thefile->bufpos : size;
211
                memcpy(thefile->buffer + thefile->bufpos, pos, blocksize);
212
                thefile->bufpos += blocksize;
213
                pos += blocksize;
214
                size -= blocksize;
215
            }
216
        }
217
182
        file_unlock(thefile);
218
        file_unlock(thefile);
183
219
184
        return rv;
220
        return rv;
Lines 283-291 Link Here
283
319
284
APR_DECLARE(apr_status_t) apr_file_putc(char ch, apr_file_t *thefile)
320
APR_DECLARE(apr_status_t) apr_file_putc(char ch, apr_file_t *thefile)
285
{
321
{
286
    apr_size_t nbytes = 1;
322
    if (!(thefile->flags & APR_XTHREAD) && 
323
        thefile->buffered &&
324
        thefile->direction == 1 &&
325
        thefile->bufpos < thefile->bufsize) {
287
326
288
    return apr_file_write(thefile, &ch, &nbytes);
327
        thefile->buffer [thefile->bufpos++] = ch;
328
329
        return APR_SUCCESS;
330
    }
331
    else {
332
        apr_size_t nbytes = 1;
333
        return apr_file_write(thefile, &ch, &nbytes);
334
    }
289
}
335
}
290
336
291
APR_DECLARE(apr_status_t) apr_file_ungetc(char ch, apr_file_t *thefile)
337
APR_DECLARE(apr_status_t) apr_file_ungetc(char ch, apr_file_t *thefile)
Lines 296-304 Link Here
296
342
297
APR_DECLARE(apr_status_t) apr_file_getc(char *ch, apr_file_t *thefile)
343
APR_DECLARE(apr_status_t) apr_file_getc(char *ch, apr_file_t *thefile)
298
{
344
{
299
    apr_size_t nbytes = 1;
345
    apr_status_t rc;
346
    apr_size_t bread;
300
347
301
    return apr_file_read(thefile, ch, &nbytes);
348
    if (thefile->ungetchar != -1) {
349
        ch = (char)thefile->ungetchar;
350
        thefile->ungetchar = -1;
351
        return APR_SUCCESS;
352
    }
353
354
    if (!(thefile->flags & APR_XTHREAD) && 
355
        thefile->buffered &&
356
        thefile->direction == 0 &&
357
        thefile->bufpos < thefile->dataRead) {
358
        *ch = thefile->buffer[thefile->bufpos++];
359
        return APR_SUCCESS;
360
    }
361
362
    bread = 1;
363
    rc = apr_file_read(thefile, ch, &bread);
364
365
    if (rc) {
366
        return rc;
367
    }
368
    
369
    if (bread == 0) {
370
        thefile->eof_hit = TRUE;
371
        return APR_EOF;
372
    }
373
    return APR_SUCCESS; 
302
}
374
}
303
375
304
APR_DECLARE(apr_status_t) apr_file_puts(const char *str, apr_file_t *thefile)
376
APR_DECLARE(apr_status_t) apr_file_puts(const char *str, apr_file_t *thefile)
(-)file_io/win32/readwrite.c (-143 / +206 lines)
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 {

Return to bug 49085