diff --git a/src/libraries/physfs/physfs.c b/src/libraries/physfs/physfs.c index 19148ad50..eec40b2bf 100644 --- a/src/libraries/physfs/physfs.c +++ b/src/libraries/physfs/physfs.c @@ -46,6 +46,8 @@ typedef struct __PHYSFS_DIRHANDLE__ void *opaque; /* Instance data unique to the archiver. */ char *dirName; /* Path to archive in platform-dependent notation. */ char *mountPoint; /* Mountpoint in virtual file tree. */ + 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. */ struct __PHYSFS_DIRHANDLE__ *next; /* linked list stuff. */ } DirHandle; @@ -86,6 +88,7 @@ static int allowSymLinks = 0; static PHYSFS_Archiver **archivers = NULL; static PHYSFS_ArchiveInfo **archiveInfo = NULL; static volatile size_t numArchivers = 0; +static size_t longest_root = 0; /* mutexes ... */ static void *errorLock = NULL; /* protects error message list. */ @@ -879,13 +882,20 @@ static DirHandle *openDirectory(PHYSFS_Io *io, const char *d, int forWriting) if (io == NULL) { + /* file doesn't exist, etc? Just fail out. */ + PHYSFS_Stat statbuf; + BAIL_IF_ERRPASS(!__PHYSFS_platformStat(d, &statbuf, 1), NULL); + /* DIR gets first shot (unlike the rest, it doesn't deal with files). */ - retval = tryOpenDir(io, &__PHYSFS_Archiver_DIR, d, forWriting, &claimed); - if (retval || claimed) - return retval; + if (statbuf.filetype == PHYSFS_FILETYPE_DIRECTORY) + { + retval = tryOpenDir(io, &__PHYSFS_Archiver_DIR, d, forWriting, &claimed); + if (retval || claimed) + return retval; + } /* if */ io = __PHYSFS_createNativeIo(d, forWriting ? 'w' : 'r'); - BAIL_IF_ERRPASS(!io, 0); + BAIL_IF_ERRPASS(!io, NULL); created_io = 1; } /* if */ @@ -973,6 +983,18 @@ static int sanitizePlatformIndependentPath(const char *src, char *dst) } /* sanitizePlatformIndependentPath */ +static inline size_t dirHandleRootLen(const DirHandle *h) +{ + return h ? h->rootlen : 0; +} /* dirHandleRootLen */ + +static inline int sanitizePlatformIndependentPathWithRoot(const DirHandle *h, const char *src, char *dst) +{ + return sanitizePlatformIndependentPath(src, dst + dirHandleRootLen(h)); +} /* sanitizePlatformIndependentPathWithRoot */ + + + /* * Figure out if (fname) is part of (h)'s mountpoint. (fname) must be an * output from sanitizePlatformIndependentPath(), so that it is in a known @@ -1371,6 +1393,7 @@ static int doDeinit(void) archivers = NULL; } /* if */ + longest_root = 0; allowSymLinks = 0; initialized = 0; @@ -1677,6 +1700,54 @@ int PHYSFS_setWriteDir(const char *newDir) } /* PHYSFS_setWriteDir */ +int PHYSFS_setRoot(const char *archive, const char *subdir) +{ + DirHandle *i; + + BAIL_IF(!archive, PHYSFS_ERR_INVALID_ARGUMENT, 0); + + __PHYSFS_platformGrabMutex(stateLock); + + for (i = searchPath; i != NULL; i = i->next) + { + if ((i->dirName != NULL) && (strcmp(archive, i->dirName) == 0)) + { + if (!subdir || (strcmp(subdir, "/") == 0)) + { + if (i->root) + allocator.Free(i->root); + i->root = NULL; + i->rootlen = 0; + } /* if */ + else + { + const size_t len = strlen(subdir) + 1; + char *ptr = (char *) allocator.Malloc(len); + BAIL_IF_MUTEX(!ptr, PHYSFS_ERR_OUT_OF_MEMORY, stateLock, 0); + if (!sanitizePlatformIndependentPath(subdir, ptr)) + { + allocator.Free(ptr); + BAIL_MUTEX_ERRPASS(stateLock, 0); + } /* if */ + + if (i->root) + allocator.Free(i->root); + i->root = ptr; + i->rootlen = len; + + if (longest_root < len) + longest_root = len; + } /* else */ + + break; + } /* if */ + } /* for */ + + __PHYSFS_platformReleaseMutex(stateLock); + return 1; +} /* PHYSFS_setRoot */ + + static int doMount(PHYSFS_Io *io, const char *fname, const char *mountPoint, int appendToPath) { @@ -1994,6 +2065,9 @@ int PHYSFS_symbolicLinksPermitted(void) * like ".." which should be done once instead of once per archive. This also * gives us license to treat (fname) as scratch space in this function. * + * (fname)'s buffer must have enough space available before it for this + * function to prepend any root directory for this DirHandle. + * * Returns non-zero if string is safe, zero if there's a security issue. * PHYSFS_getLastError() will specify what was wrong. (*fname) will be * updated to point past any mount point elements so it is prepared to @@ -2006,7 +2080,7 @@ static int verifyPath(DirHandle *h, char **_fname, int allowMissing) char *start; char *end; - if (*fname == '\0') /* quick rejection. */ + if ((*fname == '\0') && (!h->root)) /* quick rejection. */ return 1; /* !!! FIXME: This codeblock sucks. */ @@ -2029,6 +2103,17 @@ static int verifyPath(DirHandle *h, char **_fname, int allowMissing) retval = 1; /* may be reset, below. */ } /* if */ + /* prepend the root directory, if any. */ + if (h->root) + { + const int isempty = (*fname == '\0'); + fname -= h->rootlen - 1; + strcpy(fname, h->root); + if (!isempty) + fname[h->rootlen - 2] = '/'; + *_fname = fname; + } /* if */ + start = fname; if (!allowSymLinks) { @@ -2074,20 +2159,19 @@ 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) { - DirHandle *h; + DirHandle *h = writeDir; char *start; char *end; int retval = 0; int exists = 1; /* force existance check on first path element. */ - BAIL_IF_ERRPASS(!sanitizePlatformIndependentPath(_dname, dname), 0); + assert(h != NULL); - __PHYSFS_platformGrabMutex(stateLock); - BAIL_IF_MUTEX(!writeDir, PHYSFS_ERR_NO_WRITE_DIR, stateLock, 0); - h = writeDir; - BAIL_IF_MUTEX_ERRPASS(!verifyPath(h, &dname, 1), stateLock, 0); + BAIL_IF_ERRPASS(!sanitizePlatformIndependentPathWithRoot(h, _dname, dname), 0); + BAIL_IF_ERRPASS(!verifyPath(h, &dname, 1), 0); start = dname; while (1) @@ -2119,7 +2203,6 @@ static int doMkdir(const char *_dname, char *dname) start = end + 1; } /* while */ - __PHYSFS_platformReleaseMutex(stateLock); return retval; } /* doMkdir */ @@ -2131,30 +2214,26 @@ int PHYSFS_mkdir(const char *_dname) size_t len; BAIL_IF(!_dname, PHYSFS_ERR_INVALID_ARGUMENT, 0); - len = strlen(_dname) + 1; + + __PHYSFS_platformGrabMutex(stateLock); + BAIL_IF_MUTEX(!writeDir, PHYSFS_ERR_NO_WRITE_DIR, stateLock, 0); + len = strlen(_dname) + dirHandleRootLen(writeDir) + 1; dname = (char *) __PHYSFS_smallAlloc(len); - BAIL_IF(!dname, PHYSFS_ERR_OUT_OF_MEMORY, 0); + BAIL_IF_MUTEX(!dname, PHYSFS_ERR_OUT_OF_MEMORY, stateLock, 0); retval = doMkdir(_dname, dname); + __PHYSFS_platformReleaseMutex(stateLock); __PHYSFS_smallFree(dname); return retval; } /* PHYSFS_mkdir */ +/* This must hold the stateLock before calling. */ static int doDelete(const char *_fname, char *fname) { - int retval; - DirHandle *h; - BAIL_IF_ERRPASS(!sanitizePlatformIndependentPath(_fname, fname), 0); - - __PHYSFS_platformGrabMutex(stateLock); - - BAIL_IF_MUTEX(!writeDir, PHYSFS_ERR_NO_WRITE_DIR, stateLock, 0); - h = writeDir; - BAIL_IF_MUTEX_ERRPASS(!verifyPath(h, &fname, 0), stateLock, 0); - retval = h->funcs->remove(h->opaque, fname); - - __PHYSFS_platformReleaseMutex(stateLock); - return retval; + 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); } /* doDelete */ @@ -2164,11 +2243,13 @@ int PHYSFS_delete(const char *_fname) char *fname; size_t len; - BAIL_IF(!_fname, PHYSFS_ERR_INVALID_ARGUMENT, 0); - len = strlen(_fname) + 1; + __PHYSFS_platformGrabMutex(stateLock); + BAIL_IF_MUTEX(!writeDir, PHYSFS_ERR_NO_WRITE_DIR, stateLock, 0); + len = strlen(_fname) + dirHandleRootLen(writeDir) + 1; fname = (char *) __PHYSFS_smallAlloc(len); - BAIL_IF(!fname, PHYSFS_ERR_OUT_OF_MEMORY, 0); + BAIL_IF_MUTEX(!fname, PHYSFS_ERR_OUT_OF_MEMORY, stateLock, 0); retval = doDelete(_fname, fname); + __PHYSFS_platformReleaseMutex(stateLock); __PHYSFS_smallFree(fname); return retval; } /* PHYSFS_delete */ @@ -2177,17 +2258,20 @@ int PHYSFS_delete(const char *_fname) static DirHandle *getRealDirHandle(const char *_fname) { DirHandle *retval = NULL; + char *allocated_fname = NULL; char *fname = NULL; size_t len; BAIL_IF(!_fname, PHYSFS_ERR_INVALID_ARGUMENT, NULL); - len = strlen(_fname) + 1; - fname = __PHYSFS_smallAlloc(len); - BAIL_IF(!fname, PHYSFS_ERR_OUT_OF_MEMORY, NULL); + + __PHYSFS_platformGrabMutex(stateLock); + len = strlen(_fname) + longest_root + 1; + allocated_fname = __PHYSFS_smallAlloc(len); + BAIL_IF_MUTEX(!allocated_fname, PHYSFS_ERR_OUT_OF_MEMORY, stateLock, NULL); + fname = allocated_fname + longest_root; if (sanitizePlatformIndependentPath(_fname, fname)) { DirHandle *i; - __PHYSFS_platformGrabMutex(stateLock); for (i = searchPath; i != NULL; i = i->next) { char *arcfname = fname; @@ -2206,10 +2290,10 @@ static DirHandle *getRealDirHandle(const char *_fname) } /* if */ } /* if */ } /* for */ - __PHYSFS_platformReleaseMutex(stateLock); } /* if */ - __PHYSFS_smallFree(fname); + __PHYSFS_platformReleaseMutex(stateLock); + __PHYSFS_smallFree(allocated_fname); return retval; } /* getRealDirHandle */ @@ -2404,15 +2488,18 @@ int PHYSFS_enumerate(const char *_fn, PHYSFS_EnumerateCallback cb, void *data) { PHYSFS_EnumerateCallbackResult retval = PHYSFS_ENUM_OK; size_t len; + char *allocated_fname; char *fname; BAIL_IF(!_fn, PHYSFS_ERR_INVALID_ARGUMENT, 0); BAIL_IF(!cb, PHYSFS_ERR_INVALID_ARGUMENT, 0); - len = strlen(_fn) + 1; - fname = (char *) __PHYSFS_smallAlloc(len); - BAIL_IF(!fname, PHYSFS_ERR_OUT_OF_MEMORY, 0); + __PHYSFS_platformGrabMutex(stateLock); + len = strlen(_fn) + longest_root + 1; + allocated_fname = (char *) __PHYSFS_smallAlloc(len); + BAIL_IF_MUTEX(!allocated_fname, PHYSFS_ERR_OUT_OF_MEMORY, stateLock, 0); + fname = allocated_fname + longest_root; if (!sanitizePlatformIndependentPath(_fn, fname)) retval = PHYSFS_ENUM_STOP; else @@ -2420,8 +2507,6 @@ int PHYSFS_enumerate(const char *_fn, PHYSFS_EnumerateCallback cb, void *data) DirHandle *i; SymlinkFilterData filterdata; - __PHYSFS_platformGrabMutex(stateLock); - if (!allowSymLinks) { memset(&filterdata, '\0', sizeof (filterdata)); @@ -2470,10 +2555,11 @@ int PHYSFS_enumerate(const char *_fn, PHYSFS_EnumerateCallback cb, void *data) } /* else if */ } /* for */ - __PHYSFS_platformReleaseMutex(stateLock); } /* if */ - __PHYSFS_smallFree(fname); + __PHYSFS_platformReleaseMutex(stateLock); + + __PHYSFS_smallFree(allocated_fname); return (retval == PHYSFS_ENUM_ERROR) ? 0 : 1; } /* PHYSFS_enumerate */ @@ -2534,57 +2620,58 @@ int PHYSFS_isSymbolicLink(const char *fname) } /* PHYSFS_isSymbolicLink */ -static PHYSFS_File *doOpenWrite(const char *_fname, int appending) +static PHYSFS_File *doOpenWrite(const char *_fname, const int appending) { FileHandle *fh = NULL; + DirHandle *h; size_t len; char *fname; BAIL_IF(!_fname, PHYSFS_ERR_INVALID_ARGUMENT, 0); - len = strlen(_fname) + 1; - fname = (char *) __PHYSFS_smallAlloc(len); - BAIL_IF(!fname, PHYSFS_ERR_OUT_OF_MEMORY, 0); - if (sanitizePlatformIndependentPath(_fname, fname)) + __PHYSFS_platformGrabMutex(stateLock); + + h = writeDir; + 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); + + if (sanitizePlatformIndependentPathWithRoot(h, _fname, fname)) { PHYSFS_Io *io = NULL; - DirHandle *h = NULL; - const PHYSFS_Archiver *f; - - __PHYSFS_platformGrabMutex(stateLock); - - GOTO_IF(!writeDir, PHYSFS_ERR_NO_WRITE_DIR, doOpenWriteEnd); - - h = writeDir; - GOTO_IF_ERRPASS(!verifyPath(h, &fname, 0), doOpenWriteEnd); - - f = h->funcs; - if (appending) - io = f->openAppend(h->opaque, fname); - else - io = f->openWrite(h->opaque, fname); - - GOTO_IF_ERRPASS(!io, doOpenWriteEnd); - - fh = (FileHandle *) allocator.Malloc(sizeof (FileHandle)); - if (fh == NULL) + char *arcfname = fname; + if (verifyPath(h, &arcfname, 0)) { - io->destroy(io); - GOTO(PHYSFS_ERR_OUT_OF_MEMORY, doOpenWriteEnd); + const PHYSFS_Archiver *f = h->funcs; + if (appending) + io = f->openAppend(h->opaque, arcfname); + else + io = f->openWrite(h->opaque, arcfname); + + if (io) + { + fh = (FileHandle *) allocator.Malloc(sizeof (FileHandle)); + if (fh == NULL) + { + io->destroy(io); + PHYSFS_setErrorCode(PHYSFS_ERR_OUT_OF_MEMORY); + } /* if */ + else + { + memset(fh, '\0', sizeof (FileHandle)); + fh->io = io; + fh->dirHandle = h; + fh->next = openWriteList; + openWriteList = fh; + } /* else */ + } /* if */ } /* if */ - else - { - memset(fh, '\0', sizeof (FileHandle)); - fh->io = io; - fh->dirHandle = h; - fh->next = openWriteList; - openWriteList = fh; - } /* else */ - - doOpenWriteEnd: - __PHYSFS_platformReleaseMutex(stateLock); } /* if */ + __PHYSFS_platformReleaseMutex(stateLock); + __PHYSFS_smallFree(fname); return ((PHYSFS_File *) fh); } /* doOpenWrite */ @@ -2605,22 +2692,25 @@ PHYSFS_File *PHYSFS_openAppend(const char *filename) PHYSFS_File *PHYSFS_openRead(const char *_fname) { FileHandle *fh = NULL; + char *allocated_fname; char *fname; size_t len; BAIL_IF(!_fname, PHYSFS_ERR_INVALID_ARGUMENT, 0); - len = strlen(_fname) + 1; - fname = (char *) __PHYSFS_smallAlloc(len); - BAIL_IF(!fname, PHYSFS_ERR_OUT_OF_MEMORY, 0); + + __PHYSFS_platformGrabMutex(stateLock); + + BAIL_IF_MUTEX(!searchPath, PHYSFS_ERR_NOT_FOUND, stateLock, 0); + + len = strlen(_fname) + longest_root + 1; + allocated_fname = (char *) __PHYSFS_smallAlloc(len); + BAIL_IF_MUTEX(!allocated_fname, PHYSFS_ERR_OUT_OF_MEMORY, stateLock, 0); + fname = allocated_fname + longest_root; if (sanitizePlatformIndependentPath(_fname, fname)) { - DirHandle *i = NULL; PHYSFS_Io *io = NULL; - - __PHYSFS_platformGrabMutex(stateLock); - - GOTO_IF(!searchPath, PHYSFS_ERR_NOT_FOUND, openReadEnd); + DirHandle *i; for (i = searchPath; i != NULL; i = i->next) { @@ -2633,27 +2723,26 @@ PHYSFS_File *PHYSFS_openRead(const char *_fname) } /* if */ } /* for */ - GOTO_IF_ERRPASS(!io, openReadEnd); - - fh = (FileHandle *) allocator.Malloc(sizeof (FileHandle)); - if (fh == NULL) + if (io) { - io->destroy(io); - GOTO(PHYSFS_ERR_OUT_OF_MEMORY, openReadEnd); + fh = (FileHandle *) allocator.Malloc(sizeof (FileHandle)); + if (fh == NULL) + { + io->destroy(io); + PHYSFS_setErrorCode(PHYSFS_ERR_OUT_OF_MEMORY); + } /* if */ + + memset(fh, '\0', sizeof (FileHandle)); + fh->io = io; + fh->forReading = 1; + fh->dirHandle = i; + fh->next = openReadList; + openReadList = fh; } /* if */ - - memset(fh, '\0', sizeof (FileHandle)); - fh->io = io; - fh->forReading = 1; - fh->dirHandle = i; - fh->next = openReadList; - openReadList = fh; - - openReadEnd: - __PHYSFS_platformReleaseMutex(stateLock); } /* if */ - __PHYSFS_smallFree(fname); + __PHYSFS_platformReleaseMutex(stateLock); + __PHYSFS_smallFree(allocated_fname); return ((PHYSFS_File *) fh); } /* PHYSFS_openRead */ @@ -2662,7 +2751,6 @@ static int closeHandleInOpenList(FileHandle **list, FileHandle *handle) { FileHandle *prev = NULL; FileHandle *i; - int rc = 1; for (i = *list; i != NULL; i = i->next) { @@ -2670,9 +2758,19 @@ static int closeHandleInOpenList(FileHandle **list, FileHandle *handle) { PHYSFS_Io *io = handle->io; PHYSFS_uint8 *tmp = handle->buffer; - rc = PHYSFS_flush((PHYSFS_File *) handle); - if (!rc) - return -1; + + /* send our buffer to io... */ + if (!handle->forReading) + { + if (!PHYSFS_flush((PHYSFS_File *) handle)) + return -1; + + /* ...then have io send it to the disk... */ + else if (io->flush && !io->flush(io)) + return -1; + } /* if */ + + /* ...then close the underlying file. */ io->destroy(io); if (tmp != NULL) /* free any associated buffer. */ @@ -2970,21 +3068,19 @@ int PHYSFS_flush(PHYSFS_File *handle) rc = io->write(io, fh->buffer + fh->bufpos, fh->buffill - fh->bufpos); BAIL_IF_ERRPASS(rc <= 0, 0); fh->bufpos = fh->buffill = 0; - return io->flush ? io->flush(io) : 1; + return 1; } /* PHYSFS_flush */ int PHYSFS_stat(const char *_fname, PHYSFS_Stat *stat) { int retval = 0; + char *allocated_fname; char *fname; size_t len; BAIL_IF(!_fname, PHYSFS_ERR_INVALID_ARGUMENT, 0); BAIL_IF(!stat, PHYSFS_ERR_INVALID_ARGUMENT, 0); - len = strlen(_fname) + 1; - fname = (char *) __PHYSFS_smallAlloc(len); - BAIL_IF(!fname, PHYSFS_ERR_OUT_OF_MEMORY, 0); /* set some sane defaults... */ stat->filesize = -1; @@ -2994,6 +3090,12 @@ int PHYSFS_stat(const char *_fname, PHYSFS_Stat *stat) stat->filetype = PHYSFS_FILETYPE_OTHER; stat->readonly = 1; + __PHYSFS_platformGrabMutex(stateLock); + len = strlen(_fname) + longest_root + 1; + allocated_fname = (char *) __PHYSFS_smallAlloc(len); + BAIL_IF_MUTEX(!allocated_fname, PHYSFS_ERR_OUT_OF_MEMORY, stateLock, 0); + fname = allocated_fname + longest_root; + if (sanitizePlatformIndependentPath(_fname, fname)) { if (*fname == '\0') @@ -3006,7 +3108,6 @@ int PHYSFS_stat(const char *_fname, PHYSFS_Stat *stat) { DirHandle *i; int exists = 0; - __PHYSFS_platformGrabMutex(stateLock); for (i = searchPath; ((i != NULL) && (!exists)); i = i->next) { char *arcfname = fname; @@ -3024,11 +3125,11 @@ int PHYSFS_stat(const char *_fname, PHYSFS_Stat *stat) exists = 1; } /* else if */ } /* for */ - __PHYSFS_platformReleaseMutex(stateLock); } /* else */ } /* if */ - __PHYSFS_smallFree(fname); + __PHYSFS_platformReleaseMutex(stateLock); + __PHYSFS_smallFree(allocated_fname); return retval; } /* PHYSFS_stat */ diff --git a/src/libraries/physfs/physfs.h b/src/libraries/physfs/physfs.h index 91696075f..49d49dae4 100644 --- a/src/libraries/physfs/physfs.h +++ b/src/libraries/physfs/physfs.h @@ -225,11 +225,11 @@ extern "C" { #if defined(PHYSFS_DECL) /* do nothing. */ -#elif (defined _MSC_VER) +#elif defined(_MSC_VER) #define PHYSFS_DECL __declspec(dllexport) -#elif (defined __SUNPRO_C) +#elif defined(__SUNPRO_C) #define PHYSFS_DECL __global -#elif ((__GNUC__ >= 3) && (!__EMX__) && (!sun)) +#elif ((__GNUC__ >= 3) && (!defined(__EMX__)) && (!defined(sun))) #define PHYSFS_DECL __attribute__((visibility("default"))) #else #define PHYSFS_DECL @@ -433,8 +433,8 @@ typedef struct PHYSFS_Version #ifndef DOXYGEN_SHOULD_IGNORE_THIS #define PHYSFS_VER_MAJOR 3 -#define PHYSFS_VER_MINOR 0 -#define PHYSFS_VER_PATCH 1 +#define PHYSFS_VER_MINOR 1 +#define PHYSFS_VER_PATCH 0 #endif /* DOXYGEN_SHOULD_IGNORE_THIS */ @@ -3844,6 +3844,46 @@ PHYSFS_DECL int PHYSFS_deregisterArchiver(const char *ext); /* Everything above this line is part of the PhysicsFS 2.1 API. */ + +/** + * \fn int PHYSFS_setRoot(const char *archive, const char *subdir) + * \brief Make a subdirectory of an archive its root directory. + * + * This lets you narrow down the accessible files in a specific archive. For + * example, if you have x.zip with a file in y/z.txt, mounted to /a, if you + * call PHYSFS_setRoot("x.zip", "/y"), then the call + * PHYSFS_openRead("/a/z.txt") will succeed. + * + * You can change an archive's root at any time, altering the interpolated + * file tree (depending on where paths shift, a different archive may be + * providing various files). If you set the root to NULL or "/", the + * archive will be treated as if no special root was set (as if the archive + * was just mounted normally). + * + * Changing the root only affects future operations on pathnames; a file + * that was opened from a path that changed due to a setRoot will not be + * affected. + * + * Setting a new root is not limited to archives in the search path; you may + * set one on the write dir, too, which might be useful if you have files + * open for write and thus can't change the write dir at the moment. + * + * It is not an error to set a subdirectory that does not exist to be the + * root of an archive; however, no files will be visible in this case. If + * the missing directories end up getting created (a mkdir to the physical + * filesystem, etc) then this will be reflected in the interpolated tree. + * + * \param archive dir/archive on which to change root. + * \param subdir new subdirectory to make the root of this archive. + * \return nonzero on success, zero on failure. Use + * PHYSFS_getLastErrorCode() to obtain the specific error. + */ +PHYSFS_DECL int PHYSFS_setRoot(const char *archive, const char *subdir); + + +/* Everything above this line is part of the PhysicsFS 3.1 API. */ + + #ifdef __cplusplus } #endif diff --git a/src/libraries/physfs/physfs_archiver_7z.c b/src/libraries/physfs/physfs_archiver_7z.c index f35a0b10e..914f69164 100644 --- a/src/libraries/physfs/physfs_archiver_7z.c +++ b/src/libraries/physfs/physfs_archiver_7z.c @@ -203,6 +203,8 @@ static void SZIP_closeArchive(void *opaque) SZIPinfo *info = (SZIPinfo *) opaque; if (info) { + if (info->io) + info->io->destroy(info->io); SzArEx_Free(&info->db, &SZIP_SzAlloc); __PHYSFS_DirTreeDeinit(&info->tree); allocator.Free(info); diff --git a/src/libraries/physfs/physfs_internal.h b/src/libraries/physfs/physfs_internal.h index 003ecc586..29126234a 100644 --- a/src/libraries/physfs/physfs_internal.h +++ b/src/libraries/physfs/physfs_internal.h @@ -162,35 +162,44 @@ void __PHYSFS_smallFree(void *ptr); #define free(x) Do not use free() directly. /* !!! FIXME: add alloca check here. */ + +/* by default, enable things, so builds can opt out of a few things they + want to avoid. But you can build with this #defined to 0 if you would + like to turn off everything except a handful of things you opt into. */ +#ifndef PHYSFS_SUPPORTS_DEFAULT +#define PHYSFS_SUPPORTS_DEFAULT 1 +#endif + + #ifndef PHYSFS_SUPPORTS_ZIP -#define PHYSFS_SUPPORTS_ZIP 1 +#define PHYSFS_SUPPORTS_ZIP PHYSFS_SUPPORTS_DEFAULT #endif #ifndef PHYSFS_SUPPORTS_7Z -#define PHYSFS_SUPPORTS_7Z 1 +#define PHYSFS_SUPPORTS_7Z PHYSFS_SUPPORTS_DEFAULT #endif #ifndef PHYSFS_SUPPORTS_GRP -#define PHYSFS_SUPPORTS_GRP 1 +#define PHYSFS_SUPPORTS_GRP PHYSFS_SUPPORTS_DEFAULT #endif #ifndef PHYSFS_SUPPORTS_HOG -#define PHYSFS_SUPPORTS_HOG 1 +#define PHYSFS_SUPPORTS_HOG PHYSFS_SUPPORTS_DEFAULT #endif #ifndef PHYSFS_SUPPORTS_MVL -#define PHYSFS_SUPPORTS_MVL 1 +#define PHYSFS_SUPPORTS_MVL PHYSFS_SUPPORTS_DEFAULT #endif #ifndef PHYSFS_SUPPORTS_WAD -#define PHYSFS_SUPPORTS_WAD 1 +#define PHYSFS_SUPPORTS_WAD PHYSFS_SUPPORTS_DEFAULT #endif #ifndef PHYSFS_SUPPORTS_QPAK -#define PHYSFS_SUPPORTS_QPAK 1 +#define PHYSFS_SUPPORTS_QPAK PHYSFS_SUPPORTS_DEFAULT #endif #ifndef PHYSFS_SUPPORTS_SLB -#define PHYSFS_SUPPORTS_SLB 1 +#define PHYSFS_SUPPORTS_SLB PHYSFS_SUPPORTS_DEFAULT #endif #ifndef PHYSFS_SUPPORTS_ISO9660 -#define PHYSFS_SUPPORTS_ISO9660 1 +#define PHYSFS_SUPPORTS_ISO9660 PHYSFS_SUPPORTS_DEFAULT #endif #ifndef PHYSFS_SUPPORTS_VDF -#define PHYSFS_SUPPORTS_VDF 1 +#define PHYSFS_SUPPORTS_VDF PHYSFS_SUPPORTS_DEFAULT #endif #if PHYSFS_SUPPORTS_7Z diff --git a/src/libraries/physfs/physfs_miniz.h b/src/libraries/physfs/physfs_miniz.h index 30d6f4cc7..489c52d60 100644 --- a/src/libraries/physfs/physfs_miniz.h +++ b/src/libraries/physfs/physfs_miniz.h @@ -699,3 +699,4 @@ static int mz_inflateEnd(mz_streamp pStream) For more information, please refer to */ + diff --git a/src/libraries/physfs/physfs_platform_apple.m b/src/libraries/physfs/physfs_platform_apple.m index fe50f4b02..e6207f5b7 100644 --- a/src/libraries/physfs/physfs_platform_apple.m +++ b/src/libraries/physfs/physfs_platform_apple.m @@ -50,7 +50,7 @@ char *__PHYSFS_platformCalcPrefDir(const char *org, const char *app) { NSArray *paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, TRUE); BAIL_IF(!paths, PHYSFS_ERR_OS_ERROR, NULL); - NSString *path = (NSString *) paths[0]; + NSString *path = (NSString *) [paths objectAtIndex:0]; BAIL_IF(!path, PHYSFS_ERR_OS_ERROR, NULL); size_t len = [path lengthOfBytesUsingEncoding:NSUTF8StringEncoding]; const size_t applen = strlen(app); diff --git a/src/libraries/physfs/physfs_platform_windows.c b/src/libraries/physfs/physfs_platform_windows.c index 4f8c99a68..c92e98d07 100644 --- a/src/libraries/physfs/physfs_platform_windows.c +++ b/src/libraries/physfs/physfs_platform_windows.c @@ -572,18 +572,20 @@ char *__PHYSFS_platformCalcUserDir(void) /* * Should fail. Will write the size of the profile path in * psize. Also note that the second parameter can't be - * NULL or the function fails. - */ - /* - * EDIT: (03.10.2018) after Windows 10 Update 1809 psize will be zero - * if something other than NULL is passed for the second argument. - * Passing NULL now makes GetUserProfileDirectoryW fail (rc == 0) - * and psize receives the correct user directory length. - * It seems to work fine on Windows 7 and Windows 10 Update 1803 too + * NULL or the function fails on Windows XP, but has to be NULL on + * Windows 10 or it will fail. :( */ rc = pGetDir(accessToken, NULL, &psize); GOTO_IF(rc, PHYSFS_ERR_OS_ERROR, done); /* should have failed! */ + if (psize == 0) /* probably on Windows XP, try a different way. */ + { + WCHAR x = 0; + rc = pGetDir(accessToken, &x, &psize); + GOTO_IF(rc, PHYSFS_ERR_OS_ERROR, done); /* should have failed! */ + GOTO_IF(!psize, PHYSFS_ERR_OS_ERROR, done); /* Uhoh... */ + } /* if */ + /* Allocate memory for the profile directory */ wstr = (LPWSTR) __PHYSFS_smallAlloc((psize + 1) * sizeof (WCHAR)); if (wstr != NULL)