1
/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as
4
* Licensed under the Apache License, Version 2.0 (the "License");
5
* you may not use this file except in compliance with the License.
6
* You may obtain a copy of the License at
8
* http://www.apache.org/licenses/LICENSE-2.0
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.
17
#include "apr_arch_file_io.h"
18
#include "apr_strings.h"
19
#include "apr_thread_mutex.h"
20
#include "apr_support.h"
22
/* The only case where we don't use wait_for_io_or_timeout is on
23
* pre-BONE BeOS, so this check should be sufficient and simpler */
25
#define USE_WAIT_FOR_IO
28
APR_DECLARE(apr_status_t) apr_file_read(apr_file_t *thefile, void *buf, apr_size_t *nbytes)
31
apr_size_t bytes_read;
38
if (thefile->buffered) {
39
char *pos = (char *)buf;
40
apr_uint64_t blocksize;
41
apr_uint64_t size = *nbytes;
44
if (thefile->thlock) {
45
apr_thread_mutex_lock(thefile->thlock);
49
if (thefile->direction == 1) {
50
rv = apr_file_flush(thefile);
53
if (thefile->thlock) {
54
apr_thread_mutex_unlock(thefile->thlock);
60
thefile->direction = 0;
61
thefile->dataRead = 0;
65
if (thefile->ungetchar != -1) {
66
*pos = (char)thefile->ungetchar;
69
thefile->ungetchar = -1;
71
while (rv == 0 && size > 0) {
72
if (thefile->bufpos >= thefile->dataRead) {
73
int bytesread = read(thefile->filedes, thefile->buffer, APR_FILE_BUFSIZE);
75
thefile->eof_hit = TRUE;
79
else if (bytesread == -1) {
83
thefile->dataRead = bytesread;
84
thefile->filePtr += thefile->dataRead;
88
blocksize = size > thefile->dataRead - thefile->bufpos ? thefile->dataRead - thefile->bufpos : size;
89
memcpy(pos, thefile->buffer + thefile->bufpos, blocksize);
90
thefile->bufpos += blocksize;
95
*nbytes = pos - (char *)buf;
100
if (thefile->thlock) {
101
apr_thread_mutex_unlock(thefile->thlock);
108
if (thefile->ungetchar != -1) {
110
*(char *)buf = (char)thefile->ungetchar;
111
buf = (char *)buf + 1;
113
thefile->ungetchar = -1;
115
*nbytes = bytes_read;
121
rv = read(thefile->filedes, buf, *nbytes);
122
} while (rv == -1 && errno == EINTR);
123
#ifdef USE_WAIT_FOR_IO
125
(errno == EAGAIN || errno == EWOULDBLOCK) &&
126
thefile->timeout != 0) {
127
apr_status_t arv = apr_wait_for_io_or_timeout(thefile, NULL, 1);
128
if (arv != APR_SUCCESS) {
129
*nbytes = bytes_read;
134
rv = read(thefile->filedes, buf, *nbytes);
135
} while (rv == -1 && errno == EINTR);
139
*nbytes = bytes_read;
141
thefile->eof_hit = TRUE;
152
APR_DECLARE(apr_status_t) apr_file_write(apr_file_t *thefile, const void *buf, apr_size_t *nbytes)
156
if (thefile->buffered) {
157
char *pos = (char *)buf;
162
if (thefile->thlock) {
163
apr_thread_mutex_lock(thefile->thlock);
167
if ( thefile->direction == 0 ) {
168
/* Position file pointer for writing at the offset we are
169
* logically reading from
171
apr_int64_t offset = thefile->filePtr - thefile->dataRead + thefile->bufpos;
172
if (offset != thefile->filePtr)
173
lseek(thefile->filedes, offset, SEEK_SET);
174
thefile->bufpos = thefile->dataRead = 0;
175
thefile->direction = 1;
179
while (rv == 0 && size > 0) {
180
if (thefile->bufpos == APR_FILE_BUFSIZE) /* write buffer is full*/
181
rv = apr_file_flush(thefile);
183
blocksize = size > APR_FILE_BUFSIZE - thefile->bufpos ?
184
APR_FILE_BUFSIZE - thefile->bufpos : size;
185
memcpy(thefile->buffer + thefile->bufpos, pos, blocksize);
186
thefile->bufpos += blocksize;
192
if (thefile->thlock) {
193
apr_thread_mutex_unlock(thefile->thlock);
200
rv = write(thefile->filedes, buf, *nbytes);
201
} while (rv == (apr_size_t)-1 && errno == EINTR);
202
#ifdef USE_WAIT_FOR_IO
203
if (rv == (apr_size_t)-1 &&
204
(errno == EAGAIN || errno == EWOULDBLOCK) &&
205
thefile->timeout != 0) {
206
apr_status_t arv = apr_wait_for_io_or_timeout(thefile, NULL, 0);
207
if (arv != APR_SUCCESS) {
214
rv = write(thefile->filedes, buf, *nbytes);
215
} while (rv == (apr_size_t)-1 && errno == EINTR);
216
if (rv == (apr_size_t)-1 &&
217
(errno == EAGAIN || errno == EWOULDBLOCK)) {
218
*nbytes /= 2; /* yes, we'll loop if kernel lied
219
* and we can't even write 1 byte
229
if (rv == (apr_size_t)-1) {
238
APR_DECLARE(apr_status_t) apr_file_writev(apr_file_t *thefile, const struct iovec *vec,
239
apr_size_t nvec, apr_size_t *nbytes)
244
if ((bytes = writev(thefile->filedes, vec, nvec)) < 0) {
254
* The problem with trying to output the entire iovec is that we cannot
255
* maintain the behavoir that a real writev would have. If we iterate
256
* over the iovec one at a time, we loose the atomic properties of
257
* writev(). The other option is to combine the entire iovec into one
258
* buffer that we could then send in one call to write(). This is not
259
* reasonable since we do not know how much data an iovec could contain.
261
* The only reasonable option, that maintains the semantics of a real
262
* writev(), is to only write the first iovec. Callers of file_writev()
263
* must deal with partial writes as they normally would. If you want to
264
* ensure an entire iovec is written, use apr_file_writev_full().
267
*nbytes = vec[0].iov_len;
268
return apr_file_write(thefile, vec[0].iov_base, nbytes);
272
APR_DECLARE(apr_status_t) apr_file_putc(char ch, apr_file_t *thefile)
274
apr_size_t nbytes = 1;
276
return apr_file_write(thefile, &ch, &nbytes);
279
APR_DECLARE(apr_status_t) apr_file_ungetc(char ch, apr_file_t *thefile)
281
thefile->ungetchar = (unsigned char)ch;
285
APR_DECLARE(apr_status_t) apr_file_getc(char *ch, apr_file_t *thefile)
287
apr_size_t nbytes = 1;
289
return apr_file_read(thefile, ch, &nbytes);
292
APR_DECLARE(apr_status_t) apr_file_puts(const char *str, apr_file_t *thefile)
294
return apr_file_write_full(thefile, str, strlen(str), NULL);
297
APR_DECLARE(apr_status_t) apr_file_flush(apr_file_t *thefile)
299
if (thefile->buffered) {
300
apr_int64_t written = 0;
302
if (thefile->direction == 1 && thefile->bufpos) {
304
written = write(thefile->filedes, thefile->buffer, thefile->bufpos);
305
} while (written == (apr_int64_t)-1 && errno == EINTR);
306
if (written == (apr_int64_t)-1) {
309
thefile->filePtr += written;
313
/* There isn't anything to do if we aren't buffering the output
314
* so just return success.
319
APR_DECLARE(apr_status_t) apr_file_gets(char *str, int len, apr_file_t *thefile)
321
apr_status_t rv = APR_SUCCESS; /* get rid of gcc warning */
323
const char *str_start = str;
324
char *final = str + len - 1;
327
/* sort of like fgets(), which returns NULL and stores no bytes
332
/* If we have an underlying buffer, we can be *much* more efficient
333
* and skip over the apr_file_read calls.
335
if (thefile->buffered) {
338
if (thefile->thlock) {
339
apr_thread_mutex_lock(thefile->thlock);
343
if (thefile->direction == 1) {
344
rv = apr_file_flush(thefile);
347
if (thefile->thlock) {
348
apr_thread_mutex_unlock(thefile->thlock);
354
thefile->direction = 0;
356
thefile->dataRead = 0;
359
while (str < final) { /* leave room for trailing '\0' */
360
/* Force ungetc leftover to call apr_file_read. */
361
if (thefile->bufpos < thefile->dataRead &&
362
thefile->ungetchar == -1) {
363
*str = thefile->buffer[thefile->bufpos++];
367
rv = apr_file_read(thefile, str, &nbytes);
368
if (rv != APR_SUCCESS) {
380
if (thefile->thlock) {
381
apr_thread_mutex_unlock(thefile->thlock);
386
while (str < final) { /* leave room for trailing '\0' */
388
rv = apr_file_read(thefile, str, &nbytes);
389
if (rv != APR_SUCCESS) {
400
/* We must store a terminating '\0' if we've stored any chars. We can
401
* get away with storing it if we hit an error first.
404
if (str > str_start) {
405
/* we stored chars; don't report EOF or any other errors;
406
* the app will find out about that on the next call
413
struct apr_file_printf_data {
414
apr_vformatter_buff_t vbuff;
419
static int file_printf_flush(apr_vformatter_buff_t *buff)
421
struct apr_file_printf_data *data = (struct apr_file_printf_data *)buff;
423
if (apr_file_write_full(data->fptr, data->buf,
424
data->vbuff.curpos - data->buf, NULL)) {
428
data->vbuff.curpos = data->buf;
432
APR_DECLARE_NONSTD(int) apr_file_printf(apr_file_t *fptr,
433
const char *format, ...)
435
struct apr_file_printf_data data;
439
/* don't really need a HUGE_STRING_LEN anymore */
440
data.buf = malloc(HUGE_STRING_LEN);
441
if (data.buf == NULL) {
444
data.vbuff.curpos = data.buf;
445
data.vbuff.endpos = data.buf + HUGE_STRING_LEN;
447
va_start(ap, format);
448
count = apr_vformatter(file_printf_flush,
449
(apr_vformatter_buff_t *)&data, format, ap);
450
/* apr_vformatter does not call flush for the last bits */
451
if (count >= 0) file_printf_flush((apr_vformatter_buff_t *)&data);