[physfs] [PATCH][RFC] openReadWrite implementation

Matheus Izvekov mizvekov at gmail.com
Fri May 1 03:08:33 EDT 2009


This implements openReadWrite API for physfs.
It opens a file for both reading and writing, creating a 0 byte file if it
doesn't exists. If the file exists outside the write dir, but not inside,
a 0 byte file is created.
This is the simplest possible implementation of this feature.
An alternative semantic is possible:
	If the file exists outside the writing dir but not inside,
	we copy it to the writing dir and start from there.
Also, for now, this patch only changes platform_posix.c to implement it.
It will fail to compile on other platforms.
If and when this patch is accepted, I will add others. Ofcourse help will
be appreciated.
---

diff -r 4413637bdcf2 src/archiver_dir.c
--- a/src/archiver_dir.c	Mon Apr 20 23:48:16 2009 -0400
+++ b/src/archiver_dir.c	Fri May 01 03:36:47 2009 -0300
@@ -201,6 +201,12 @@
 } /* DIR_openRead */
 
 
+static fvoid *DIR_openReadWrite(dvoid *opaque, const char *filename)
+{
+    return(doOpen(opaque, filename, __PHYSFS_platformOpenReadWrite, NULL));
+} /* DIR_openReadWrite */
+
+
 static fvoid *DIR_openWrite(dvoid *opaque, const char *filename)
 {
     return(doOpen(opaque, filename, __PHYSFS_platformOpenWrite, NULL));
@@ -265,6 +271,7 @@
     DIR_isSymLink,          /* isSymLink() method      */
     DIR_getLastModTime,     /* getLastModTime() method */
     DIR_openRead,           /* openRead() method       */
+    DIR_openReadWrite,      /* openReadWrite() method  */
     DIR_openWrite,          /* openWrite() method      */
     DIR_openAppend,         /* openAppend() method     */
     DIR_remove,             /* remove() method         */
diff -r 4413637bdcf2 src/archiver_grp.c
--- a/src/archiver_grp.c	Mon Apr 20 23:48:16 2009 -0400
+++ b/src/archiver_grp.c	Fri May 01 03:36:47 2009 -0300
@@ -411,6 +411,12 @@
 } /* GRP_openRead */
 
 
+static fvoid *GRP_openReadWrite(dvoid *opaque, const char *name)
+{
+    BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
+} /* GRP_openReadWrite */
+
+
 static fvoid *GRP_openWrite(dvoid *opaque, const char *name)
 {
     BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
@@ -455,6 +461,7 @@
     GRP_isSymLink,          /* isSymLink() method      */
     GRP_getLastModTime,     /* getLastModTime() method */
     GRP_openRead,           /* openRead() method       */
+    GRP_openReadWrite,      /* openReadWrite() method  */
     GRP_openWrite,          /* openWrite() method      */
     GRP_openAppend,         /* openAppend() method     */
     GRP_remove,             /* remove() method         */
diff -r 4413637bdcf2 src/archiver_hog.c
--- a/src/archiver_hog.c	Mon Apr 20 23:48:16 2009 -0400
+++ b/src/archiver_hog.c	Fri May 01 03:36:47 2009 -0300
@@ -450,6 +450,12 @@
 } /* HOG_openRead */
 
 
+static fvoid *HOG_openReadWrite(dvoid *opaque, const char *name)
+{
+    BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
+} /* HOG_openReadWrite */
+
+
 static fvoid *HOG_openWrite(dvoid *opaque, const char *name)
 {
     BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
@@ -494,6 +500,7 @@
     HOG_isSymLink,          /* isSymLink() method      */
     HOG_getLastModTime,     /* getLastModTime() method */
     HOG_openRead,           /* openRead() method       */
+    HOG_openReadWrite,      /* openReadWrite() method  */
     HOG_openWrite,          /* openWrite() method      */
     HOG_openAppend,         /* openAppend() method     */
     HOG_remove,             /* remove() method         */
diff -r 4413637bdcf2 src/archiver_lzma.c
--- a/src/archiver_lzma.c	Mon Apr 20 23:48:16 2009 -0400
+++ b/src/archiver_lzma.c	Fri May 01 03:36:47 2009 -0300
@@ -655,6 +655,12 @@
 } /* LZMA_openRead */
 
 
+static fvoid *LZMA_openReadWrite(dvoid *opaque, const char *filename)
+{
+    BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
+} /* LZMA_openReadWrite */
+
+
 static fvoid *LZMA_openWrite(dvoid *opaque, const char *filename)
 {
     BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
@@ -715,6 +721,7 @@
     LZMA_isSymLink,          /* isSymLink() method      */
     LZMA_getLastModTime,     /* getLastModTime() method */
     LZMA_openRead,           /* openRead() method       */
+    LZMA_openReadWrite,      /* openReadWrite() method  */
     LZMA_openWrite,          /* openWrite() method      */
     LZMA_openAppend,         /* openAppend() method     */
     LZMA_remove,             /* remove() method         */
diff -r 4413637bdcf2 src/archiver_mvl.c
--- a/src/archiver_mvl.c	Mon Apr 20 23:48:16 2009 -0400
+++ b/src/archiver_mvl.c	Fri May 01 03:36:47 2009 -0300
@@ -407,6 +407,12 @@
 } /* MVL_openRead */
 
 
+static fvoid *MVL_openReadWrite(dvoid *opaque, const char *name)
+{
+    BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
+} /* MVL_openReadWrite */
+
+
 static fvoid *MVL_openWrite(dvoid *opaque, const char *name)
 {
     BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
@@ -451,6 +457,7 @@
     MVL_isSymLink,          /* isSymLink() method      */
     MVL_getLastModTime,     /* getLastModTime() method */
     MVL_openRead,           /* openRead() method       */
+    MVL_openReadWrite,      /* openReadWrite() method  */
     MVL_openWrite,          /* openWrite() method      */
     MVL_openAppend,         /* openAppend() method     */
     MVL_remove,             /* remove() method         */
diff -r 4413637bdcf2 src/archiver_qpak.c
--- a/src/archiver_qpak.c	Mon Apr 20 23:48:16 2009 -0400
+++ b/src/archiver_qpak.c	Fri May 01 03:36:47 2009 -0300
@@ -566,6 +566,12 @@
 } /* QPAK_openRead */
 
 
+static fvoid *QPAK_openReadWrite(dvoid *opaque, const char *name)
+{
+    BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
+} /* QPAK_openReadWrite */
+
+
 static fvoid *QPAK_openWrite(dvoid *opaque, const char *name)
 {
     BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
@@ -610,6 +616,7 @@
     QPAK_isSymLink,          /* isSymLink() method      */
     QPAK_getLastModTime,     /* getLastModTime() method */
     QPAK_openRead,           /* openRead() method       */
+    QPAK_openReadWrite,      /* openReadWrite() method  */
     QPAK_openWrite,          /* openWrite() method      */
     QPAK_openAppend,         /* openAppend() method     */
     QPAK_remove,             /* remove() method         */
diff -r 4413637bdcf2 src/archiver_wad.c
--- a/src/archiver_wad.c	Mon Apr 20 23:48:16 2009 -0400
+++ b/src/archiver_wad.c	Fri May 01 03:36:47 2009 -0300
@@ -470,6 +470,12 @@
 } /* WAD_openRead */
 
 
+static fvoid *WAD_openReadWrite(dvoid *opaque, const char *name)
+{
+    BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
+} /* WAD_openReadWrite */
+
+
 static fvoid *WAD_openWrite(dvoid *opaque, const char *name)
 {
     BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
@@ -514,6 +520,7 @@
     WAD_isSymLink,          /* isSymLink() method      */
     WAD_getLastModTime,     /* getLastModTime() method */
     WAD_openRead,           /* openRead() method       */
+    WAD_openReadWrite,      /* openReadWrite() method  */
     WAD_openWrite,          /* openWrite() method      */
     WAD_openAppend,         /* openAppend() method     */
     WAD_remove,             /* remove() method         */
diff -r 4413637bdcf2 src/archiver_zip.c
--- a/src/archiver_zip.c	Mon Apr 20 23:48:16 2009 -0400
+++ b/src/archiver_zip.c	Fri May 01 03:36:47 2009 -0300
@@ -1376,6 +1376,12 @@
 } /* ZIP_openRead */
 
 
+static fvoid *ZIP_openReadWrite(dvoid *opaque, const char *filename)
+{
+    BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
+} /* ZIP_openReadWrite */
+
+
 static fvoid *ZIP_openWrite(dvoid *opaque, const char *filename)
 {
     BAIL_MACRO(ERR_NOT_SUPPORTED, NULL);
@@ -1429,6 +1435,7 @@
     ZIP_isSymLink,          /* isSymLink() method      */
     ZIP_getLastModTime,     /* getLastModTime() method */
     ZIP_openRead,           /* openRead() method       */
+    ZIP_openReadWrite,      /* openReadWrite() method  */
     ZIP_openWrite,          /* openWrite() method      */
     ZIP_openAppend,         /* openAppend() method     */
     ZIP_remove,             /* remove() method         */
diff -r 4413637bdcf2 src/physfs.c
--- a/src/physfs.c	Mon Apr 20 23:48:16 2009 -0400
+++ b/src/physfs.c	Fri May 01 03:36:47 2009 -0300
@@ -30,7 +30,8 @@
 typedef struct __PHYSFS_FILEHANDLE__
 {
     void *opaque;  /* Instance data unique to the archiver for this file. */
-    PHYSFS_uint8 forReading; /* Non-zero if reading, zero if write/append */
+    PHYSFS_uint8 forReading; /* Non-zero if reading */
+    PHYSFS_uint8 forWriting; /* Non-zero if writing */
     const DirHandle *dirHandle;  /* Archiver instance that created this */
     const PHYSFS_Archiver *funcs;  /* Ptr to archiver info for this handle. */
     PHYSFS_uint8 *buffer;  /* Buffer, if set (NULL otherwise). Don't touch! */
@@ -1742,7 +1743,7 @@
 } /* PHYSFS_isSymbolicLink */
 
 
-static PHYSFS_File *doOpenWrite(const char *_fname, int appending)
+static PHYSFS_File *doOpenWrite(const char *_fname, int appending, int readwrite)
 {
     FileHandle *fh = NULL;
     size_t len;
@@ -1767,7 +1768,9 @@
         GOTO_IF_MACRO(!verifyPath(h, &fname, 0), NULL, doOpenWriteEnd);
 
         f = h->funcs;
-        if (appending)
+        if (readwrite)
+            opaque = f->openReadWrite(h->opaque, fname);
+        else if (appending)
             opaque = f->openAppend(h->opaque, fname);
         else
             opaque = f->openWrite(h->opaque, fname);
@@ -1784,6 +1787,9 @@
         {
             memset(fh, '\0', sizeof (FileHandle));
             fh->opaque = opaque;
+            if (readwrite)
+                fh->forReading = 1;
+            fh->forWriting = 1;
             fh->dirHandle = h;
             fh->funcs = h->funcs;
             fh->next = openWriteList;
@@ -1799,15 +1805,21 @@
 } /* doOpenWrite */
 
 
+PHYSFS_File *PHYSFS_openReadWrite(const char *filename)
+{
+    return(doOpenWrite(filename, 0, 1));
+} /* PHYSFS_openReadWrite */
+
+
 PHYSFS_File *PHYSFS_openWrite(const char *filename)
 {
-    return(doOpenWrite(filename, 0));
+    return(doOpenWrite(filename, 0, 0));
 } /* PHYSFS_openWrite */
 
 
 PHYSFS_File *PHYSFS_openAppend(const char *filename)
 {
-    return(doOpenWrite(filename, 1));
+    return(doOpenWrite(filename, 1, 0));
 } /* PHYSFS_openAppend */
 
 
@@ -1860,6 +1872,7 @@
         memset(fh, '\0', sizeof (FileHandle));
         fh->opaque = opaque;
         fh->forReading = 1;
+	fh->forWriting = 0;
         fh->dirHandle = i;
         fh->funcs = i->funcs;
         fh->next = openReadList;
@@ -2015,7 +2028,7 @@
 {
     FileHandle *fh = (FileHandle *) handle;
 
-    BAIL_IF_MACRO(fh->forReading, ERR_FILE_ALREADY_OPEN_R, -1);
+    BAIL_IF_MACRO(!fh->forWriting, ERR_FILE_ALREADY_OPEN_R, -1);
     BAIL_IF_MACRO(objSize == 0, NULL, 0);
     BAIL_IF_MACRO(objCount == 0, NULL, 0);
     if (fh->buffer != NULL)
@@ -2029,7 +2042,7 @@
 {
     FileHandle *fh = (FileHandle *) handle;
 
-    if (!fh->forReading)  /* never EOF on files opened for write/append. */
+    if (fh->forWriting)  /* never EOF on files opened for write/append. */
         return(0);
 
     /* eof if buffer is empty and archiver says so. */
@@ -2041,7 +2054,7 @@
 {
     FileHandle *fh = (FileHandle *) handle;
     PHYSFS_sint64 pos = fh->funcs->tell(fh->opaque);
-    PHYSFS_sint64 retval = fh->forReading ?
+    PHYSFS_sint64 retval = (fh->forReading && !fh->forWriting) ?
                             (pos - fh->buffill) + fh->bufpos :
                             (pos + fh->buffill);
     return(retval);
@@ -2053,7 +2066,7 @@
     FileHandle *fh = (FileHandle *) handle;
     BAIL_IF_MACRO(!PHYSFS_flush(handle), NULL, 0);
 
-    if (fh->buffer && fh->forReading)
+    if (fh->buffer && fh->forReading && !fh->forWriting)
     {
         /* avoid throwing away our precious buffer if seeking within it. */
         PHYSFS_sint64 offset = pos - PHYSFS_tell(handle);
@@ -2095,7 +2108,7 @@
      *  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 ((fh->forReading) && (fh->buffill != fh->bufpos))
+    if ((fh->forReading && !fh->forWriting) && (fh->buffill != fh->bufpos))
     {
         PHYSFS_uint64 pos;
         PHYSFS_sint64 curpos = fh->funcs->tell(fh->opaque);
@@ -2132,7 +2145,7 @@
     FileHandle *fh = (FileHandle *) handle;
     PHYSFS_sint64 rc;
 
-    if ((fh->forReading) || (fh->bufpos == fh->buffill))
+    if ((fh->forWriting) || (fh->bufpos == fh->buffill))
         return(1);  /* open for read or buffer empty are successful no-ops. */
 
     /* dump buffer to disk. */
diff -r 4413637bdcf2 src/physfs.h
--- a/src/physfs.h	Mon Apr 20 23:48:16 2009 -0400
+++ b/src/physfs.h	Fri May 01 03:36:47 2009 -0300
@@ -1110,6 +1110,7 @@
  *           of the error can be gleaned from PHYSFS_getLastError().
  *
  * \sa PHYSFS_openRead
+ * \sa PHYSFS_openReadWrite
  * \sa PHYSFS_openAppend
  * \sa PHYSFS_write
  * \sa PHYSFS_close
@@ -1136,6 +1137,7 @@
  *           of the error can be gleaned from PHYSFS_getLastError().
  *
  * \sa PHYSFS_openRead
+ * \sa PHYSFS_openReadWrite
  * \sa PHYSFS_openWrite
  * \sa PHYSFS_write
  * \sa PHYSFS_close
@@ -1160,6 +1162,7 @@
  *  \return A valid PhysicsFS filehandle on success, NULL on error. Specifics
  *           of the error can be gleaned from PHYSFS_getLastError().
  *
+ * \sa PHYSFS_openReadWrite
  * \sa PHYSFS_openWrite
  * \sa PHYSFS_openAppend
  * \sa PHYSFS_read
@@ -1169,6 +1172,32 @@
 
 
 /**
+ * \fn PHYSFS_File *PHYSFS_openReadWrite(const char *filename)
+ * \brief Open a file for reading and writing.
+ *
+ * Open a file for reading and writing, in platform-independent notation. The search path
+ *  is checked one at a time until a matching file is found, in which case an
+ *  abstract filehandle is associated with it, and reading may be done.
+ *  The reading offset is set to the first byte of the file.
+ *
+ * Note that entries that are symlinks are ignored if
+ *  PHYSFS_permitSymbolicLinks(1) hasn't been called, and opening a
+ *  symlink with this function will fail in such a case.
+ *
+ *   \param filename File to open.
+ *  \return A valid PhysicsFS filehandle on success, NULL on error. Specifics
+ *           of the error can be gleaned from PHYSFS_getLastError().
+ *
+ * \sa PHYSFS_openRead
+ * \sa PHYSFS_openWrite
+ * \sa PHYSFS_openAppend
+ * \sa PHYSFS_read
+ * \sa PHYSFS_close
+ */
+__EXPORT__ PHYSFS_File *PHYSFS_openReadWrite(const char *filename);
+
+
+/**
  * \fn int PHYSFS_close(PHYSFS_File *handle)
  * \brief Close a PhysicsFS filehandle.
  *
@@ -1183,6 +1212,7 @@
  *          gleaned from PHYSFS_getLastError().
  *
  * \sa PHYSFS_openRead
+ * \sa PHYSFS_openReadWrite
  * \sa PHYSFS_openWrite
  * \sa PHYSFS_openAppend
  */
diff -r 4413637bdcf2 src/physfs_internal.h
--- a/src/physfs_internal.h	Mon Apr 20 23:48:16 2009 -0400
+++ b/src/physfs_internal.h	Fri May 01 03:36:47 2009 -0300
@@ -824,6 +824,19 @@
     fvoid *(*openRead)(dvoid *opaque, const char *fname, int *fileExists);
 
         /*
+         * Open file for reading and writing.
+         * If the file does not exist, it should be created.
+	 * The offset should be the start of the file.
+         * This filename is in platform-independent notation.
+         * If you can't handle multiple opens of the same file,
+         *  you can opt to fail for the second call.
+         * Returns NULL on failure, and calls __PHYSFS_setError().
+         *  Returns non-NULL on success. The pointer returned will be
+         *  passed as the "opaque" parameter for later file calls.
+         */
+    fvoid *(*openReadWrite)(dvoid *opaque, const char *filename);
+
+        /*
          * Open file for writing.
          * If the file does not exist, it should be created. If it exists,
          *  it should be truncated to zero bytes. The writing
@@ -1145,6 +1158,22 @@
 
 
 /*
+ * Open a file for reading and writing. (filename) is in platform-dependent
+ *  notation. If the file doesn't exists, it should be created as a zero-byte
+ *  file. The file pointer should be positioned on the first byte of the file.
+ *
+ * The return value will be some platform-specific datatype that is opaque to
+ *  the caller; it could be a (FILE *) under Unix, or a (HANDLE *) under win32,
+ *  etc.
+ *
+ * Opening a file for read and write multiple times has undefined results.
+ *
+ * Call __PHYSFS_setError() and return (NULL) if the file can't be opened.
+ */
+void *__PHYSFS_platformOpenReadWrite(const char *filename);
+
+
+/*
  * Open a file for writing. (filename) is in platform-dependent notation. If
  *  the file exists, it should be truncated to zero bytes, and if it doesn't
  *  exist, it should be created as a zero-byte file. The file pointer should
diff -r 4413637bdcf2 src/platform_posix.c
--- a/src/platform_posix.c	Mon Apr 20 23:48:16 2009 -0400
+++ b/src/platform_posix.c	Fri May 01 03:36:47 2009 -0300
@@ -274,6 +274,12 @@
 } /* __PHYSFS_platformOpenRead */
 
 
+void *__PHYSFS_platformOpenReadWrite(const char *filename)
+{
+    return(doOpen(filename, O_RDWR | O_CREAT));
+} /* __PHYSFS_platformOpenReadWrite */
+
+
 void *__PHYSFS_platformOpenWrite(const char *filename)
 {
     return(doOpen(filename, O_WRONLY | O_CREAT | O_TRUNC));


More information about the physfs mailing list