Example #1
0
APR_DECLARE(apr_status_t) apr_file_buffer_set(apr_file_t *file, 
                                              char * buffer,
                                              apr_size_t bufsize)
{
    apr_status_t rv;

    file_lock(file);

    if(file->buffered) {
        /* Flush the existing buffer */
        rv = apr_file_flush_locked(file);
        if (rv != APR_SUCCESS) {
            file_unlock(file);
            return rv;
        }
    }
        
    file->buffer = buffer;
    file->bufsize = bufsize;
    file->buffered = 1;
    file->bufpos = 0;
    file->direction = 0;
    file->dataRead = 0;
 
    if (file->bufsize == 0) {
            /* Setting the buffer size to zero is equivalent to turning 
             * buffering off. 
             */
            file->buffered = 0;
    }

    file_unlock(file);

    return APR_SUCCESS;
}
Example #2
0
apr_status_t apr_file_trunc(apr_file_t *fp, apr_off_t offset)
{
    if (fp->buffered) {
        int rc = 0;
        file_lock(fp);
        if (fp->direction == 1 && fp->bufpos != 0) {
            apr_off_t len = fp->filePtr + fp->bufpos;
            if (offset < len) {
                /* New file end fall below our write buffer limit.
                 * Figure out if and what needs to be flushed.
                 */
                apr_off_t off = len - offset;
                if (off >= 0 && off <= fp->bufpos)
                    fp->bufpos = fp->bufpos - (size_t)off;
                else
                    fp->bufpos = 0;
            }
            rc = apr_file_flush_locked(fp);
            /* Reset buffer positions for write mode */
            fp->bufpos = fp->direction = fp->dataRead = 0;
        }
        file_unlock(fp);
        if (rc) {
            return rc;
        }
    }
    if (ftruncate(fp->filedes, offset) == -1) {
        return errno;
    }
    return apr_file_seek(fp, APR_SET, &offset);
}
Example #3
0
static apr_status_t setptr(apr_file_t *thefile, apr_off_t pos )
{
    apr_off_t newbufpos;
    apr_status_t rv;

    if (thefile->direction == 1) {
        rv = apr_file_flush_locked(thefile);
        if (rv) {
            return rv;
        }
        thefile->bufpos = thefile->direction = thefile->dataRead = 0;
    }

    newbufpos = pos - (thefile->filePtr - thefile->dataRead);
    if (newbufpos >= 0 && newbufpos <= thefile->dataRead) {
        thefile->bufpos = newbufpos;
        rv = APR_SUCCESS;
    }
    else {
        if (lseek(thefile->filedes, pos, SEEK_SET) != -1) {
            thefile->bufpos = thefile->dataRead = 0;
            thefile->filePtr = pos;
            rv = APR_SUCCESS;
        }
        else {
            rv = errno;
        }
    }

    return rv;
}
Example #4
0
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;
    int 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 behavoir that a real writev would have.  If we iterate
     * over the iovec one at a time, we loose 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
}
Example #5
0
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, APR_FILE_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;
}
Example #6
0
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);
    }
Example #7
0
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; 
}
Example #8
0
apr_status_t apr_file_info_get_locked(apr_finfo_t *finfo, apr_int32_t wanted,
                                      apr_file_t *thefile)
{
    struct_stat info;

    if (thefile->buffered) {
        apr_status_t rv = apr_file_flush_locked(thefile);
        if (rv != APR_SUCCESS)
            return rv;
    }

    if (fstat(thefile->filedes, &info) == 0) {
        finfo->pool = thefile->pool;
        finfo->fname = thefile->fname;
        fill_out_finfo(finfo, &info, wanted);
        return (wanted & ~finfo->valid) ? APR_INCOMPLETE : APR_SUCCESS;
    }
    else {
        return errno;
    }
}
Example #9
0
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 == APR_FILE_BUFSIZE)   /* write buffer is full*/
                rv = apr_file_flush_locked(thefile);

            blocksize = size > APR_FILE_BUFSIZE - thefile->bufpos ? 
                        APR_FILE_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;
    }
}