Apache HTTPD
readwrite.c
Go to the documentation of this file.
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_general.h"
20#include "apr_strings.h"
21#include "apr_lib.h"
22#include "apr_errno.h"
23#include <malloc.h>
24#include "apr_arch_atime.h"
25#include "apr_arch_misc.h"
26
27/*
28 * read_with_timeout()
29 * Uses async i/o to emulate unix non-blocking i/o with timeouts.
30 */
32{
33 apr_status_t rv;
34 DWORD res;
36 DWORD bytesread = 0;
37
38 /* Handle the zero timeout non-blocking case */
39 if (file->timeout == 0) {
40 /* Peek at the pipe. If there is no data available, return APR_EAGAIN.
41 * If data is available, go ahead and read it.
42 */
43 if (file->pipe) {
45 if (!PeekNamedPipe(file->filehand, NULL, 0, NULL, &bytes, NULL)) {
46 rv = apr_get_os_error();
48 rv = APR_EOF;
49 }
50 *nbytes = 0;
51 return rv;
52 }
53 else {
54 if (bytes == 0) {
55 *nbytes = 0;
56 return APR_EAGAIN;
57 }
58 if (len > bytes) {
59 len = bytes;
60 }
61 }
62 }
63 else {
64 /* ToDo: Handle zero timeout non-blocking file i/o
65 * This is not needed until an APR application needs to
66 * timeout file i/o (which means setting file i/o non-blocking)
67 */
68 }
69 }
70
71 if (file->pOverlapped && !file->pipe) {
72 file->pOverlapped->Offset = (DWORD)file->filePtr;
73 file->pOverlapped->OffsetHigh = (DWORD)(file->filePtr >> 32);
74 }
75
78 rv = APR_SUCCESS;
79 }
80 else {
81 rv = apr_get_os_error();
83 /* Wait for the pending i/o, timeout converted from us to ms
84 * Note that we loop if someone gives up the event, since
85 * folks suggest that WAIT_ABANDONED isn't actually a result
86 * but an alert that ownership of the event has passed from
87 * one owner to a new proc/thread.
88 */
89 do {
91 (file->timeout > 0)
92 ? (DWORD)(file->timeout/1000)
93 : ((file->timeout == -1)
94 ? INFINITE : 0));
95 } while (res == WAIT_ABANDONED);
96
97 /* There is one case that represents entirely
98 * successful operations, otherwise we will cancel
99 * the operation in progress.
100 */
101 if (res != WAIT_OBJECT_0) {
103 }
104
105 /* Ignore any failures above. Attempt to complete
106 * the overlapped operation and use only _its_ result.
107 * For example, CancelIo or WaitForSingleObject can
108 * fail if the handle is closed, yet the read may have
109 * completed before we attempted to CancelIo...
110 */
112 &bytesread, TRUE)) {
113 rv = APR_SUCCESS;
114 }
115 else {
116 rv = apr_get_os_error();
119 && (res == WAIT_TIMEOUT))
120 rv = APR_TIMEUP;
121 }
122 }
124 /* Assume ERROR_BROKEN_PIPE signals an EOF reading from a pipe */
125 rv = APR_EOF;
126 } else if (rv == APR_FROM_OS_ERROR(ERROR_HANDLE_EOF)) {
127 /* Did we hit EOF reading from the handle? */
128 rv = APR_EOF;
129 }
130 }
131
132 /* OK and 0 bytes read ==> end of file */
133 if (rv == APR_SUCCESS && bytesread == 0)
134 rv = APR_EOF;
135
136 if (rv == APR_SUCCESS && file->pOverlapped && !file->pipe) {
138 }
139 *nbytes = bytesread;
140 return rv;
141}
142
144{
145 apr_status_t rv;
146 char *pos = (char *)buf;
149 apr_size_t remaining = *len;
150
151 if (thefile->direction == 1) {
153 if (rv != APR_SUCCESS) {
154 return rv;
155 }
156 thefile->bufpos = 0;
157 thefile->direction = 0;
158 thefile->dataRead = 0;
159 }
160
161 /* Copy the data we have in the buffer. */
163 if (size > remaining) {
164 size = remaining;
165 }
167 pos += size;
168 remaining -= size;
169 thefile->bufpos += size;
170
171 if (remaining == 0) {
172 /* Nothing to do more, keep *LEN unchanged and return. */
173 return APR_SUCCESS;
174 }
175 /* The buffer is empty, but the caller wants more.
176 * Decide on the most appropriate way to read from the file:
177 */
178 if (remaining > thefile->bufsize) {
179 /* If the remaining chunk won't fit into the buffer, read it into
180 * the destination buffer with a single syscall.
181 */
182 rv = read_with_timeout(thefile, pos, remaining, &bytes_read);
184 pos += bytes_read;
185 /* Also, copy the last BUFSIZE (or less in case of a short read) bytes
186 * from the chunk to our buffer so that seeking backwards and reading
187 * would work from the buffer.
188 */
190 if (size > bytes_read) {
192 }
193 memcpy(thefile->buffer, pos - size, size);
196 }
197 else {
198 /* The remaining chunk fits into the buffer. Read up to BUFSIZE bytes
199 * from the file to our internal buffer.
200 */
203 thefile->bufpos = 0;
205 /* Copy the required part to the caller. */
206 size = remaining;
207 if (size > bytes_read) {
209 }
210 memcpy(pos, thefile->buffer, size);
211 pos += size;
212 thefile->bufpos += size;
213 }
214
215 if (bytes_read == 0 && rv == APR_EOF) {
217 }
218
219 *len = pos - (char *)buf;
220 if (*len) {
221 rv = APR_SUCCESS;
222 }
223
224 return rv;
225}
226
228{
229 apr_status_t rv;
230 DWORD bytes_read = 0;
231
232 if (*len <= 0) {
233 *len = 0;
234 return APR_SUCCESS;
235 }
236
237 /* If the file is open for xthread support, allocate and
238 * initialize the overlapped and io completion event (hEvent).
239 * Threads should NOT share an apr_file_t or its hEvent.
240 */
243 sizeof(OVERLAPPED));
245 if (!thefile->pOverlapped->hEvent) {
246 rv = apr_get_os_error();
247 return rv;
248 }
249 }
250
251 /* Handle the ungetchar if there is one */
252 if (thefile->ungetchar != -1) {
253 bytes_read = 1;
254 *(char *)buf = (char)thefile->ungetchar;
255 buf = (char *)buf + 1;
256 (*len)--;
257 thefile->ungetchar = -1;
258 if (*len == 0) {
259 *len = bytes_read;
260 return APR_SUCCESS;
261 }
262 }
263 if (thefile->buffered) {
266 }
270 }
271 } else {
272 /* Unbuffered i/o */
275 if (rv == APR_EOF)
277 *len = nbytes;
278 }
279
280 return rv;
281}
282
283/* Helper function that adapts WriteFile() to apr_size_t instead
284 * of DWORD. */
285static apr_status_t write_helper(HANDLE filehand, const char *buf,
287{
288 apr_size_t remaining = len;
289
290 *pwritten = 0;
291 do {
293 DWORD written;
294
295 if (remaining > APR_DWORD_MAX) {
297 }
298 else {
299 to_write = (DWORD)remaining;
300 }
301
302 if (!WriteFile(filehand, buf, to_write, &written, NULL)) {
303 *pwritten += written;
304 return apr_get_os_error();
305 }
306
307 *pwritten += written;
308 remaining -= written;
309 buf += written;
310 } while (remaining);
311
312 return APR_SUCCESS;
313}
314
317{
318 apr_status_t rv;
319
320 if (thefile->direction == 0) {
321 /* Position file pointer for writing at the offset we are logically reading from */
324 LONG offhi = (LONG)(offset >> 32);
325 if (offset != thefile->filePtr)
328 thefile->direction = 1;
329 }
330
331 *pwritten = 0;
332
333 while (len > 0) {
334 if (thefile->bufpos == thefile->bufsize) { /* write buffer is full */
336 if (rv) {
337 return rv;
338 }
339 }
340 /* If our buffer is empty, and we cannot fit the remaining chunk
341 * into it, write the chunk with a single syscall and return.
342 */
343 if (thefile->bufpos == 0 && len > thefile->bufsize) {
344 apr_size_t written;
345
346 rv = write_helper(thefile->filehand, buf, len, &written);
347 thefile->filePtr += written;
348 *pwritten += written;
349 return rv;
350 }
351 else {
353
356 }
359 buf += blocksize;
360 len -= blocksize;
362 }
363 }
364
365 return APR_SUCCESS;
366}
367
369{
370 apr_status_t rv;
372
373 /* If the file is open for xthread support, allocate and
374 * initialize the overlapped and io completion event (hEvent).
375 * Threads should NOT share an apr_file_t or its hEvent.
376 */
379 sizeof(OVERLAPPED));
381 if (!thefile->pOverlapped->hEvent) {
382 rv = apr_get_os_error();
383 return rv;
384 }
385 }
386
387 if (thefile->buffered) {
390 }
394 }
395 return rv;
396 } else {
397 if (thefile->pipe) {
400 }
401 else if (thefile->append && !thefile->pOverlapped) {
402 OVERLAPPED ov = {0};
403
404 /* If the file is opened for synchronous I/O, take advantage of the
405 * documented way to atomically append data by calling WriteFile()
406 * with both the OVERLAPPED.Offset and OffsetHigh members set to
407 * 0xFFFFFFFF. This avoids calling LockFile() that is otherwise
408 * required to avoid a race condition between seeking to the end
409 * and writing data. Not locking the file improves robustness of
410 * such appends and avoids a deadlock when appending to an already
411 * locked file, as described in PR50058.
412 *
413 * We use this approach only for files opened for synchronous I/O
414 * because in this case the I/O Manager maintains the current file
415 * position. Otherwise, the file offset returned or changed by
416 * the SetFilePointer() API is not guaranteed to be valid and that
417 * could, for instance, break apr_file_seek() calls after appending
418 * data. Sadly, if a file is opened for asynchronous I/O, this
419 * call doesn't update the OVERLAPPED.Offset member to reflect the
420 * actual offset used when appending the data (which we could then
421 * use to make seeking and other operations involving filePtr work).
422 * Therefore, when appending to files opened for asynchronous I/O,
423 * we still use the LockFile + SetFilePointer + WriteFile approach.
424 *
425 * References:
426 * https://bz.apache.org/bugzilla/show_bug.cgi?id=50058
427 * https://msdn.microsoft.com/en-us/library/windows/desktop/aa365747
428 * https://msdn.microsoft.com/en-us/library/windows/hardware/ff567121
429 */
430 ov.Offset = MAXDWORD;
431 ov.OffsetHigh = MAXDWORD;
433 }
434 else {
435 apr_off_t offset = 0;
437 if (thefile->append) {
438 /* apr_file_lock will mutex the file across processes.
439 * The call to apr_thread_mutex_lock is added to avoid
440 * a race condition between LockFile and WriteFile
441 * that occasionally leads to deadlocked threads.
442 */
445 if (rc != APR_SUCCESS) {
447 return rc;
448 }
450 if (rc != APR_SUCCESS) {
452 return rc;
453 }
454 }
455 if (thefile->pOverlapped) {
457 thefile->pOverlapped->OffsetHigh = (DWORD)(thefile->filePtr >> 32);
458 }
461 if (thefile->append) {
464 }
465 }
466 if (rv) {
467 *nbytes = bwrote;
468 rv = APR_SUCCESS;
469 }
470 else {
471 (*nbytes) = 0;
472 rv = apr_get_os_error();
473
474 /* XXX: This must be corrected, per the apr_file_read logic!!! */
476
477 DWORD timeout_ms;
478
479 if (thefile->timeout == 0) {
480 timeout_ms = 0;
481 }
482 else if (thefile->timeout < 0) {
483 timeout_ms = INFINITE;
484 }
485 else {
486 timeout_ms = (DWORD)(thefile->timeout / 1000);
487 }
488
489 rv = WaitForSingleObject(thefile->pOverlapped->hEvent, timeout_ms);
490 switch (rv) {
491 case WAIT_OBJECT_0:
493 &bwrote, TRUE);
494 *nbytes = bwrote;
495 rv = APR_SUCCESS;
496 break;
497 case WAIT_TIMEOUT:
498 rv = (timeout_ms == 0) ? APR_EAGAIN : APR_TIMEUP;
499 break;
500 case WAIT_FAILED:
501 rv = apr_get_os_error();
502 break;
503 default:
504 break;
505 }
506 if (rv != APR_SUCCESS) {
509 }
510 }
511 }
512 if (rv == APR_SUCCESS && thefile->pOverlapped && !thefile->pipe) {
514 }
515 }
516 return rv;
517}
518/* ToDo: Write for it anyway and test the oslevel!
519 * Too bad WriteFileGather() is not supported on 95&98 (or NT prior to SP2)
520 */
522 const struct iovec *vec,
525{
528 apr_size_t bwrote = 0;
529 char *buf;
530
531 *nbytes = 0;
532 for (i = 0; i < nvec; i++) {
533 buf = vec[i].iov_base;
534 bwrote = vec[i].iov_len;
536 *nbytes += bwrote;
537 if (rv != APR_SUCCESS) {
538 break;
539 }
540 }
541 return rv;
542}
543
545{
546 apr_size_t len = 1;
547
548 return apr_file_write(thefile, &ch, &len);
549}
550
552{
553 thefile->ungetchar = (unsigned char) ch;
554 return APR_SUCCESS;
555}
556
558{
561
562 bread = 1;
564
565 if (rc) {
566 return rc;
567 }
568
569 if (bread == 0) {
571 return APR_EOF;
572 }
573 return APR_SUCCESS;
574}
575
577{
578 apr_size_t len = strlen(str);
579
580 return apr_file_write(thefile, str, &len);
581}
582
584{
587 const char *str_start = str;
588 char *final = str + len - 1;
589
590 /* If the file is open for xthread support, allocate and
591 * initialize the overlapped and io completion event (hEvent).
592 * Threads should NOT share an apr_file_t or its hEvent.
593 */
596 sizeof(OVERLAPPED));
598 if (!thefile->pOverlapped->hEvent) {
599 rv = apr_get_os_error();
600 return rv;
601 }
602 }
603
604 /* Handle the ungetchar if there is one. */
605 if (thefile->ungetchar != -1 && str < final) {
607 thefile->ungetchar = -1;
608 if (*str == '\n') {
609 *(++str) = '\0';
610 return APR_SUCCESS;
611 }
612 ++str;
613 }
614
615 /* If we have an underlying buffer, we can be *much* more efficient
616 * and skip over the read_with_timeout() calls.
617 */
618 if (thefile->buffered) {
621 }
622
623 if (thefile->direction == 1) {
625 if (rv) {
628 }
629 return rv;
630 }
631
632 thefile->direction = 0;
633 thefile->bufpos = 0;
634 thefile->dataRead = 0;
635 }
636
637 while (str < final) { /* leave room for trailing '\0' */
638 if (thefile->bufpos < thefile->dataRead) {
640 }
641 else {
642 nbytes = 1;
644 if (rv != APR_SUCCESS) {
645 break;
646 }
647 }
648 if (*str == '\n') {
649 ++str;
650 break;
651 }
652 ++str;
653 }
656 }
657 }
658 else {
659 while (str < final) { /* leave room for trailing '\0' */
660 nbytes = 1;
662 if (rv == APR_EOF)
664
665 if (rv != APR_SUCCESS) {
666 break;
667 }
668 if (*str == '\n') {
669 ++str;
670 break;
671 }
672 ++str;
673 }
674 }
675
676 /* We must store a terminating '\0' if we've stored any chars. We can
677 * get away with storing it if we hit an error first.
678 */
679 *str = '\0';
680 if (str > str_start) {
681 /* We stored chars; don't report EOF or any other errors;
682 * the app will find out about that on the next call.
683 */
684 return APR_SUCCESS;
685 }
686 return rv;
687}
688
690{
691 if (thefile->buffered) {
692 apr_status_t rc = 0;
693
694 if (thefile->direction == 1 && thefile->bufpos) {
695 apr_size_t written;
696
698 thefile->bufpos, &written);
699 thefile->filePtr += written;
700
701 if (rc == 0)
702 thefile->bufpos = 0;
703 }
704
705 return rc;
706 }
707
708 /* There isn't anything to do if we aren't buffering the output
709 * so just return success.
710 */
711 return APR_SUCCESS;
712}
713
715 apr_status_t rv;
716
718 if (rv != APR_SUCCESS) {
719 return rv;
720 }
721
723 rv = apr_get_os_error();
724 }
725
726 return rv;
727}
728
730 return apr_file_sync(thefile);
731}
732
736 char *buf;
737};
738
740{
742
743 if (apr_file_write_full(data->fptr, data->buf,
744 data->vbuff.curpos - data->buf, NULL)) {
745 return -1;
746 }
747
748 data->vbuff.curpos = data->buf;
749 return 0;
750}
751
753 const char *format, ...)
754{
756 va_list ap;
757 int count;
758
760 if (data.buf == NULL) {
761 return 0;
762 }
763 data.vbuff.curpos = data.buf;
764 data.vbuff.endpos = data.buf + HUGE_STRING_LEN;
765 data.fptr = fptr;
769 /* apr_vformatter does not call flush for the last bits */
771
772 va_end(ap);
773
774 free(data.buf);
775 return count;
776}
const char * buff
Definition ap_regex.h:186
const char apr_size_t len
Definition ap_regex.h:187
#define TRUE
Definition abts.h:38
#define FALSE
Definition abts.h:35
#define WaitForSingleObject(h, d)
APR Error Codes.
APR File I/O Handling.
APR Miscellaneous library routines.
APR general purpose library routines.
APR Strings library.
#define HUGE_STRING_LEN
Definition httpd.h:303
const unsigned char * buf
Definition util_md5.h:50
#define APR_EAGAIN
Definition apr_errno.h:730
#define APR_EOF
Definition apr_errno.h:461
#define APR_TIMEUP
Definition apr_errno.h:450
unsigned int count
Definition apr_md5.h:152
apr_pool_t apr_dbd_t apr_dbd_results_t ** res
Definition apr_dbd.h:287
apr_redis_t * rc
Definition apr_redis.h:173
const void apr_status_t(*) apr_status_t(* APR_DECLARE)(void) apr_pool_pre_cleanup_register(apr_pool_t *p
Definition apr_pools.h:646
apr_size_t size
#define APR_FROM_OS_ERROR(e)
Definition apr_errno.h:1214
#define APR_SUCCESS
Definition apr_errno.h:225
#define apr_get_os_error()
Definition apr_errno.h:1217
int apr_status_t
Definition apr_errno.h:44
apr_file_t * thefile
void apr_size_t * nbytes
const struct iovec * vec
apr_seek_where_t apr_off_t * offset
const char * format
void apr_size_t apr_size_t * bytes_read
void * data
const char apr_file_t * file
const struct iovec apr_size_t nvec
#define APR_FLOCK_EXCLUSIVE
#define APR_FOPEN_XTHREAD
Definition apr_file_io.h:67
#define APR_END
apr_vformatter_buff_t const char va_list ap
Definition apr_lib.h:176
APR_DECLARE_NONSTD(void) apr_terminate(void)
Definition start.c:173
#define apr_pcalloc(p, size)
Definition apr_pools.h:465
const void apr_size_t bytes
Definition apr_random.h:91
#define LONG
return NULL
Definition mod_so.c:359
int i
Definition mod_so.c:347
apr_status_t apr_file_lock(apr_file_t *thefile, int type)
Definition flock.c:21
apr_status_t apr_file_unlock(apr_file_t *thefile)
Definition flock.c:33
apr_vformatter_buff_t vbuff
Definition readwrite.c:494
apr_file_t * fptr
Definition readwrite.c:495
apr_int32_t flags
apr_interval_time_t timeout
apr_size_t bufpos
apr_off_t filePtr
apr_thread_mutex_t * mutex
apr_off_t dataRead
apr_pool_t * pool
OVERLAPPED * pOverlapped
apr_size_t bufsize
static int file_printf_flush(apr_vformatter_buff_t *buff)
Definition readwrite.c:499
#define str
typedef HANDLE(WINAPI *apr_winapi_fpt_CreateToolhelp32Snapshot)(DWORD dwFlags
APR_DECLARE_DATA apr_oslevel_e apr_os_level
Definition misc.c:24
@ APR_WIN_98
#define CancelIo
typedef DWORD(WINAPI *apr_winapi_fpt_GetCompressedFileSizeA)(IN LPCSTR lpFileName
static apr_status_t read_buffered(apr_file_t *thefile, void *buf, apr_size_t *len)
Definition readwrite.c:143
static apr_status_t write_helper(HANDLE filehand, const char *buf, apr_size_t len, apr_size_t *pwritten)
Definition readwrite.c:285
static apr_status_t read_with_timeout(apr_file_t *file, void *buf, apr_size_t len_in, apr_size_t *nbytes)
Definition readwrite.c:31
static apr_status_t write_buffered(apr_file_t *thefile, const char *buf, apr_size_t len, apr_size_t *pwritten)
Definition readwrite.c:315