Skip to content

Commit

Permalink
First chunk of PHYSFS_mount() implementation. Incomplete!
Browse files Browse the repository at this point in the history
  • Loading branch information
icculus committed Mar 13, 2005
1 parent 389a4d8 commit 93adbf1
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 24 deletions.
2 changes: 2 additions & 0 deletions TODO
Expand Up @@ -45,6 +45,8 @@ Some might be dupes, some might be done already.
- Should file enumeration return an error or set error state?
- Ryanify pocketpc.c ...
- Update internal zlib?
- Split verifySecurity() off into sanitizePath() and hook it into mount point
initialization.
- Get svn hooks working.
- maybe other stuff.

Expand Down
63 changes: 51 additions & 12 deletions physfs.c
Expand Up @@ -25,6 +25,7 @@ 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. */
const PHYSFS_Archiver *funcs; /* Ptr to archiver info for this handle. */
struct __PHYSFS_DIRHANDLE__ *next; /* linked list stuff. */
} DirHandle;
Expand Down Expand Up @@ -440,6 +441,7 @@ static DirHandle *tryOpenDir(const PHYSFS_Archiver *funcs,
else
{
memset(retval, '\0', sizeof (DirHandle));
retval->mountPoint = NULL;
retval->funcs = funcs;
retval->opaque = opaque;
} /* else */
Expand Down Expand Up @@ -487,25 +489,41 @@ static DirHandle *openDirectory(const char *d, int forWriting)
} /* openDirectory */


static DirHandle *createDirHandle(const char *newDir, int forWriting)
static DirHandle *createDirHandle(const char *newDir,
const char *mountPoint,
int forWriting)
{
DirHandle *dirHandle = NULL;

BAIL_IF_MACRO(newDir == NULL, ERR_INVALID_ARGUMENT, NULL);
GOTO_IF_MACRO(!newDir, ERR_INVALID_ARGUMENT, badDirHandle);

dirHandle = openDirectory(newDir, forWriting);
BAIL_IF_MACRO(dirHandle == NULL, NULL, NULL);
GOTO_IF_MACRO(!dirHandle, NULL, badDirHandle);

dirHandle->dirName = (char *) malloc(strlen(newDir) + 1);
if (dirHandle->dirName == NULL)
GOTO_IF_MACRO(!dirHandle->dirName, ERR_OUT_OF_MEMORY, badDirHandle);
strcpy(dirHandle->dirName, newDir);

if ((mountPoint != NULL) && (*mountPoint != '\0'))
{
/* !!! FIXME: Sanitize the string here. */
dirHandle->mountPoint = (char *) malloc(strlen(mountPoint) + 2);
GOTO_IF_MACRO(!dirHandle->mountPoint, ERR_OUT_OF_MEMORY, badDirHandle);
strcpy(dirHandle->mountPoint, mountPoint);
strcat(dirHandle->mountPoint, "/");
} /* if */

return(dirHandle);

badDirHandle:
if (dirHandle != NULL)
{
dirHandle->funcs->dirClose(dirHandle->opaque);
free(dirHandle->dirName);
free(dirHandle->mountPoint);
free(dirHandle);
BAIL_MACRO(ERR_OUT_OF_MEMORY, NULL);
} /* if */

strcpy(dirHandle->dirName, newDir);
return(dirHandle);
return(NULL);
} /* createDirHandle */


Expand Down Expand Up @@ -859,7 +877,7 @@ int PHYSFS_setWriteDir(const char *newDir)

if (newDir != NULL)
{
writeDir = createDirHandle(newDir, 1);
writeDir = createDirHandle(newDir, NULL, 1);
retval = (writeDir != NULL);
} /* if */

Expand All @@ -869,12 +887,15 @@ int PHYSFS_setWriteDir(const char *newDir)
} /* PHYSFS_setWriteDir */


int PHYSFS_addToSearchPath(const char *newDir, int appendToPath)
int PHYSFS_mount(const char *newDir, const char *mountPoint, int appendToPath)
{
DirHandle *dh;
DirHandle *prev = NULL;
DirHandle *i;

BAIL_IF_MACRO(newDir == NULL, ERR_INVALID_ARGUMENT, 0);
BAIL_IF_MACRO(mountPoint == NULL, ERR_INVALID_ARGUMENT, 0);

__PHYSFS_platformGrabMutex(stateLock);

for (i = searchPath; i != NULL; i = i->next)
Expand All @@ -884,7 +905,7 @@ int PHYSFS_addToSearchPath(const char *newDir, int appendToPath)
prev = i;
} /* for */

dh = createDirHandle(newDir, 0);
dh = createDirHandle(newDir, mountPoint, 0);
BAIL_IF_MACRO_MUTEX(dh == NULL, NULL, stateLock, 0);

if (appendToPath)
Expand All @@ -902,6 +923,12 @@ int PHYSFS_addToSearchPath(const char *newDir, int appendToPath)

__PHYSFS_platformReleaseMutex(stateLock);
return(1);
} /* PHYSFS_mount */


int PHYSFS_addToSearchPath(const char *newDir, int appendToPath)
{
return(PHYSFS_mount(newDir, "/", appendToPath));
} /* PHYSFS_addToSearchPath */


Expand Down Expand Up @@ -1130,7 +1157,8 @@ char * __PHYSFS_convertToDependent(const char *prepend,
* Verify that (fname) (in platform-independent notation), in relation
* to (h) is secure. That means that each element of fname is checked
* for symlinks (if they aren't permitted). Also, elements such as
* ".", "..", or ":" are flagged.
* ".", "..", or ":" are flagged. This also allows for quick rejection of
* files that exist outside an archive's mountpoint.
*
* With some exceptions (like PHYSFS_mkdir(), which builds multiple subdirs
* at a time), you should always pass zero for "allowMissing" for efficiency.
Expand All @@ -1148,6 +1176,17 @@ int __PHYSFS_verifySecurity(DirHandle *h, const char *fname, int allowMissing)
if (*fname == '\0') /* quick rejection. */
return(1);

if (h->mountPoint != NULL) /* NULL mountpoint means "/". */
{
/* !!! FIXME: Case insensitive? */
size_t mntpntlen = strlen(h->mountPoint);
assert(mntpntlen > 1); /* root mount points should be NULL. */
if (strncmp(h->mountPoint, fname, mntpntlen) != 0)
return(0); /* not under the mountpoint, so skip this archive. */

fname += mntpntlen; /* move to start of actual archive path. */
} /* if */

/* !!! FIXME: Can we ditch this malloc()? */
start = str = malloc(strlen(fname) + 1);
BAIL_IF_MACRO(str == NULL, ERR_OUT_OF_MEMORY, 0);
Expand Down
70 changes: 58 additions & 12 deletions physfs.h
Expand Up @@ -78,13 +78,13 @@
* it correctly.
*
* Files opened through PhysicsFS may NOT contain "." or ".." or ":" as dir
* elements. Not only are these meaningless on MacOS and/or Unix, they are a
* security hole. Also, symbolic links (which can be found in some archive
* types and directly in the filesystem on Unix platforms) are NOT followed
* until you call PHYSFS_permitSymbolicLinks(). That's left to your own
* discretion, as following a symlink can allow for access outside the write
* dir and search paths. There is no mechanism for creating new symlinks in
* PhysicsFS.
* elements. Not only are these meaningless on MacOS Classic and/or Unix,
* they are a security hole. Also, symbolic links (which can be found in
* some archive types and directly in the filesystem on Unix platforms) are
* NOT followed until you call PHYSFS_permitSymbolicLinks(). That's left to
* your own discretion, as following a symlink can allow for access outside
* the write dir and search paths. For portability, there is no mechanism for
* creating new symlinks in PhysicsFS.
*
* The write dir is not included in the search path unless you specifically
* add it. While you CAN change the write dir as many times as you like,
Expand All @@ -110,6 +110,18 @@
* PHYSFS_getBaseDir(), and PHYSFS_getUserDir() for info on what those
* are and how they can help you determine an optimal search path.
*
* PhysicsFS 2.0 adds the concept of "mounting" archives to arbitrary points
* in the search path. If a zipfile contains "maps/level.map" and you mount
* that archive at "mods/mymod", then you would have to open
* "mods/mymod/maps/level.map" to access the file, even though "mods/mymod"
* isn't actually specified in the .zip file. Unlike the Unix mentality of
* mounting a filesystem, "mods/mymod" doesn't actually have to exist when
* mounting the zipfile. It's a "virtual" directory. The mounting mechanism
* allows the developer to seperate archives in the tree and avoid trampling
* over files when added new archives, such as including mod support in a
* game...keeping external content on a tight leash in this manner can be of
* utmost importance to some applications.
*
* PhysicsFS is mostly thread safe. The error messages returned by
* PHYSFS_getLastError are unique by thread, and library-state-setting
* functions are mutex'd. For efficiency, individual file accesses are
Expand All @@ -124,7 +136,7 @@
* Note that archives need not be named as such: if you have a ZIP file and
* rename it with a .PKG extension, the file will still be recognized as a
* ZIP archive by PhysicsFS; the file's contents are used to determine its
* type.
* type where possible.
*
* Currently supported archive types:
* - .ZIP (pkZip/WinZip/Info-ZIP compatible)
Expand All @@ -133,12 +145,13 @@
* - .HOG (Descent I/II HOG file archives)
* - .MVL (Descent II movielib archives)
* - .WAD (DOOM engine archives)
* - .MIX (Older Westwood games archives)
*
* Please see the file LICENSE in the source's root directory for licensing
* and redistribution rights.
*
* Please see the file CREDITS in the source's root directory for a complete
* list of who's responsible for this.
* Please see the file CREDITS in the source's root directory for a more or
* less complete list of who's responsible for this.
*
* \author Ryan C. Gordon.
*/
Expand Down Expand Up @@ -656,19 +669,52 @@ __EXPORT__ int PHYSFS_setWriteDir(const char *newDir);


/**
* \fn int PHYSFS_addToSearchPath(const char *newDir, int appendToPath)
* \fn int PHYSFS_mount(const char *newDir, const char *mountPoint, int appendToPath);
* \brief Add an archive or directory to the search path.
*
* If this is a duplicate, the entry is not added again, even though the
* function succeeds.
* function succeeds. You may not add the same archive to two different
* mountpoints: duplicate checking is done against the archive and not the
* mountpoint.
*
* When you mount an archive, it is added to a virtual file system...all files
* in all of the archives are interpolated into a single hierachical file
* tree. Two archives mounted at the same place (or an archive with files
* overlapping another mountpoint) may have overlapping files: in such a case,
* the file earliest in the search path is selected, and the other files are
* inaccessible to the application. This allows archives to be used to
* override previous revisions; you can use the mounting mechanism to place
* archives at a specific point in the file tree and prevent overlap; this
* is useful for downloadable mods that might trample over application data
* or each other, for example.
*
* The mountpoint does not need to exist prior to mounting, which is different
* than those familiar with the Unix concept of "mounting" may not expect.
* As well, more than one archive can be mounted to the same mountpoint, or
* mountpoints and archive contents can overlap...the interpolation mechanism
* still functions as usual.
*
* \param newDir directory or archive to add to the path, in
* platform-dependent notation.
* \param mountPoint Location in the interpolated tree that this archive
* will be "mounted", in platform-independent notation.
* \param appendToPath nonzero to append to search path, zero to prepend.
* \return nonzero if added to path, zero on failure (bogus archive, dir
* missing, etc). Specifics of the error can be
* gleaned from PHYSFS_getLastError().
*/
__EXPORT__ int PHYSFS_mount(const char *newDir, const char *mountPoint, int appendToPath);


/**
* \fn int PHYSFS_addToSearchPath(const char *newDir, int appendToPath)
* \brief Add an archive or directory to the search path.
*
* This is a legacy call, equivalent to:
* PHYSFS_mount(newDir, "/", appendToPath);
*
* \sa PHYSFS_mount
* \sa PHYSFS_unmount
* \sa PHYSFS_removeFromSearchPath
* \sa PHYSFS_getSearchPath
*/
Expand Down

0 comments on commit 93adbf1

Please sign in to comment.