--- a/physfs.c Sun Dec 01 11:17:56 2002 +0000
+++ b/physfs.c Sun Dec 01 11:21:27 2002 +0000
@@ -1227,12 +1227,22 @@
if (h->funcs->isSymLink(h, str, &retval))
{
__PHYSFS_setError(ERR_SYMLINK_DISALLOWED);
- retval = 0;
+ free(str);
+ return(0); /* insecure. */
} /* if */
- /* break out early if path element is missing or it's a symlink. */
+ /* break out early if path element is missing. */
if (!retval)
+ {
+ /*
+ * We need to clear it if it's the last element of the path,
+ * since this might be a non-existant file we're opening
+ * for writing...
+ */
+ if (end == NULL)
+ retval = 1;
break;
+ } /* if */
} /* if */
if (end == NULL)
@@ -1569,6 +1579,9 @@
free(list);
else
{
+ rc->buffer = NULL; /* just in case. */
+ rc->buffill = rc->bufpos = rc->bufsize = 0; /* just in case. */
+ rc->forReading = 0;
list->handle.opaque = (void *) rc;
list->next = openWriteList;
openWriteList = list;
@@ -1615,13 +1628,17 @@
BAIL_IF_MACRO_MUTEX(rc == NULL, NULL, stateLock, NULL);
list = (FileHandleList *) malloc(sizeof (FileHandleList));
- BAIL_IF_MACRO(!list, ERR_OUT_OF_MEMORY, NULL);
+ BAIL_IF_MACRO_MUTEX(!list, ERR_OUT_OF_MEMORY, stateLock, NULL);
list->handle.opaque = (void *) rc;
list->next = openReadList;
openReadList = list;
retval = &(list->handle);
+ __PHYSFS_platformReleaseMutex(stateLock);
- __PHYSFS_platformReleaseMutex(stateLock);
+ rc->buffer = NULL; /* just in case. */
+ rc->buffill = rc->bufpos = rc->bufsize = 0; /* just in case. */
+ rc->forReading = 1;
+
return(retval);
} /* PHYSFS_openRead */
@@ -1631,16 +1648,22 @@
FileHandle *h = (FileHandle *) handle->opaque;
FileHandleList *prev = NULL;
FileHandleList *i;
- int rc;
+ int rc = 1;
for (i = *list; i != NULL; i = i->next)
{
if (&i->handle == handle) /* handle is in this list? */
{
- rc = h->funcs->fileClose(h);
+ PHYSFS_uint8 *tmp = h->buffer;
+ rc = PHYSFS_flush(handle);
+ if (rc)
+ rc = h->funcs->fileClose(h);
if (!rc)
return(-1);
+ if (tmp != NULL) /* free any associated buffer. */
+ free(tmp);
+
if (prev == NULL)
*list = i->next;
else
@@ -1677,18 +1700,92 @@
} /* PHYSFS_close */
+static PHYSFS_sint64 doBufferedRead(PHYSFS_file *handle, void *buffer,
+ PHYSFS_uint32 objSize,
+ PHYSFS_uint32 objCount)
+{
+ FileHandle *h = (FileHandle *) handle->opaque;
+ PHYSFS_sint64 retval = 0;
+ PHYSFS_uint32 remainder = 0;
+
+ while (objCount > 0)
+ {
+ PHYSFS_uint64 buffered = h->buffill - h->bufpos;
+ PHYSFS_uint64 mustread = (objSize * objCount) - remainder;
+ PHYSFS_uint32 copied;
+
+ if (buffered == 0) /* need to refill buffer? */
+ {
+ PHYSFS_sint64 rc = h->funcs->read(h, h->buffer, 1, h->bufsize);
+ if (rc <= 0)
+ {
+ h->bufpos -= remainder;
+ return(((rc == -1) && (retval == 0)) ? -1 : retval);
+ } /* if */
+
+ buffered = h->buffill = rc;
+ h->bufpos = 0;
+ } /* if */
+
+ if (buffered > mustread)
+ buffered = mustread;
+
+ memcpy(buffer, h->buffer + h->bufpos, (size_t) buffered);
+ buffer = ((PHYSFS_uint8 *) buffer) + buffered;
+ h->bufpos += buffered;
+ buffered += remainder; /* take remainder into account. */
+ copied = (buffered / objSize);
+ remainder = (buffered % objSize);
+ retval += copied;
+ objCount -= copied;
+ } /* while */
+
+ return(retval);
+} /* doBufferedRead */
+
+
PHYSFS_sint64 PHYSFS_read(PHYSFS_file *handle, void *buffer,
PHYSFS_uint32 objSize, PHYSFS_uint32 objCount)
{
FileHandle *h = (FileHandle *) handle->opaque;
+
+ BAIL_IF_MACRO(!h->forReading, ERR_FILE_ALREADY_OPEN_W, -1);
+ if (h->buffer != NULL)
+ return(doBufferedRead(handle, buffer, objSize, objCount));
+
return(h->funcs->read(h, buffer, objSize, objCount));
} /* PHYSFS_read */
+static PHYSFS_sint64 doBufferedWrite(PHYSFS_file *handle, const void *buffer,
+ PHYSFS_uint32 objSize,
+ PHYSFS_uint32 objCount)
+{
+ FileHandle *h = (FileHandle *) handle->opaque;
+
+ /* whole thing fits in the buffer? */
+ if (h->buffill + (objSize * objCount) < h->bufsize)
+ {
+ memcpy(h->buffer + h->buffill, buffer, objSize * objCount);
+ h->buffill += (objSize * objCount);
+ return(objCount);
+ } /* if */
+
+ /* would overflow buffer. Flush and then write the new objects, too. */
+ BAIL_IF_MACRO(!PHYSFS_flush(handle), NULL, -1);
+ return(h->funcs->write(h, buffer, objSize, objCount));
+} /* doBufferedWrite */
+
+
PHYSFS_sint64 PHYSFS_write(PHYSFS_file *handle, const void *buffer,
PHYSFS_uint32 objSize, PHYSFS_uint32 objCount)
{
FileHandle *h = (FileHandle *) handle->opaque;
+
+ BAIL_IF_MACRO(h->forReading, ERR_FILE_ALREADY_OPEN_R, -1);
+ if (h->buffer != NULL)
+ return(doBufferedWrite(handle, buffer, objSize, objCount));
+
return(h->funcs->write(h, buffer, objSize, objCount));
} /* PHYSFS_write */
@@ -1696,20 +1793,29 @@
int PHYSFS_eof(PHYSFS_file *handle)
{
FileHandle *h = (FileHandle *) handle->opaque;
- return(h->funcs->eof(h));
+
+ if (!h->forReading) /* never EOF on files opened for write/append. */
+ return(0);
+
+ /* eof if buffer is empty and archiver says so. */
+ return((h->bufpos == h->buffill) && (h->funcs->eof(h)));
} /* PHYSFS_eof */
PHYSFS_sint64 PHYSFS_tell(PHYSFS_file *handle)
{
FileHandle *h = (FileHandle *) handle->opaque;
- return(h->funcs->tell(h));
+ PHYSFS_sint64 retval = h->forReading ?
+ (h->funcs->tell(h) - h->buffill) + h->bufpos :
+ (h->funcs->tell(h) + h->buffill);
+ return(retval);
} /* PHYSFS_tell */
int PHYSFS_seek(PHYSFS_file *handle, PHYSFS_uint64 pos)
{
FileHandle *h = (FileHandle *) handle->opaque;
+ BAIL_IF_MACRO(!PHYSFS_flush(handle), NULL, 0);
return(h->funcs->seek(h, pos));
} /* PHYSFS_seek */
@@ -1721,6 +1827,65 @@
} /* PHYSFS_filelength */
+int PHYSFS_setBuffer(PHYSFS_file *handle, PHYSFS_uint64 bufsize)
+{
+ FileHandle *h = (FileHandle *) handle->opaque;
+
+ BAIL_IF_MACRO(!PHYSFS_flush(handle), NULL, 0);
+
+ /*
+ * For reads, we need to move the file pointer to where it would be
+ * if we weren't buffering, so that the next read will get the
+ * right chunk of stuff from the file. PHYSFS_flush() handles writes.
+ */
+ if ((h->forReading) && (h->buffill != h->bufpos))
+ {
+ PHYSFS_uint64 pos;
+ PHYSFS_sint64 curpos = h->funcs->tell(h);
+ BAIL_IF_MACRO(curpos == -1, NULL, 0);
+ pos = ((curpos - h->buffill) + h->bufpos);
+ BAIL_IF_MACRO(!h->funcs->seek(h, pos), NULL, 0);
+ } /* if */
+
+ if (bufsize == 0) /* delete existing buffer. */
+ {
+ if (h->buffer != NULL)
+ {
+ free(h->buffer);
+ h->buffer = NULL;
+ } /* if */
+ } /* if */
+
+ else
+ {
+ PHYSFS_uint8 *newbuf = realloc(h->buffer, bufsize);
+ BAIL_IF_MACRO(newbuf == NULL, ERR_OUT_OF_MEMORY, 0);
+ h->buffer = newbuf;
+ } /* else */
+
+ h->bufsize = bufsize;
+ h->buffill = h->bufpos = 0;
+ return(1);
+} /* PHYSFS_setBuffer */
+
+
+int PHYSFS_flush(PHYSFS_file *handle)
+{
+ FileHandle *h = (FileHandle *) handle->opaque;
+ PHYSFS_sint64 rc;
+
+ if ((h->forReading) || (h->bufpos == h->buffill))
+ return(1); /* open for read or buffer empty are successful no-ops. */
+
+ /* dump buffer to disk. */
+ rc = h->funcs->write(h, h->buffer + h->bufpos, h->buffill - h->bufpos, 1);
+ BAIL_IF_MACRO(rc <= 0, NULL, 0);
+
+ h->bufpos = h->buffill = 0;
+ return(1);
+} /* PHYSFS_flush */
+
+
LinkedStringList *__PHYSFS_addToLinkedStringList(LinkedStringList *retval,
LinkedStringList **prev,
const char *str,