blob: d567ef3a5c06d5cca63f20ef4e998bf0f91929f2 [file] [log] [blame]
/* 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.
*/
#define INCL_DOS
#define INCL_DOSERRORS
#include "apr_arch_file_io.h"
#include "apr_file_io.h"
#include "apr_lib.h"
#include "apr_strings.h"
#include <malloc.h>
static void file_lock(apr_file_t *thefile)
{
if (thefile->mutex && thefile->buffered) {
apr_thread_mutex_lock(thefile->mutex);
}
}
static void file_unlock(apr_file_t *thefile)
{
if (thefile->mutex && thefile->buffered) {
apr_thread_mutex_unlock(thefile->mutex);
}
}
APR_DECLARE(apr_status_t) apr_file_read(apr_file_t *thefile, void *buf, apr_size_t *nbytes)
{
ULONG rc = 0;
ULONG bytesread;
apr_size_t req_nbytes = *nbytes;
if (!thefile->isopen) {
*nbytes = 0;
return APR_EBADF;
}
if (thefile->ungetchar != -1 && req_nbytes >= 1) {
*(char *)buf = (char)thefile->ungetchar;
thefile->ungetchar = -1;
(*nbytes) = 1;
return APR_SUCCESS;
}
if (thefile->buffered) {
char *pos = (char *)buf;
ULONG blocksize;
ULONG size = *nbytes;
file_lock(thefile);
if (thefile->direction == 1) {
int rv = apr_file_flush(thefile);
if (rv != APR_SUCCESS) {
file_unlock(thefile);
return rv;
}
thefile->bufpos = 0;
thefile->direction = 0;
thefile->dataRead = 0;
}
while (rc == 0 && size > 0) {
if (thefile->bufpos >= thefile->dataRead) {
ULONG bytesread;
rc = DosRead(thefile->filedes, thefile->buffer,
thefile->bufsize, &bytesread);
if (bytesread == 0) {
if (rc == 0)
thefile->eof_hit = TRUE;
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 = rc == 0 ? pos - (char *)buf : 0;
file_unlock(thefile);
if (*nbytes == 0 && rc == 0 && thefile->eof_hit) {
return APR_EOF;
}
return APR_FROM_OS_ERROR(rc);
} else {
if (thefile->pipe)
DosResetEventSem(thefile->pipeSem, &rc);
rc = DosRead(thefile->filedes, buf, *nbytes, &bytesread);
if (rc == ERROR_NO_DATA && thefile->timeout != 0) {
int rcwait = DosWaitEventSem(thefile->pipeSem, thefile->timeout >= 0 ? thefile->timeout / 1000 : SEM_INDEFINITE_WAIT);
if (rcwait == 0) {
rc = DosRead(thefile->filedes, buf, *nbytes, &bytesread);
}
else if (rcwait == ERROR_TIMEOUT) {
*nbytes = 0;
return APR_TIMEUP;
}
}
if (rc) {
*nbytes = 0;
return APR_FROM_OS_ERROR(rc);
}
*nbytes = bytesread;
if (bytesread == 0 && req_nbytes > 0) {
thefile->eof_hit = TRUE;
return APR_EOF;
}
return APR_SUCCESS;
}
}
APR_DECLARE(apr_status_t) apr_file_write(apr_file_t *thefile, const void *buf, apr_size_t *nbytes)
{
ULONG rc = 0;
ULONG byteswritten;
if (!thefile->isopen) {
*nbytes = 0;
return APR_EBADF;
}
if (thefile->buffered) {
char *pos = (char *)buf;
int blocksize;
int size = *nbytes;
apr_status_t rv = APR_SUCCESS;
file_lock(thefile);
if ( thefile->direction == 0 ) {
/* Position file pointer for writing at the offset we are logically reading from */
ULONG offset = thefile->filePtr - thefile->dataRead + thefile->bufpos;
if (offset != thefile->filePtr)
DosSetFilePtr(thefile->filedes, offset, FILE_BEGIN, &thefile->filePtr );
thefile->bufpos = thefile->dataRead = 0;
thefile->direction = 1;
}
while (rv == APR_SUCCESS && size > 0) {
if (thefile->bufpos == thefile->bufsize) {
/* write buffer is full */
rv = apr_file_flush(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 {
if (thefile->pipe) {
DosResetEventSem(thefile->pipeSem, &rc);
}
if (thefile->flags & APR_FOPEN_APPEND) {
FILELOCK all = { 0, 0x7fffffff };
ULONG newpos;
rc = DosSetFileLocks(thefile->filedes, NULL, &all, -1, 0);
if (rc == 0) {
rc = DosSetFilePtr(thefile->filedes, 0, FILE_END, &newpos);
if (rc == 0) {
rc = DosWrite(thefile->filedes, buf, *nbytes, &byteswritten);
}
DosSetFileLocks(thefile->filedes, &all, NULL, -1, 0);
}
} else {
rc = DosWrite(thefile->filedes, buf, *nbytes, &byteswritten);
if (thefile->pipe && rc == 0 && *nbytes > 0 && byteswritten == 0) {
/* Pipe is full, wait or timeout */
int rcwait = DosWaitEventSem(thefile->pipeSem, thefile->timeout >= 0 ? thefile->timeout / 1000 : SEM_INDEFINITE_WAIT);
if (rcwait == 0) {
rc = DosWrite(thefile->filedes, buf, *nbytes, &byteswritten);
}
else if (rcwait == ERROR_TIMEOUT) {
return APR_TIMEUP;
}
else {
rc = rcwait;
}
}
}
if (rc) {
*nbytes = 0;
return APR_FROM_OS_ERROR(rc);
}
*nbytes = byteswritten;
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)
{
int c;
apr_status_t rv = APR_SUCCESS;
apr_size_t written = 0;
for (c = 0; c < nvec && rv == APR_SUCCESS; c++) {
apr_size_t nbytes = vec[c].iov_len;
rv = apr_file_write(thefile, vec[c].iov_base, &nbytes);
written += nbytes;
}
*nbytes = written;
return rv;
}
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)
{
ULONG rc;
apr_size_t bytesread;
if (!thefile->isopen) {
return APR_EBADF;
}
bytesread = 1;
rc = apr_file_read(thefile, ch, &bytesread);
if (rc) {
return rc;
}
if (bytesread == 0) {
thefile->eof_hit = TRUE;
return APR_EOF;
}
return APR_SUCCESS;
}
APR_DECLARE(apr_status_t) apr_file_puts(const char *str, apr_file_t *thefile)
{
apr_size_t len;
len = strlen(str);
return apr_file_write(thefile, str, &len);
}
APR_DECLARE(apr_status_t) apr_file_flush(apr_file_t *thefile)
{
if (thefile->buffered) {
ULONG written = 0;
int rc = 0;
if (thefile->direction == 1 && thefile->bufpos) {
file_lock(thefile);
rc = DosWrite(thefile->filedes, thefile->buffer, thefile->bufpos, &written);
thefile->filePtr += written;
if (rc == 0)
thefile->bufpos = 0;
file_unlock(thefile);
}
return APR_FROM_OS_ERROR(rc);
} else {
/* There isn't anything to do if we aren't buffering the output
* so just return success.
*/
return APR_SUCCESS;
}
}
APR_DECLARE(apr_status_t) apr_file_sync(apr_file_t *thefile)
{
apr_status_t rv;
int rc;
rv = apr_file_flush(thefile);
if (rv != APR_SUCCESS) {
return rv;
}
rc = DosResetBuffer(thefile->filedes);
return APR_FROM_OS_ERROR(rc);
}
APR_DECLARE(apr_status_t) apr_file_datasync(apr_file_t *thefile)
{
return apr_file_sync(thefile);
}
APR_DECLARE(apr_status_t) apr_file_gets(char *str, int len, apr_file_t *thefile)
{
apr_size_t readlen;
apr_status_t rv = APR_SUCCESS;
int i;
for (i = 0; i < len-1; i++) {
readlen = 1;
rv = apr_file_read(thefile, str+i, &readlen);
if (rv != APR_SUCCESS) {
break;
}
if (readlen != 1) {
rv = APR_EOF;
break;
}
if (str[i] == '\n') {
i++;
break;
}
}
str[i] = 0;
if (i > 0) {
/* 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;
}
apr_status_t apr_file_check_read(apr_file_t *fd)
{
int rc;
if (!fd->pipe)
return APR_SUCCESS; /* Not a pipe, assume no waiting */
rc = DosWaitEventSem(fd->pipeSem, SEM_IMMEDIATE_RETURN);
if (rc == ERROR_TIMEOUT)
return APR_TIMEUP;
return APR_FROM_OS_ERROR(rc);
}
APR_DECLARE(apr_status_t) apr_file_pipe_wait(apr_file_t *pipe, apr_wait_type_t direction)
{
int rc;
if (!pipe->pipe) {
/* No support for waiting on a regular file */
return APR_ENOTIMPL;
}
if (((pipe->flags & APR_FOPEN_READ) > 0) != (direction == APR_WAIT_READ)) {
/* Attempt to wait for read from the write end of the pipe or vica versa */
return APR_EINVAL;
}
rc = DosWaitEventSem(pipe->pipeSem, pipe->timeout >= 0 ? pipe->timeout / 1000 : SEM_INDEFINITE_WAIT);
if (rc == ERROR_TIMEOUT) {
return APR_TIMEUP;
}
return APR_FROM_OS_ERROR(rc);
}
APR_DECLARE(apr_status_t) apr_file_rotating_check(apr_file_t *thefile)
{
return APR_ENOTIMPL;
}
APR_DECLARE(apr_status_t) apr_file_rotating_manual_check(apr_file_t *thefile, apr_time_t n)
{
return APR_ENOTIMPL;
}