Added buffering API.

This commit is contained in:
Ryan C. Gordon 2002-12-01 11:21:27 +00:00
parent c1cf146a75
commit 3ad51e49e4
4 changed files with 561 additions and 29 deletions

181
physfs.c
View File

@ -1227,12 +1227,22 @@ int __PHYSFS_verifySecurity(DirHandle *h, const char *fname)
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 @@ static PHYSFS_file *doOpenWrite(const char *fname, int appending)
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 @@ PHYSFS_file *PHYSFS_openRead(const char *fname)
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);
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 @@ static int closeHandleInOpenList(FileHandleList **list, PHYSFS_file *handle)
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 @@ int PHYSFS_close(PHYSFS_file *handle)
} /* 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 @@ PHYSFS_sint64 PHYSFS_write(PHYSFS_file *handle, const void *buffer,
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_sint64 PHYSFS_fileLength(PHYSFS_file *handle)
} /* 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,

110
physfs.h
View File

@ -258,6 +258,8 @@ PHYSFS_COMPILE_TIME_ASSERT(sint64, sizeof(PHYSFS_sint64) == 8);
* \sa PHYSFS_seek
* \sa PHYSFS_tell
* \sa PHYSFS_eof
* \sa PHYSFS_setBuffer
* \sa PHYSFS_flush
*/
typedef struct
{
@ -289,6 +291,7 @@ typedef struct
const char *url; /**< URL related to this archive */
} PHYSFS_ArchiveInfo;
/**
* \struct PHYSFS_Version
* \brief Information the version of PhysicsFS in use.
@ -315,6 +318,9 @@ typedef struct
#define PHYSFS_VER_PATCH 7
#endif /* DOXYGEN_SHOULD_IGNORE_THIS */
/* PhysicsFS state stuff ... */
/**
* \def PHYSFS_VERSION(x)
* \brief Macro to determine PhysicsFS version program was compiled against.
@ -775,6 +781,8 @@ __EXPORT__ int PHYSFS_setSaneConfig(const char *organization,
int archivesFirst);
/* Directory management stuff ... */
/**
* \fn int PHYSFS_mkdir(const char *dirName)
* \brief Create a directory.
@ -856,7 +864,6 @@ __EXPORT__ int PHYSFS_delete(const char *filename);
__EXPORT__ const char *PHYSFS_getRealDir(const char *filename);
/**
* \fn char **PHYSFS_enumerateFiles(const char *dir)
* \brief Get a file listing of a search path's directory.
@ -956,6 +963,24 @@ __EXPORT__ int PHYSFS_isDirectory(const char *fname);
__EXPORT__ int PHYSFS_isSymbolicLink(const char *fname);
/**
* \fn PHYSFS_sint64 PHYSFS_getLastModTime(const char *filename)
* \brief Get the last modification time of a file.
*
* The modtime is returned as a number of seconds since the epoch
* (Jan 1, 1970). The exact derivation and accuracy of this time depends on
* the particular archiver. If there is no reasonable way to obtain this
* information for a particular archiver, or there was some sort of error,
* this function returns (-1).
*
* \param filename filename to check, in platform-independent notation.
* \return last modified time of the file. -1 if it can't be determined.
*/
__EXPORT__ PHYSFS_sint64 PHYSFS_getLastModTime(const char *filename);
/* i/o stuff... */
/**
* \fn PHYSFS_file *PHYSFS_openWrite(const char *filename)
* \brief Open a file for writing.
@ -1053,22 +1078,6 @@ __EXPORT__ PHYSFS_file *PHYSFS_openRead(const char *filename);
__EXPORT__ int PHYSFS_close(PHYSFS_file *handle);
/**
* \fn PHYSFS_sint64 PHYSFS_getLastModTime(const char *filename)
* \brief Get the last modification time of a file.
*
* The modtime is returned as a number of seconds since the epoch
* (Jan 1, 1970). The exact derivation and accuracy of this time depends on
* the particular archiver. If there is no reasonable way to obtain this
* information for a particular archiver, or there was some sort of error,
* this function returns (-1).
*
* \param filename filename to check, in platform-independent notation.
* \return last modified time of the file. -1 if it can't be determined.
*/
__EXPORT__ PHYSFS_sint64 PHYSFS_getLastModTime(const char *filename);
/**
* \fn PHYSFS_sint64 PHYSFS_read(PHYSFS_file *handle, void *buffer, PHYSFS_uint32 objSize, PHYSFS_uint32 objCount)
* \brief Read data from a PhysicsFS filehandle
@ -1108,6 +1117,9 @@ __EXPORT__ PHYSFS_sint64 PHYSFS_write(PHYSFS_file *handle,
PHYSFS_uint32 objSize,
PHYSFS_uint32 objCount);
/* File position stuff... */
/**
* \fn int PHYSFS_eof(PHYSFS_file *handle)
* \brief Check for end-of-file state on a PhysicsFS filehandle.
@ -1172,6 +1184,70 @@ __EXPORT__ int PHYSFS_seek(PHYSFS_file *handle, PHYSFS_uint64 pos);
__EXPORT__ PHYSFS_sint64 PHYSFS_fileLength(PHYSFS_file *handle);
/* Buffering stuff... */
/**
* \fn int PHYSFS_setBuffer(PHYSFS_file *handle, PHYSFS_uint64 bufsize)
* \brief Set up buffering for a PhysicsFS file handle.
*
* Define an i/o buffer for a file handle. A memory block of (bufsize) bytes
* will be allocated and associated with (handle).
*
* For files opened for reading, up to (bufsize) bytes are read from (handle)
* and stored in the internal buffer. Calls to PHYSFS_read() will pull
* from this buffer until it is empty, and then refill it for more reading.
* Note that compressed files, like ZIP archives, will decompress while
* buffering, so this can be handy for offsetting CPU-intensive operations.
* The buffer isn't filled until you do your next read.
*
* For files opened for writing, data will be buffered to memory until the
* buffer is full or the buffer is flushed. Closing a handle implicitly
* causes a flush...check your return values!
*
* Seeking, etc transparently accounts for buffering.
*
* You can resize an existing buffer by calling this function more than once
* on the same file. Setting the buffer size to zero will free an existing
* buffer.
*
* PhysicsFS file handles are unbuffered by default.
*
* Please check the return value of this function! Failures can include
* not being able to seek backwards in a read-only file when removing the
* buffer, not being able to allocate the buffer, and not being able to
* flush the buffer to disk, among other unexpected problems.
*
* \param handle handle returned from PHYSFS_open*().
* \param bufsize size, in bytes, of buffer to allocate.
* \return nonzero if successful, zero on error.
*
* \sa PHYSFS_flush
* \sa PHYSFS_read
* \sa PHYSFS_write
* \sa PHYSFS_close
*/
__EXPORT__ int PHYSFS_setBuffer(PHYSFS_file *handle, PHYSFS_uint64 bufsize);
/**
* \fn int PHYSFS_flush(PHYSFS_file *handle, PHYSFS_uint64 bufsize)
* \brief Flush a buffered PhysicsFS file handle.
*
* For buffered files opened for writing, this will put the current contents
* of the buffer to disk and flag the buffer as empty if possible.
*
* For buffered files opened for reading or unbuffered files, this is a safe
* no-op, and will report success.
*
* \param handle handle returned from PHYSFS_open*().
* \return nonzero if successful, zero on error.
*
* \sa PHYSFS_setBuffer
* \sa PHYSFS_close
*/
__EXPORT__ int PHYSFS_flush(PHYSFS_file *handle);
/* Byteorder stuff... */
/**

View File

@ -724,6 +724,31 @@ typedef struct __PHYSFS_FILEHANDLE__
*/
void *opaque;
/*
* Non-zero if file opened for reading, zero if write/append.
*/
PHYSFS_uint8 forReading;
/*
* This is the buffer, if one is set (NULL otherwise). Don't touch.
*/
PHYSFS_uint8 *buffer;
/*
* This is the buffer size, if one is set (0 otherwise). Don't touch.
*/
PHYSFS_uint64 bufsize;
/*
* This is the buffer fill size. Don't touch.
*/
PHYSFS_uint64 buffill;
/*
* This is the buffer position. Don't touch.
*/
PHYSFS_uint64 bufpos;
/*
* This should be the DirHandle that created this FileHandle.
*/

View File

@ -34,6 +34,7 @@
#define TEST_VERSION_PATCH 7
static FILE *history_file = NULL;
static PHYSFS_uint32 do_buffer_size = 0;
static void output_versions(void)
{
@ -288,6 +289,230 @@ static int cmd_permitsyms(char *args)
} /* cmd_permitsyms */
static int cmd_setbuffer(char *args)
{
if (*args == '\"')
{
args++;
args[strlen(args) - 1] = '\0';
} /* if */
do_buffer_size = atoi(args);
if (do_buffer_size)
{
printf("Further tests will set a (%lu) size buffer.\n",
(unsigned long) do_buffer_size);
} /* if */
else
{
printf("Further tests will NOT use a buffer.\n");
} /* else */
return(1);
} /* cmd_setbuffer */
static int cmd_stressbuffer(char *args)
{
int num;
if (*args == '\"')
{
args++;
args[strlen(args) - 1] = '\0';
} /* if */
num = atoi(args);
if (num < 0)
printf("buffer must be greater than or equal to zero.\n");
else
{
PHYSFS_file *f;
int rndnum;
printf("Stress testing with (%d) byte buffer...\n", num);
f = PHYSFS_openWrite("test.txt");
if (f == NULL)
printf("Couldn't open test.txt for writing: %s.\n", PHYSFS_getLastError());
else
{
int i, j;
char buf[37];
char buf2[37];
if (!PHYSFS_setBuffer(f, num))
{
printf("PHYSFS_setBuffer() failed: %s.\n", PHYSFS_getLastError());
PHYSFS_close(f);
PHYSFS_delete("test.txt");
return(1);
} /* if */
strcpy(buf, "abcdefghijklmnopqrstuvwxyz0123456789");
srand(time(NULL));
for (i = 0; i < 10; i++)
{
for (j = 0; j < 10000; j++)
{
int right = 1 + (int) (35.0 * rand() / (RAND_MAX + 1.0));
int left = 36 - right;
if (PHYSFS_write(f, buf, left, 1) != 1)
{
printf("PHYSFS_write() failed: %s.\n", PHYSFS_getLastError());
PHYSFS_close(f);
return(1);
} /* if */
rndnum = 1 + (int) (1000.0 * rand() / (RAND_MAX + 1.0));
if (rndnum == 42)
{
if (!PHYSFS_flush(f))
{
printf("PHYSFS_flush() failed: %s.\n", PHYSFS_getLastError());
PHYSFS_close(f);
return(1);
} /* if */
} /* if */
if (PHYSFS_write(f, buf + left, 1, right) != right)
{
printf("PHYSFS_write() failed: %s.\n", PHYSFS_getLastError());
PHYSFS_close(f);
return(1);
} /* if */
rndnum = 1 + (int) (1000.0 * rand() / (RAND_MAX + 1.0));
if (rndnum == 42)
{
if (!PHYSFS_flush(f))
{
printf("PHYSFS_flush() failed: %s.\n", PHYSFS_getLastError());
PHYSFS_close(f);
return(1);
} /* if */
} /* if */
} /* for */
if (!PHYSFS_flush(f))
{
printf("PHYSFS_flush() failed: %s.\n", PHYSFS_getLastError());
PHYSFS_close(f);
return(1);
} /* if */
} /* for */
if (!PHYSFS_close(f))
{
printf("PHYSFS_close() failed: %s.\n", PHYSFS_getLastError());
return(1); /* oh well. */
} /* if */
printf(" ... test file written ...\n");
f = PHYSFS_openRead("test.txt");
if (f == NULL)
{
printf("Failed to reopen stress file for reading: %s.\n", PHYSFS_getLastError());
return(1);
} /* if */
if (!PHYSFS_setBuffer(f, num))
{
printf("PHYSFS_setBuffer() failed: %s.\n", PHYSFS_getLastError());
PHYSFS_close(f);
return(1);
} /* if */
for (i = 0; i < 10; i++)
{
for (j = 0; j < 10000; j++)
{
int right = 1 + (int) (35.0 * rand() / (RAND_MAX + 1.0));
int left = 36 - right;
if (PHYSFS_read(f, buf2, left, 1) != 1)
{
printf("PHYSFS_read() failed: %s.\n", PHYSFS_getLastError());
PHYSFS_close(f);
return(1);
} /* if */
rndnum = 1 + (int) (1000.0 * rand() / (RAND_MAX + 1.0));
if (rndnum == 42)
{
if (!PHYSFS_flush(f))
{
printf("PHYSFS_flush() failed: %s.\n", PHYSFS_getLastError());
PHYSFS_close(f);
return(1);
} /* if */
} /* if */
if (PHYSFS_read(f, buf2 + left, 1, right) != right)
{
printf("PHYSFS_read() failed: %s.\n", PHYSFS_getLastError());
PHYSFS_close(f);
return(1);
} /* if */
rndnum = 1 + (int) (1000.0 * rand() / (RAND_MAX + 1.0));
if (rndnum == 42)
{
if (!PHYSFS_flush(f))
{
printf("PHYSFS_flush() failed: %s.\n", PHYSFS_getLastError());
PHYSFS_close(f);
return(1);
} /* if */
} /* if */
if (memcmp(buf, buf2, 36) != 0)
{
printf("readback is mismatched on iterations (%d, %d).\n", i, j);
printf("wanted: [");
for (i = 0; i < 36; i++)
printf("%c", buf[i]);
printf("]\n");
printf(" got: [");
for (i = 0; i < 36; i++)
printf("%c", buf2[i]);
printf("]\n");
PHYSFS_close(f);
return(1);
} /* if */
} /* for */
if (!PHYSFS_flush(f))
{
printf("PHYSFS_flush() failed: %s.\n", PHYSFS_getLastError());
PHYSFS_close(f);
return(1);
} /* if */
} /* for */
printf(" ... test file read ...\n");
if (!PHYSFS_eof(f))
printf("PHYSFS_eof() returned true! That's wrong.\n");
if (!PHYSFS_close(f))
{
printf("PHYSFS_close() failed: %s.\n", PHYSFS_getLastError());
return(1); /* oh well. */
} /* if */
PHYSFS_delete("test.txt");
printf("stress test completed successfully.\n");
} /* else */
} /* else */
return(1);
} /* cmd_stressbuffer */
static int cmd_setsaneconfig(char *args)
{
char *org;
@ -433,6 +658,17 @@ static int cmd_cat(char *args)
printf("failed to open. Reason: [%s].\n", PHYSFS_getLastError());
else
{
if (do_buffer_size)
{
if (!PHYSFS_setBuffer(f, do_buffer_size))
{
printf("failed to set file buffer. Reason: [%s].\n",
PHYSFS_getLastError());
PHYSFS_close(f);
return(1);
} /* if */
} /* if */
while (1)
{
char buffer[128];
@ -506,8 +742,22 @@ static int cmd_append(char *args)
printf("failed to open. Reason: [%s].\n", PHYSFS_getLastError());
else
{
size_t bw = strlen(WRITESTR);
PHYSFS_sint64 rc = PHYSFS_write(f, WRITESTR, 1, bw);
size_t bw;
PHYSFS_sint64 rc;
if (do_buffer_size)
{
if (!PHYSFS_setBuffer(f, do_buffer_size))
{
printf("failed to set file buffer. Reason: [%s].\n",
PHYSFS_getLastError());
PHYSFS_close(f);
return(1);
} /* if */
} /* if */
bw = strlen(WRITESTR);
rc = PHYSFS_write(f, WRITESTR, 1, bw);
if (rc != bw)
{
printf("Wrote (%d) of (%d) bytes. Reason: [%s].\n",
@ -540,8 +790,22 @@ static int cmd_write(char *args)
printf("failed to open. Reason: [%s].\n", PHYSFS_getLastError());
else
{
size_t bw = strlen(WRITESTR);
PHYSFS_sint64 rc = PHYSFS_write(f, WRITESTR, 1, bw);
size_t bw;
PHYSFS_sint64 rc;
if (do_buffer_size)
{
if (!PHYSFS_setBuffer(f, do_buffer_size))
{
printf("failed to set file buffer. Reason: [%s].\n",
PHYSFS_getLastError());
PHYSFS_close(f);
return(1);
} /* if */
} /* if */
bw = strlen(WRITESTR);
rc = PHYSFS_write(f, WRITESTR, 1, bw);
if (rc != bw)
{
printf("Wrote (%d) of (%d) bytes. Reason: [%s].\n",
@ -648,6 +912,8 @@ static const command_info commands[] =
{ "append", cmd_append, 1, "<fileToAppend>" },
{ "write", cmd_write, 1, "<fileToCreateOrTrash>" },
{ "getlastmodtime", cmd_getlastmodtime, 1, "<fileToExamine>" },
{ "setbuffer", cmd_setbuffer, 1, "<bufferSize>" },
{ "stressbuffer", cmd_stressbuffer, 1, "<bufferSize>" },
{ NULL, NULL, -1, NULL }
};