feat:replace boost library with C++11 std library
This commit is contained in:
+528
@@ -0,0 +1,528 @@
|
||||
/* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "apr_arch_file_io.h"
|
||||
#include "apr_strings.h"
|
||||
#include "apr_thread_mutex.h"
|
||||
#include "apr_support.h"
|
||||
|
||||
/* The only case where we don't use wait_for_io_or_timeout is on
|
||||
* pre-BONE BeOS, so this check should be sufficient and simpler */
|
||||
#if !defined(BEOS_R5)
|
||||
#define USE_WAIT_FOR_IO
|
||||
#endif
|
||||
|
||||
static apr_status_t file_read_buffered(apr_file_t *thefile, void *buf,
|
||||
apr_size_t *nbytes)
|
||||
{
|
||||
apr_ssize_t rv;
|
||||
char *pos = (char *)buf;
|
||||
apr_uint64_t blocksize;
|
||||
apr_uint64_t size = *nbytes;
|
||||
|
||||
if (thefile->direction == 1) {
|
||||
rv = apr_file_flush_locked(thefile);
|
||||
if (rv) {
|
||||
return rv;
|
||||
}
|
||||
thefile->bufpos = 0;
|
||||
thefile->direction = 0;
|
||||
thefile->dataRead = 0;
|
||||
}
|
||||
|
||||
rv = 0;
|
||||
if (thefile->ungetchar != -1) {
|
||||
*pos = (char)thefile->ungetchar;
|
||||
++pos;
|
||||
--size;
|
||||
thefile->ungetchar = -1;
|
||||
}
|
||||
while (rv == 0 && size > 0) {
|
||||
if (thefile->bufpos >= thefile->dataRead) {
|
||||
int bytesread = read(thefile->filedes, thefile->buffer,
|
||||
thefile->bufsize);
|
||||
if (bytesread == 0) {
|
||||
thefile->eof_hit = TRUE;
|
||||
rv = APR_EOF;
|
||||
break;
|
||||
}
|
||||
else if (bytesread == -1) {
|
||||
rv = errno;
|
||||
break;
|
||||
}
|
||||
thefile->dataRead = bytesread;
|
||||
thefile->filePtr += thefile->dataRead;
|
||||
thefile->bufpos = 0;
|
||||
}
|
||||
|
||||
blocksize = size > thefile->dataRead - thefile->bufpos ? thefile->dataRead - thefile->bufpos : size;
|
||||
memcpy(pos, thefile->buffer + thefile->bufpos, blocksize);
|
||||
thefile->bufpos += blocksize;
|
||||
pos += blocksize;
|
||||
size -= blocksize;
|
||||
}
|
||||
|
||||
*nbytes = pos - (char *)buf;
|
||||
if (*nbytes) {
|
||||
rv = 0;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_read(apr_file_t *thefile, void *buf, apr_size_t *nbytes)
|
||||
{
|
||||
apr_ssize_t rv;
|
||||
apr_size_t bytes_read;
|
||||
|
||||
if (*nbytes <= 0) {
|
||||
*nbytes = 0;
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
if (thefile->buffered) {
|
||||
file_lock(thefile);
|
||||
rv = file_read_buffered(thefile, buf, nbytes);
|
||||
file_unlock(thefile);
|
||||
return rv;
|
||||
}
|
||||
else {
|
||||
bytes_read = 0;
|
||||
if (thefile->ungetchar != -1) {
|
||||
bytes_read = 1;
|
||||
*(char *)buf = (char)thefile->ungetchar;
|
||||
buf = (char *)buf + 1;
|
||||
(*nbytes)--;
|
||||
thefile->ungetchar = -1;
|
||||
if (*nbytes == 0) {
|
||||
*nbytes = bytes_read;
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
do {
|
||||
rv = read(thefile->filedes, buf, *nbytes);
|
||||
} while (rv == -1 && errno == EINTR);
|
||||
#ifdef USE_WAIT_FOR_IO
|
||||
if (rv == -1 &&
|
||||
(errno == EAGAIN || errno == EWOULDBLOCK) &&
|
||||
thefile->timeout != 0) {
|
||||
apr_status_t arv = apr_wait_for_io_or_timeout(thefile, NULL, 1);
|
||||
if (arv != APR_SUCCESS) {
|
||||
*nbytes = bytes_read;
|
||||
return arv;
|
||||
}
|
||||
else {
|
||||
do {
|
||||
rv = read(thefile->filedes, buf, *nbytes);
|
||||
} while (rv == -1 && errno == EINTR);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
*nbytes = bytes_read;
|
||||
if (rv == 0) {
|
||||
thefile->eof_hit = TRUE;
|
||||
return APR_EOF;
|
||||
}
|
||||
if (rv > 0) {
|
||||
*nbytes += rv;
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
return errno;
|
||||
}
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_write(apr_file_t *thefile, const void *buf, apr_size_t *nbytes)
|
||||
{
|
||||
apr_size_t rv;
|
||||
|
||||
if (thefile->buffered) {
|
||||
char *pos = (char *)buf;
|
||||
int blocksize;
|
||||
int size = *nbytes;
|
||||
|
||||
file_lock(thefile);
|
||||
|
||||
if ( thefile->direction == 0 ) {
|
||||
/* Position file pointer for writing at the offset we are
|
||||
* logically reading from
|
||||
*/
|
||||
apr_int64_t offset = thefile->filePtr - thefile->dataRead + thefile->bufpos;
|
||||
if (offset != thefile->filePtr)
|
||||
lseek(thefile->filedes, offset, SEEK_SET);
|
||||
thefile->bufpos = thefile->dataRead = 0;
|
||||
thefile->direction = 1;
|
||||
}
|
||||
|
||||
rv = 0;
|
||||
while (rv == 0 && size > 0) {
|
||||
if (thefile->bufpos == thefile->bufsize) /* write buffer is full*/
|
||||
rv = apr_file_flush_locked(thefile);
|
||||
|
||||
blocksize = size > thefile->bufsize - thefile->bufpos ?
|
||||
thefile->bufsize - thefile->bufpos : size;
|
||||
memcpy(thefile->buffer + thefile->bufpos, pos, blocksize);
|
||||
thefile->bufpos += blocksize;
|
||||
pos += blocksize;
|
||||
size -= blocksize;
|
||||
}
|
||||
|
||||
file_unlock(thefile);
|
||||
|
||||
return rv;
|
||||
}
|
||||
else {
|
||||
do {
|
||||
rv = write(thefile->filedes, buf, *nbytes);
|
||||
} while (rv == (apr_size_t)-1 && errno == EINTR);
|
||||
#ifdef USE_WAIT_FOR_IO
|
||||
if (rv == (apr_size_t)-1 &&
|
||||
(errno == EAGAIN || errno == EWOULDBLOCK) &&
|
||||
thefile->timeout != 0) {
|
||||
apr_status_t arv = apr_wait_for_io_or_timeout(thefile, NULL, 0);
|
||||
if (arv != APR_SUCCESS) {
|
||||
*nbytes = 0;
|
||||
return arv;
|
||||
}
|
||||
else {
|
||||
do {
|
||||
do {
|
||||
rv = write(thefile->filedes, buf, *nbytes);
|
||||
} while (rv == (apr_size_t)-1 && errno == EINTR);
|
||||
if (rv == (apr_size_t)-1 &&
|
||||
(errno == EAGAIN || errno == EWOULDBLOCK)) {
|
||||
*nbytes /= 2; /* yes, we'll loop if kernel lied
|
||||
* and we can't even write 1 byte
|
||||
*/
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
} while (1);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (rv == (apr_size_t)-1) {
|
||||
(*nbytes) = 0;
|
||||
return errno;
|
||||
}
|
||||
*nbytes = rv;
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_writev(apr_file_t *thefile, const struct iovec *vec,
|
||||
apr_size_t nvec, apr_size_t *nbytes)
|
||||
{
|
||||
#ifdef HAVE_WRITEV
|
||||
apr_status_t rv;
|
||||
apr_ssize_t bytes;
|
||||
|
||||
if (thefile->buffered) {
|
||||
file_lock(thefile);
|
||||
|
||||
rv = apr_file_flush_locked(thefile);
|
||||
if (rv != APR_SUCCESS) {
|
||||
file_unlock(thefile);
|
||||
return rv;
|
||||
}
|
||||
if (thefile->direction == 0) {
|
||||
/* Position file pointer for writing at the offset we are
|
||||
* logically reading from
|
||||
*/
|
||||
apr_int64_t offset = thefile->filePtr - thefile->dataRead +
|
||||
thefile->bufpos;
|
||||
if (offset != thefile->filePtr)
|
||||
lseek(thefile->filedes, offset, SEEK_SET);
|
||||
thefile->bufpos = thefile->dataRead = 0;
|
||||
}
|
||||
|
||||
file_unlock(thefile);
|
||||
}
|
||||
|
||||
if ((bytes = writev(thefile->filedes, vec, nvec)) < 0) {
|
||||
*nbytes = 0;
|
||||
rv = errno;
|
||||
}
|
||||
else {
|
||||
*nbytes = bytes;
|
||||
rv = APR_SUCCESS;
|
||||
}
|
||||
return rv;
|
||||
#else
|
||||
/**
|
||||
* The problem with trying to output the entire iovec is that we cannot
|
||||
* maintain the behaviour that a real writev would have. If we iterate
|
||||
* over the iovec one at a time, we lose the atomic properties of
|
||||
* writev(). The other option is to combine the entire iovec into one
|
||||
* buffer that we could then send in one call to write(). This is not
|
||||
* reasonable since we do not know how much data an iovec could contain.
|
||||
*
|
||||
* The only reasonable option, that maintains the semantics of a real
|
||||
* writev(), is to only write the first iovec. Callers of file_writev()
|
||||
* must deal with partial writes as they normally would. If you want to
|
||||
* ensure an entire iovec is written, use apr_file_writev_full().
|
||||
*/
|
||||
|
||||
*nbytes = vec[0].iov_len;
|
||||
return apr_file_write(thefile, vec[0].iov_base, nbytes);
|
||||
#endif
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_putc(char ch, apr_file_t *thefile)
|
||||
{
|
||||
apr_size_t nbytes = 1;
|
||||
|
||||
return apr_file_write(thefile, &ch, &nbytes);
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_ungetc(char ch, apr_file_t *thefile)
|
||||
{
|
||||
thefile->ungetchar = (unsigned char)ch;
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_getc(char *ch, apr_file_t *thefile)
|
||||
{
|
||||
apr_size_t nbytes = 1;
|
||||
|
||||
return apr_file_read(thefile, ch, &nbytes);
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_puts(const char *str, apr_file_t *thefile)
|
||||
{
|
||||
return apr_file_write_full(thefile, str, strlen(str), NULL);
|
||||
}
|
||||
|
||||
apr_status_t apr_file_flush_locked(apr_file_t *thefile)
|
||||
{
|
||||
apr_status_t rv = APR_SUCCESS;
|
||||
|
||||
if (thefile->direction == 1 && thefile->bufpos) {
|
||||
apr_ssize_t written = 0, ret;
|
||||
|
||||
do {
|
||||
ret = write(thefile->filedes, thefile->buffer + written,
|
||||
thefile->bufpos - written);
|
||||
if (ret > 0)
|
||||
written += ret;
|
||||
} while (written < thefile->bufpos &&
|
||||
(ret > 0 || (ret == -1 && errno == EINTR)));
|
||||
if (ret == -1) {
|
||||
rv = errno;
|
||||
} else {
|
||||
thefile->filePtr += written;
|
||||
thefile->bufpos = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_flush(apr_file_t *thefile)
|
||||
{
|
||||
apr_status_t rv = APR_SUCCESS;
|
||||
|
||||
if (thefile->buffered) {
|
||||
file_lock(thefile);
|
||||
rv = apr_file_flush_locked(thefile);
|
||||
file_unlock(thefile);
|
||||
}
|
||||
/* There isn't anything to do if we aren't buffering the output
|
||||
* so just return success.
|
||||
*/
|
||||
return rv;
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_sync(apr_file_t *thefile)
|
||||
{
|
||||
apr_status_t rv = APR_SUCCESS;
|
||||
|
||||
file_lock(thefile);
|
||||
|
||||
if (thefile->buffered) {
|
||||
rv = apr_file_flush_locked(thefile);
|
||||
|
||||
if (rv != APR_SUCCESS) {
|
||||
file_unlock(thefile);
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
if (fsync(thefile->filedes)) {
|
||||
rv = apr_get_os_error();
|
||||
}
|
||||
|
||||
file_unlock(thefile);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_datasync(apr_file_t *thefile)
|
||||
{
|
||||
apr_status_t rv = APR_SUCCESS;
|
||||
|
||||
file_lock(thefile);
|
||||
|
||||
if (thefile->buffered) {
|
||||
rv = apr_file_flush_locked(thefile);
|
||||
|
||||
if (rv != APR_SUCCESS) {
|
||||
file_unlock(thefile);
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_FDATASYNC
|
||||
if (fdatasync(thefile->filedes)) {
|
||||
#elif defined(F_FULLFSYNC)
|
||||
if (fcntl(thefile->filedes, F_FULLFSYNC)) {
|
||||
#else
|
||||
if (fsync(thefile->filedes)) {
|
||||
#endif
|
||||
rv = apr_get_os_error();
|
||||
}
|
||||
|
||||
file_unlock(thefile);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
APR_DECLARE(apr_status_t) apr_file_gets(char *str, int len, apr_file_t *thefile)
|
||||
{
|
||||
apr_status_t rv = APR_SUCCESS; /* get rid of gcc warning */
|
||||
apr_size_t nbytes;
|
||||
const char *str_start = str;
|
||||
char *final = str + len - 1;
|
||||
|
||||
if (len <= 1) {
|
||||
/* sort of like fgets(), which returns NULL and stores no bytes
|
||||
*/
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
/* If we have an underlying buffer, we can be *much* more efficient
|
||||
* and skip over the apr_file_read calls.
|
||||
*/
|
||||
if (thefile->buffered) {
|
||||
file_lock(thefile);
|
||||
|
||||
if (thefile->direction == 1) {
|
||||
rv = apr_file_flush_locked(thefile);
|
||||
if (rv) {
|
||||
file_unlock(thefile);
|
||||
return rv;
|
||||
}
|
||||
|
||||
thefile->direction = 0;
|
||||
thefile->bufpos = 0;
|
||||
thefile->dataRead = 0;
|
||||
}
|
||||
|
||||
while (str < final) { /* leave room for trailing '\0' */
|
||||
/* Force ungetc leftover to call apr_file_read. */
|
||||
if (thefile->bufpos < thefile->dataRead &&
|
||||
thefile->ungetchar == -1) {
|
||||
*str = thefile->buffer[thefile->bufpos++];
|
||||
}
|
||||
else {
|
||||
nbytes = 1;
|
||||
rv = file_read_buffered(thefile, str, &nbytes);
|
||||
if (rv != APR_SUCCESS) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (*str == '\n') {
|
||||
++str;
|
||||
break;
|
||||
}
|
||||
++str;
|
||||
}
|
||||
file_unlock(thefile);
|
||||
}
|
||||
else {
|
||||
while (str < final) { /* leave room for trailing '\0' */
|
||||
nbytes = 1;
|
||||
rv = apr_file_read(thefile, str, &nbytes);
|
||||
if (rv != APR_SUCCESS) {
|
||||
break;
|
||||
}
|
||||
if (*str == '\n') {
|
||||
++str;
|
||||
break;
|
||||
}
|
||||
++str;
|
||||
}
|
||||
}
|
||||
|
||||
/* We must store a terminating '\0' if we've stored any chars. We can
|
||||
* get away with storing it if we hit an error first.
|
||||
*/
|
||||
*str = '\0';
|
||||
if (str > str_start) {
|
||||
/* we stored chars; don't report EOF or any other errors;
|
||||
* the app will find out about that on the next call
|
||||
*/
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
struct apr_file_printf_data {
|
||||
apr_vformatter_buff_t vbuff;
|
||||
apr_file_t *fptr;
|
||||
char *buf;
|
||||
};
|
||||
|
||||
static int file_printf_flush(apr_vformatter_buff_t *buff)
|
||||
{
|
||||
struct apr_file_printf_data *data = (struct apr_file_printf_data *)buff;
|
||||
|
||||
if (apr_file_write_full(data->fptr, data->buf,
|
||||
data->vbuff.curpos - data->buf, NULL)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
data->vbuff.curpos = data->buf;
|
||||
return 0;
|
||||
}
|
||||
|
||||
APR_DECLARE_NONSTD(int) apr_file_printf(apr_file_t *fptr,
|
||||
const char *format, ...)
|
||||
{
|
||||
struct apr_file_printf_data data;
|
||||
va_list ap;
|
||||
int count;
|
||||
|
||||
/* don't really need a HUGE_STRING_LEN anymore */
|
||||
data.buf = malloc(HUGE_STRING_LEN);
|
||||
if (data.buf == NULL) {
|
||||
return -1;
|
||||
}
|
||||
data.vbuff.curpos = data.buf;
|
||||
data.vbuff.endpos = data.buf + HUGE_STRING_LEN;
|
||||
data.fptr = fptr;
|
||||
va_start(ap, format);
|
||||
count = apr_vformatter(file_printf_flush,
|
||||
(apr_vformatter_buff_t *)&data, format, ap);
|
||||
/* apr_vformatter does not call flush for the last bits */
|
||||
if (count >= 0) file_printf_flush((apr_vformatter_buff_t *)&data);
|
||||
|
||||
va_end(ap);
|
||||
|
||||
free(data.buf);
|
||||
|
||||
return count;
|
||||
}
|
||||
Reference in New Issue
Block a user