diff --git a/src/libraries/physfs/physfs.c b/src/libraries/physfs/physfs.c index eec40b2bf..f2b241f47 100644 --- a/src/libraries/physfs/physfs.c +++ b/src/libraries/physfs/physfs.c @@ -49,6 +49,7 @@ typedef struct __PHYSFS_DIRHANDLE__ char *root; /* subdirectory of archiver to use as root of archive (NULL for actual root) */ size_t rootlen; /* subdirectory of archiver to use as root of archive (NULL for actual root) */ const PHYSFS_Archiver *funcs; /* Ptr to archiver info for this handle. */ + int forWriting; /* Whether this was opened for writing or not. */ struct __PHYSFS_DIRHANDLE__ *next; /* linked list stuff. */ } DirHandle; @@ -862,6 +863,7 @@ static DirHandle *tryOpenDir(PHYSFS_Io *io, const PHYSFS_Archiver *funcs, retval->mountPoint = NULL; retval->funcs = funcs; retval->opaque = opaque; + retval->forWriting = forWriting; } /* else */ } /* if */ @@ -1749,7 +1751,7 @@ int PHYSFS_setRoot(const char *archive, const char *subdir) static int doMount(PHYSFS_Io *io, const char *fname, - const char *mountPoint, int appendToPath) + const char *mountPoint, int appendToPath, int forWriting) { DirHandle *dh; DirHandle *prev = NULL; @@ -1770,7 +1772,7 @@ static int doMount(PHYSFS_Io *io, const char *fname, prev = i; } /* for */ - dh = createDirHandle(io, fname, mountPoint, 0); + dh = createDirHandle(io, fname, mountPoint, forWriting); BAIL_IF_MUTEX_ERRPASS(!dh, stateLock, 0); if (appendToPath) @@ -1797,7 +1799,7 @@ int PHYSFS_mountIo(PHYSFS_Io *io, const char *fname, BAIL_IF(!io, PHYSFS_ERR_INVALID_ARGUMENT, 0); BAIL_IF(!fname, PHYSFS_ERR_INVALID_ARGUMENT, 0); BAIL_IF(io->version != 0, PHYSFS_ERR_UNSUPPORTED, 0); - return doMount(io, fname, mountPoint, appendToPath); + return doMount(io, fname, mountPoint, appendToPath, 0); } /* PHYSFS_mountIo */ @@ -1813,7 +1815,7 @@ int PHYSFS_mountMemory(const void *buf, PHYSFS_uint64 len, void (*del)(void *), io = __PHYSFS_createMemoryIo(buf, len, del); BAIL_IF_ERRPASS(!io, 0); - retval = doMount(io, fname, mountPoint, appendToPath); + retval = doMount(io, fname, mountPoint, appendToPath, 0); if (!retval) { /* docs say not to call (del) in case of failure, so cheat. */ @@ -1837,7 +1839,7 @@ int PHYSFS_mountHandle(PHYSFS_File *file, const char *fname, io = __PHYSFS_createHandleIo(file); BAIL_IF_ERRPASS(!io, 0); - retval = doMount(io, fname, mountPoint, appendToPath); + retval = doMount(io, fname, mountPoint, appendToPath, 0); if (!retval) { /* docs say not to destruct in case of failure, so cheat. */ @@ -1852,7 +1854,14 @@ int PHYSFS_mountHandle(PHYSFS_File *file, const char *fname, int PHYSFS_mount(const char *newDir, const char *mountPoint, int appendToPath) { BAIL_IF(!newDir, PHYSFS_ERR_INVALID_ARGUMENT, 0); - return doMount(NULL, newDir, mountPoint, appendToPath); + return doMount(NULL, newDir, mountPoint, appendToPath, 0); +} /* PHYSFS_mount */ + + +int PHYSFS_mountRW(const char *newDir, const char *mountPoint, int appendToPath) +{ + BAIL_IF(!newDir, PHYSFS_ERR_INVALID_ARGUMENT, 0); + return doMount(NULL, newDir, mountPoint, appendToPath, 1); } /* PHYSFS_mount */ @@ -2159,10 +2168,39 @@ static int verifyPath(DirHandle *h, char **_fname, int allowMissing) } /* verifyPath */ -/* This must hold the stateLock before calling. */ -static int doMkdir(const char *_dname, char *dname) +static DirHandle *findWriteHandle(const char *_fname) +{ + DirHandle *i = NULL; + char *allocated_fname; + char *fname; + size_t len; + + len = strlen(_fname) + longest_root + 1; + allocated_fname = (char *) __PHYSFS_smallAlloc(len); + BAIL_IF(!allocated_fname, PHYSFS_ERR_OUT_OF_MEMORY, NULL); + fname = allocated_fname + longest_root; + + if (sanitizePlatformIndependentPath(_fname, fname)) + { + for (i = searchPath; i != NULL; i = i->next) + { + char *arcfname = fname; + if (i->forWriting && verifyPath(i, &arcfname, 0)) + { + break; + } /* if */ + } /* for */ + } + + __PHYSFS_smallFree(allocated_fname); + + return i != NULL ? i : writeDir; +} /* findWriteHandle */ + + +/* This must hold the stateLock before calling. */ +static int doMkdir(const char *_dname, char *dname, DirHandle *h) { - DirHandle *h = writeDir; char *start; char *end; int retval = 0; @@ -2212,15 +2250,17 @@ int PHYSFS_mkdir(const char *_dname) int retval = 0; char *dname; size_t len; + DirHandle *h = NULL; BAIL_IF(!_dname, PHYSFS_ERR_INVALID_ARGUMENT, 0); __PHYSFS_platformGrabMutex(stateLock); - BAIL_IF_MUTEX(!writeDir, PHYSFS_ERR_NO_WRITE_DIR, stateLock, 0); - len = strlen(_dname) + dirHandleRootLen(writeDir) + 1; + h = findWriteHandle(_dname); + BAIL_IF_MUTEX(!h, PHYSFS_ERR_NO_WRITE_DIR, stateLock, 0); + len = strlen(_dname) + dirHandleRootLen(h) + 1; dname = (char *) __PHYSFS_smallAlloc(len); BAIL_IF_MUTEX(!dname, PHYSFS_ERR_OUT_OF_MEMORY, stateLock, 0); - retval = doMkdir(_dname, dname); + retval = doMkdir(_dname, dname, h); __PHYSFS_platformReleaseMutex(stateLock); __PHYSFS_smallFree(dname); return retval; @@ -2228,9 +2268,8 @@ int PHYSFS_mkdir(const char *_dname) /* This must hold the stateLock before calling. */ -static int doDelete(const char *_fname, char *fname) +static int doDelete(const char *_fname, char *fname, DirHandle *h) { - DirHandle *h = writeDir; BAIL_IF_ERRPASS(!sanitizePlatformIndependentPathWithRoot(h, _fname, fname), 0); BAIL_IF_ERRPASS(!verifyPath(h, &fname, 0), 0); return h->funcs->remove(h->opaque, fname); @@ -2242,13 +2281,15 @@ int PHYSFS_delete(const char *_fname) int retval; char *fname; size_t len; + DirHandle *h = NULL; __PHYSFS_platformGrabMutex(stateLock); - BAIL_IF_MUTEX(!writeDir, PHYSFS_ERR_NO_WRITE_DIR, stateLock, 0); - len = strlen(_fname) + dirHandleRootLen(writeDir) + 1; + h = findWriteHandle(_fname); + BAIL_IF_MUTEX(!h, PHYSFS_ERR_NO_WRITE_DIR, stateLock, 0); + len = strlen(_fname) + dirHandleRootLen(h) + 1; fname = (char *) __PHYSFS_smallAlloc(len); BAIL_IF_MUTEX(!fname, PHYSFS_ERR_OUT_OF_MEMORY, stateLock, 0); - retval = doDelete(_fname, fname); + retval = doDelete(_fname, fname, h); __PHYSFS_platformReleaseMutex(stateLock); __PHYSFS_smallFree(fname); return retval; @@ -2631,7 +2672,7 @@ static PHYSFS_File *doOpenWrite(const char *_fname, const int appending) __PHYSFS_platformGrabMutex(stateLock); - h = writeDir; + h = findWriteHandle(_fname); BAIL_IF_MUTEX(!h, PHYSFS_ERR_NO_WRITE_DIR, stateLock, 0); len = strlen(_fname) + dirHandleRootLen(h) + 1; @@ -3115,7 +3156,7 @@ int PHYSFS_stat(const char *_fname, PHYSFS_Stat *stat) if (exists) { stat->filetype = PHYSFS_FILETYPE_DIRECTORY; - stat->readonly = 1; + stat->readonly = !i->forWriting; retval = 1; } /* if */ else if (verifyPath(i, &arcfname, 0)) diff --git a/src/libraries/physfs/physfs.h b/src/libraries/physfs/physfs.h index 49d49dae4..9ec5e79e7 100644 --- a/src/libraries/physfs/physfs.h +++ b/src/libraries/physfs/physfs.h @@ -2204,6 +2204,14 @@ PHYSFS_DECL int PHYSFS_mount(const char *newDir, const char *mountPoint, int appendToPath); +/** + * Just like mount() but attempts to open the directory for writing as well as + * reading. + */ +PHYSFS_DECL int PHYSFS_mountRW(const char *newDir, + const char *mountPoint, + int appendToPath); + /** * \fn int PHYSFS_getMountPoint(const char *dir) * \brief Determine a mounted archive's mountpoint.