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
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
29 * 1) ungetchar not used for buffered files
31 APR_DECLARE(apr_status_t) apr_file_read(apr_file_t *thefile, void *buf, apr_size_t *nbytes)
34 apr_size_t bytes_read;
41 if (thefile->buffered) {
42 char *pos = (char *)buf;
43 apr_uint64_t blocksize;
44 apr_uint64_t size = *nbytes;
48 if (thefile->direction == 1) {
49 rv = apr_file_flush_locked(thefile);
55 thefile->direction = 0;
56 thefile->dataRead = 0;
60 if (thefile->ungetchar != -1) {
61 *pos = (char)thefile->ungetchar;
64 thefile->ungetchar = -1;
66 while (rv == 0 && size > 0) {
67 if (thefile->bufpos >= thefile->dataRead) {
68 int bytesread = read(thefile->filedes, thefile->buffer, APR_FILE_BUFSIZE);
70 thefile->eof_hit = TRUE;
74 else if (bytesread == -1) {
78 thefile->dataRead = bytesread;
79 thefile->filePtr += thefile->dataRead;
83 blocksize = size > thefile->dataRead - thefile->bufpos ? thefile->dataRead - thefile->bufpos : size;
84 memcpy(pos, thefile->buffer + thefile->bufpos, blocksize);
85 thefile->bufpos += blocksize;
90 *nbytes = pos - (char *)buf;
101 if (thefile->ungetchar != -1) {
103 *(char *)buf = (char)thefile->ungetchar;
104 buf = (char *)buf + 1;
106 thefile->ungetchar = -1;
108 *nbytes = bytes_read;
114 rv = read(thefile->filedes, buf, *nbytes);
115 } while (rv == -1 && errno == EINTR);
116 #ifdef USE_WAIT_FOR_IO
118 (errno == EAGAIN || errno == EWOULDBLOCK) &&
119 thefile->timeout != 0) {
120 apr_status_t arv = apr_wait_for_io_or_timeout(thefile, NULL, 1);
121 if (arv != APR_SUCCESS) {
122 *nbytes = bytes_read;
127 rv = read(thefile->filedes, buf, *nbytes);
128 } while (rv == -1 && errno == EINTR);
132 *nbytes = bytes_read;
134 thefile->eof_hit = TRUE;
145 APR_DECLARE(apr_status_t) apr_file_write(apr_file_t *thefile, const void *buf, apr_size_t *nbytes)
149 if (thefile->buffered) {
150 char *pos = (char *)buf;
156 if ( thefile->direction == 0 ) {
157 /* Position file pointer for writing at the offset we are
158 * logically reading from
160 apr_int64_t offset = thefile->filePtr - thefile->dataRead + thefile->bufpos;
161 if (offset != thefile->filePtr)
162 lseek(thefile->filedes, offset, SEEK_SET);
163 thefile->bufpos = thefile->dataRead = 0;
164 thefile->direction = 1;
168 while (rv == 0 && size > 0) {
169 if (thefile->bufpos == APR_FILE_BUFSIZE) /* write buffer is full*/
170 rv = apr_file_flush_locked(thefile);
172 blocksize = size > APR_FILE_BUFSIZE - thefile->bufpos ?
173 APR_FILE_BUFSIZE - thefile->bufpos : size;
174 memcpy(thefile->buffer + thefile->bufpos, pos, blocksize);
175 thefile->bufpos += blocksize;
180 file_unlock(thefile);
186 rv = write(thefile->filedes, buf, *nbytes);
187 } while (rv == (apr_size_t)-1 && errno == EINTR);
188 #ifdef USE_WAIT_FOR_IO
189 if (rv == (apr_size_t)-1 &&
190 (errno == EAGAIN || errno == EWOULDBLOCK) &&
191 thefile->timeout != 0) {
192 apr_status_t arv = apr_wait_for_io_or_timeout(thefile, NULL, 0);
193 if (arv != APR_SUCCESS) {
200 rv = write(thefile->filedes, buf, *nbytes);
201 } while (rv == (apr_size_t)-1 && errno == EINTR);
202 if (rv == (apr_size_t)-1 &&
203 (errno == EAGAIN || errno == EWOULDBLOCK)) {
204 *nbytes /= 2; /* yes, we'll loop if kernel lied
205 * and we can't even write 1 byte
215 if (rv == (apr_size_t)-1) {
224 APR_DECLARE(apr_status_t) apr_file_writev(apr_file_t *thefile, const struct iovec *vec,
225 apr_size_t nvec, apr_size_t *nbytes)
231 if (thefile->buffered) {
234 rv = apr_file_flush_locked(thefile);
235 if (rv != APR_SUCCESS) {
236 file_unlock(thefile);
239 if (thefile->direction == 0) {
240 /* Position file pointer for writing at the offset we are
241 * logically reading from
243 apr_int64_t offset = thefile->filePtr - thefile->dataRead +
245 if (offset != thefile->filePtr)
246 lseek(thefile->filedes, offset, SEEK_SET);
247 thefile->bufpos = thefile->dataRead = 0;
250 file_unlock(thefile);
253 if ((bytes = writev(thefile->filedes, vec, nvec)) < 0) {
263 *nbytes = vec[0].iov_len;
264 return apr_file_write(thefile, vec[0].iov_base, nbytes);
268 APR_DECLARE(apr_status_t) apr_file_putc(char ch, apr_file_t *thefile)
270 apr_size_t nbytes = 1;
272 return apr_file_write(thefile, &ch, &nbytes);
275 APR_DECLARE(apr_status_t) apr_file_ungetc(char ch, apr_file_t *thefile)
277 thefile->ungetchar = (unsigned char)ch;
281 APR_DECLARE(apr_status_t) apr_file_getc(char *ch, apr_file_t *thefile)
283 apr_size_t nbytes = 1;
285 return apr_file_read(thefile, ch, &nbytes);
288 APR_DECLARE(apr_status_t) apr_file_puts(const char *str, apr_file_t *thefile)
290 apr_size_t nbytes = strlen(str);
292 return apr_file_write(thefile, str, &nbytes);
295 apr_status_t apr_file_flush_locked(apr_file_t *thefile)
297 apr_status_t rv = APR_SUCCESS;
299 if (thefile->direction == 1 && thefile->bufpos) {
303 written = write(thefile->filedes, thefile->buffer, thefile->bufpos);
304 } while (written == -1 && errno == EINTR);
308 thefile->filePtr += written;
316 APR_DECLARE(apr_status_t) apr_file_flush(apr_file_t *thefile)
318 apr_status_t rv = APR_SUCCESS;
320 if (thefile->buffered) {
322 rv = apr_file_flush_locked(thefile);
323 file_unlock(thefile);
325 /* There isn't anything to do if we aren't buffering the output
326 * so just return success.
331 APR_DECLARE(apr_status_t) apr_file_gets(char *str, int len, apr_file_t *thefile)
333 apr_status_t rv = APR_SUCCESS; /* get rid of gcc warning */
335 const char *str_start = str;
336 char *final = str + len - 1;
339 /* sort of like fgets(), which returns NULL and stores no bytes
344 while (str < final) { /* leave room for trailing '\0' */
346 rv = apr_file_read(thefile, str, &nbytes);
347 if (rv != APR_SUCCESS) {
356 /* We must store a terminating '\0' if we've stored any chars. We can
357 * get away with storing it if we hit an error first.
360 if (str > str_start) {
361 /* we stored chars; don't report EOF or any other errors;
362 * the app will find out about that on the next call
369 APR_DECLARE_NONSTD(int) apr_file_printf(apr_file_t *fptr,
370 const char *format, ...)
377 buf = malloc(HUGE_STRING_LEN);
381 va_start(ap, format);
382 len = apr_vsnprintf(buf, HUGE_STRING_LEN, format, ap);
383 cc = apr_file_puts(buf, fptr);
386 return (cc == APR_SUCCESS) ? len : -1;