|
@@ -46,6 +46,8 @@ typedef struct __PHYSFS_DIRHANDLE__
|
|
void *opaque; /* Instance data unique to the archiver. */
|
|
void *opaque; /* Instance data unique to the archiver. */
|
|
char *dirName; /* Path to archive in platform-dependent notation. */
|
|
char *dirName; /* Path to archive in platform-dependent notation. */
|
|
char *mountPoint; /* Mountpoint in virtual file tree. */
|
|
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. */
|
|
const PHYSFS_Archiver *funcs; /* Ptr to archiver info for this handle. */
|
|
struct __PHYSFS_DIRHANDLE__ *next; /* linked list stuff. */
|
|
struct __PHYSFS_DIRHANDLE__ *next; /* linked list stuff. */
|
|
} DirHandle;
|
|
} DirHandle;
|
|
@@ -86,6 +88,7 @@ static int allowSymLinks = 0;
|
|
static PHYSFS_Archiver **archivers = NULL;
|
|
static PHYSFS_Archiver **archivers = NULL;
|
|
static PHYSFS_ArchiveInfo **archiveInfo = NULL;
|
|
static PHYSFS_ArchiveInfo **archiveInfo = NULL;
|
|
static volatile size_t numArchivers = 0;
|
|
static volatile size_t numArchivers = 0;
|
|
|
|
+static size_t longest_root = 0;
|
|
|
|
|
|
/* mutexes ... */
|
|
/* mutexes ... */
|
|
static void *errorLock = NULL; /* protects error message list. */
|
|
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)
|
|
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). */
|
|
/* 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');
|
|
io = __PHYSFS_createNativeIo(d, forWriting ? 'w' : 'r');
|
|
- BAIL_IF_ERRPASS(!io, 0);
|
|
|
|
|
|
+ BAIL_IF_ERRPASS(!io, NULL);
|
|
created_io = 1;
|
|
created_io = 1;
|
|
} /* if */
|
|
} /* if */
|
|
|
|
|
|
@@ -973,6 +983,18 @@ static int sanitizePlatformIndependentPath(const char *src, char *dst)
|
|
} /* sanitizePlatformIndependentPath */
|
|
} /* 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
|
|
* Figure out if (fname) is part of (h)'s mountpoint. (fname) must be an
|
|
* output from sanitizePlatformIndependentPath(), so that it is in a known
|
|
* output from sanitizePlatformIndependentPath(), so that it is in a known
|
|
@@ -1371,6 +1393,7 @@ static int doDeinit(void)
|
|
archivers = NULL;
|
|
archivers = NULL;
|
|
} /* if */
|
|
} /* if */
|
|
|
|
|
|
|
|
+ longest_root = 0;
|
|
allowSymLinks = 0;
|
|
allowSymLinks = 0;
|
|
initialized = 0;
|
|
initialized = 0;
|
|
|
|
|
|
@@ -1677,6 +1700,54 @@ int PHYSFS_setWriteDir(const char *newDir)
|
|
} /* PHYSFS_setWriteDir */
|
|
} /* 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,
|
|
static int doMount(PHYSFS_Io *io, const char *fname,
|
|
const char *mountPoint, int appendToPath)
|
|
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
|
|
* 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.
|
|
* 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.
|
|
* Returns non-zero if string is safe, zero if there's a security issue.
|
|
* PHYSFS_getLastError() will specify what was wrong. (*fname) will be
|
|
* PHYSFS_getLastError() will specify what was wrong. (*fname) will be
|
|
* updated to point past any mount point elements so it is prepared to
|
|
* 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 *start;
|
|
char *end;
|
|
char *end;
|
|
|
|
|
|
- if (*fname == '\0') /* quick rejection. */
|
|
|
|
|
|
+ if ((*fname == '\0') && (!h->root)) /* quick rejection. */
|
|
return 1;
|
|
return 1;
|
|
|
|
|
|
/* !!! FIXME: This codeblock sucks. */
|
|
/* !!! FIXME: This codeblock sucks. */
|
|
@@ -2029,6 +2103,17 @@ static int verifyPath(DirHandle *h, char **_fname, int allowMissing)
|
|
retval = 1; /* may be reset, below. */
|
|
retval = 1; /* may be reset, below. */
|
|
} /* if */
|
|
} /* 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;
|
|
start = fname;
|
|
if (!allowSymLinks)
|
|
if (!allowSymLinks)
|
|
{
|
|
{
|
|
@@ -2074,20 +2159,19 @@ static int verifyPath(DirHandle *h, char **_fname, int allowMissing)
|
|
} /* verifyPath */
|
|
} /* verifyPath */
|
|
|
|
|
|
|
|
|
|
|
|
+/* This must hold the stateLock before calling. */
|
|
static int doMkdir(const char *_dname, char *dname)
|
|
static int doMkdir(const char *_dname, char *dname)
|
|
{
|
|
{
|
|
- DirHandle *h;
|
|
|
|
|
|
+ DirHandle *h = writeDir;
|
|
char *start;
|
|
char *start;
|
|
char *end;
|
|
char *end;
|
|
int retval = 0;
|
|
int retval = 0;
|
|
int exists = 1; /* force existance check on first path element. */
|
|
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;
|
|
start = dname;
|
|
while (1)
|
|
while (1)
|
|
@@ -2119,7 +2203,6 @@ static int doMkdir(const char *_dname, char *dname)
|
|
start = end + 1;
|
|
start = end + 1;
|
|
} /* while */
|
|
} /* while */
|
|
|
|
|
|
- __PHYSFS_platformReleaseMutex(stateLock);
|
|
|
|
return retval;
|
|
return retval;
|
|
} /* doMkdir */
|
|
} /* doMkdir */
|
|
|
|
|
|
@@ -2131,30 +2214,26 @@ int PHYSFS_mkdir(const char *_dname)
|
|
size_t len;
|
|
size_t len;
|
|
|
|
|
|
BAIL_IF(!_dname, PHYSFS_ERR_INVALID_ARGUMENT, 0);
|
|
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);
|
|
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);
|
|
retval = doMkdir(_dname, dname);
|
|
|
|
+ __PHYSFS_platformReleaseMutex(stateLock);
|
|
__PHYSFS_smallFree(dname);
|
|
__PHYSFS_smallFree(dname);
|
|
return retval;
|
|
return retval;
|
|
} /* PHYSFS_mkdir */
|
|
} /* PHYSFS_mkdir */
|
|
|
|
|
|
|
|
|
|
|
|
+/* This must hold the stateLock before calling. */
|
|
static int doDelete(const char *_fname, char *fname)
|
|
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 */
|
|
} /* doDelete */
|
|
|
|
|
|
|
|
|
|
@@ -2164,11 +2243,13 @@ int PHYSFS_delete(const char *_fname)
|
|
char *fname;
|
|
char *fname;
|
|
size_t len;
|
|
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);
|
|
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);
|
|
retval = doDelete(_fname, fname);
|
|
|
|
+ __PHYSFS_platformReleaseMutex(stateLock);
|
|
__PHYSFS_smallFree(fname);
|
|
__PHYSFS_smallFree(fname);
|
|
return retval;
|
|
return retval;
|
|
} /* PHYSFS_delete */
|
|
} /* PHYSFS_delete */
|
|
@@ -2177,17 +2258,20 @@ int PHYSFS_delete(const char *_fname)
|
|
static DirHandle *getRealDirHandle(const char *_fname)
|
|
static DirHandle *getRealDirHandle(const char *_fname)
|
|
{
|
|
{
|
|
DirHandle *retval = NULL;
|
|
DirHandle *retval = NULL;
|
|
|
|
+ char *allocated_fname = NULL;
|
|
char *fname = NULL;
|
|
char *fname = NULL;
|
|
size_t len;
|
|
size_t len;
|
|
|
|
|
|
BAIL_IF(!_fname, PHYSFS_ERR_INVALID_ARGUMENT, NULL);
|
|
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))
|
|
if (sanitizePlatformIndependentPath(_fname, fname))
|
|
{
|
|
{
|
|
DirHandle *i;
|
|
DirHandle *i;
|
|
- __PHYSFS_platformGrabMutex(stateLock);
|
|
|
|
for (i = searchPath; i != NULL; i = i->next)
|
|
for (i = searchPath; i != NULL; i = i->next)
|
|
{
|
|
{
|
|
char *arcfname = fname;
|
|
char *arcfname = fname;
|
|
@@ -2206,10 +2290,10 @@ static DirHandle *getRealDirHandle(const char *_fname)
|
|
} /* if */
|
|
} /* if */
|
|
} /* if */
|
|
} /* if */
|
|
} /* for */
|
|
} /* for */
|
|
- __PHYSFS_platformReleaseMutex(stateLock);
|
|
|
|
} /* if */
|
|
} /* if */
|
|
|
|
|
|
- __PHYSFS_smallFree(fname);
|
|
|
|
|
|
+ __PHYSFS_platformReleaseMutex(stateLock);
|
|
|
|
+ __PHYSFS_smallFree(allocated_fname);
|
|
return retval;
|
|
return retval;
|
|
} /* getRealDirHandle */
|
|
} /* getRealDirHandle */
|
|
|
|
|
|
@@ -2404,15 +2488,18 @@ int PHYSFS_enumerate(const char *_fn, PHYSFS_EnumerateCallback cb, void *data)
|
|
{
|
|
{
|
|
PHYSFS_EnumerateCallbackResult retval = PHYSFS_ENUM_OK;
|
|
PHYSFS_EnumerateCallbackResult retval = PHYSFS_ENUM_OK;
|
|
size_t len;
|
|
size_t len;
|
|
|
|
+ char *allocated_fname;
|
|
char *fname;
|
|
char *fname;
|
|
|
|
|
|
BAIL_IF(!_fn, PHYSFS_ERR_INVALID_ARGUMENT, 0);
|
|
BAIL_IF(!_fn, PHYSFS_ERR_INVALID_ARGUMENT, 0);
|
|
BAIL_IF(!cb, 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))
|
|
if (!sanitizePlatformIndependentPath(_fn, fname))
|
|
retval = PHYSFS_ENUM_STOP;
|
|
retval = PHYSFS_ENUM_STOP;
|
|
else
|
|
else
|
|
@@ -2420,8 +2507,6 @@ int PHYSFS_enumerate(const char *_fn, PHYSFS_EnumerateCallback cb, void *data)
|
|
DirHandle *i;
|
|
DirHandle *i;
|
|
SymlinkFilterData filterdata;
|
|
SymlinkFilterData filterdata;
|
|
|
|
|
|
- __PHYSFS_platformGrabMutex(stateLock);
|
|
|
|
-
|
|
|
|
if (!allowSymLinks)
|
|
if (!allowSymLinks)
|
|
{
|
|
{
|
|
memset(&filterdata, '\0', sizeof (filterdata));
|
|
memset(&filterdata, '\0', sizeof (filterdata));
|
|
@@ -2470,10 +2555,11 @@ int PHYSFS_enumerate(const char *_fn, PHYSFS_EnumerateCallback cb, void *data)
|
|
} /* else if */
|
|
} /* else if */
|
|
} /* for */
|
|
} /* for */
|
|
|
|
|
|
- __PHYSFS_platformReleaseMutex(stateLock);
|
|
|
|
} /* if */
|
|
} /* if */
|
|
|
|
|
|
- __PHYSFS_smallFree(fname);
|
|
|
|
|
|
+ __PHYSFS_platformReleaseMutex(stateLock);
|
|
|
|
+
|
|
|
|
+ __PHYSFS_smallFree(allocated_fname);
|
|
|
|
|
|
return (retval == PHYSFS_ENUM_ERROR) ? 0 : 1;
|
|
return (retval == PHYSFS_ENUM_ERROR) ? 0 : 1;
|
|
} /* PHYSFS_enumerate */
|
|
} /* PHYSFS_enumerate */
|
|
@@ -2534,57 +2620,58 @@ int PHYSFS_isSymbolicLink(const char *fname)
|
|
} /* PHYSFS_isSymbolicLink */
|
|
} /* PHYSFS_isSymbolicLink */
|
|
|
|
|
|
|
|
|
|
-static PHYSFS_File *doOpenWrite(const char *_fname, int appending)
|
|
|
|
|
|
+static PHYSFS_File *doOpenWrite(const char *_fname, const int appending)
|
|
{
|
|
{
|
|
FileHandle *fh = NULL;
|
|
FileHandle *fh = NULL;
|
|
|
|
+ DirHandle *h;
|
|
size_t len;
|
|
size_t len;
|
|
char *fname;
|
|
char *fname;
|
|
|
|
|
|
BAIL_IF(!_fname, PHYSFS_ERR_INVALID_ARGUMENT, 0);
|
|
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_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);
|
|
|
|
|
|
+ __PHYSFS_platformGrabMutex(stateLock);
|
|
|
|
|
|
- f = h->funcs;
|
|
|
|
- if (appending)
|
|
|
|
- io = f->openAppend(h->opaque, fname);
|
|
|
|
- else
|
|
|
|
- io = f->openWrite(h->opaque, fname);
|
|
|
|
|
|
+ h = writeDir;
|
|
|
|
+ BAIL_IF_MUTEX(!h, PHYSFS_ERR_NO_WRITE_DIR, stateLock, 0);
|
|
|
|
|
|
- GOTO_IF_ERRPASS(!io, doOpenWriteEnd);
|
|
|
|
|
|
+ len = strlen(_fname) + dirHandleRootLen(h) + 1;
|
|
|
|
+ fname = (char *) __PHYSFS_smallAlloc(len);
|
|
|
|
+ BAIL_IF_MUTEX(!fname, PHYSFS_ERR_OUT_OF_MEMORY, stateLock, 0);
|
|
|
|
|
|
- fh = (FileHandle *) allocator.Malloc(sizeof (FileHandle));
|
|
|
|
- if (fh == NULL)
|
|
|
|
- {
|
|
|
|
- io->destroy(io);
|
|
|
|
- GOTO(PHYSFS_ERR_OUT_OF_MEMORY, doOpenWriteEnd);
|
|
|
|
- } /* if */
|
|
|
|
- else
|
|
|
|
|
|
+ if (sanitizePlatformIndependentPathWithRoot(h, _fname, fname))
|
|
|
|
+ {
|
|
|
|
+ PHYSFS_Io *io = NULL;
|
|
|
|
+ char *arcfname = fname;
|
|
|
|
+ if (verifyPath(h, &arcfname, 0))
|
|
{
|
|
{
|
|
- memset(fh, '\0', sizeof (FileHandle));
|
|
|
|
- fh->io = io;
|
|
|
|
- fh->dirHandle = h;
|
|
|
|
- fh->next = openWriteList;
|
|
|
|
- openWriteList = fh;
|
|
|
|
- } /* else */
|
|
|
|
|
|
+ const PHYSFS_Archiver *f = h->funcs;
|
|
|
|
+ if (appending)
|
|
|
|
+ io = f->openAppend(h->opaque, arcfname);
|
|
|
|
+ else
|
|
|
|
+ io = f->openWrite(h->opaque, arcfname);
|
|
|
|
|
|
- doOpenWriteEnd:
|
|
|
|
- __PHYSFS_platformReleaseMutex(stateLock);
|
|
|
|
|
|
+ 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 */
|
|
} /* if */
|
|
} /* if */
|
|
|
|
|
|
|
|
+ __PHYSFS_platformReleaseMutex(stateLock);
|
|
|
|
+
|
|
__PHYSFS_smallFree(fname);
|
|
__PHYSFS_smallFree(fname);
|
|
return ((PHYSFS_File *) fh);
|
|
return ((PHYSFS_File *) fh);
|
|
} /* doOpenWrite */
|
|
} /* doOpenWrite */
|
|
@@ -2605,22 +2692,25 @@ PHYSFS_File *PHYSFS_openAppend(const char *filename)
|
|
PHYSFS_File *PHYSFS_openRead(const char *_fname)
|
|
PHYSFS_File *PHYSFS_openRead(const char *_fname)
|
|
{
|
|
{
|
|
FileHandle *fh = NULL;
|
|
FileHandle *fh = NULL;
|
|
|
|
+ char *allocated_fname;
|
|
char *fname;
|
|
char *fname;
|
|
size_t len;
|
|
size_t len;
|
|
|
|
|
|
BAIL_IF(!_fname, PHYSFS_ERR_INVALID_ARGUMENT, 0);
|
|
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))
|
|
if (sanitizePlatformIndependentPath(_fname, fname))
|
|
{
|
|
{
|
|
- DirHandle *i = NULL;
|
|
|
|
PHYSFS_Io *io = 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)
|
|
for (i = searchPath; i != NULL; i = i->next)
|
|
{
|
|
{
|
|
@@ -2633,27 +2723,26 @@ PHYSFS_File *PHYSFS_openRead(const char *_fname)
|
|
} /* if */
|
|
} /* if */
|
|
} /* for */
|
|
} /* 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);
|
|
|
|
- } /* if */
|
|
|
|
-
|
|
|
|
- memset(fh, '\0', sizeof (FileHandle));
|
|
|
|
- fh->io = io;
|
|
|
|
- fh->forReading = 1;
|
|
|
|
- fh->dirHandle = i;
|
|
|
|
- fh->next = openReadList;
|
|
|
|
- openReadList = fh;
|
|
|
|
|
|
+ fh = (FileHandle *) allocator.Malloc(sizeof (FileHandle));
|
|
|
|
+ if (fh == NULL)
|
|
|
|
+ {
|
|
|
|
+ io->destroy(io);
|
|
|
|
+ PHYSFS_setErrorCode(PHYSFS_ERR_OUT_OF_MEMORY);
|
|
|
|
+ } /* if */
|
|
|
|
|
|
- openReadEnd:
|
|
|
|
- __PHYSFS_platformReleaseMutex(stateLock);
|
|
|
|
|
|
+ memset(fh, '\0', sizeof (FileHandle));
|
|
|
|
+ fh->io = io;
|
|
|
|
+ fh->forReading = 1;
|
|
|
|
+ fh->dirHandle = i;
|
|
|
|
+ fh->next = openReadList;
|
|
|
|
+ openReadList = fh;
|
|
|
|
+ } /* if */
|
|
} /* if */
|
|
} /* if */
|
|
|
|
|
|
- __PHYSFS_smallFree(fname);
|
|
|
|
|
|
+ __PHYSFS_platformReleaseMutex(stateLock);
|
|
|
|
+ __PHYSFS_smallFree(allocated_fname);
|
|
return ((PHYSFS_File *) fh);
|
|
return ((PHYSFS_File *) fh);
|
|
} /* PHYSFS_openRead */
|
|
} /* PHYSFS_openRead */
|
|
|
|
|
|
@@ -2662,7 +2751,6 @@ static int closeHandleInOpenList(FileHandle **list, FileHandle *handle)
|
|
{
|
|
{
|
|
FileHandle *prev = NULL;
|
|
FileHandle *prev = NULL;
|
|
FileHandle *i;
|
|
FileHandle *i;
|
|
- int rc = 1;
|
|
|
|
|
|
|
|
for (i = *list; i != NULL; i = i->next)
|
|
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_Io *io = handle->io;
|
|
PHYSFS_uint8 *tmp = handle->buffer;
|
|
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);
|
|
io->destroy(io);
|
|
|
|
|
|
if (tmp != NULL) /* free any associated buffer. */
|
|
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);
|
|
rc = io->write(io, fh->buffer + fh->bufpos, fh->buffill - fh->bufpos);
|
|
BAIL_IF_ERRPASS(rc <= 0, 0);
|
|
BAIL_IF_ERRPASS(rc <= 0, 0);
|
|
fh->bufpos = fh->buffill = 0;
|
|
fh->bufpos = fh->buffill = 0;
|
|
- return io->flush ? io->flush(io) : 1;
|
|
|
|
|
|
+ return 1;
|
|
} /* PHYSFS_flush */
|
|
} /* PHYSFS_flush */
|
|
|
|
|
|
|
|
|
|
int PHYSFS_stat(const char *_fname, PHYSFS_Stat *stat)
|
|
int PHYSFS_stat(const char *_fname, PHYSFS_Stat *stat)
|
|
{
|
|
{
|
|
int retval = 0;
|
|
int retval = 0;
|
|
|
|
+ char *allocated_fname;
|
|
char *fname;
|
|
char *fname;
|
|
size_t len;
|
|
size_t len;
|
|
|
|
|
|
BAIL_IF(!_fname, PHYSFS_ERR_INVALID_ARGUMENT, 0);
|
|
BAIL_IF(!_fname, PHYSFS_ERR_INVALID_ARGUMENT, 0);
|
|
BAIL_IF(!stat, 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... */
|
|
/* set some sane defaults... */
|
|
stat->filesize = -1;
|
|
stat->filesize = -1;
|
|
@@ -2994,6 +3090,12 @@ int PHYSFS_stat(const char *_fname, PHYSFS_Stat *stat)
|
|
stat->filetype = PHYSFS_FILETYPE_OTHER;
|
|
stat->filetype = PHYSFS_FILETYPE_OTHER;
|
|
stat->readonly = 1;
|
|
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 (sanitizePlatformIndependentPath(_fname, fname))
|
|
{
|
|
{
|
|
if (*fname == '\0')
|
|
if (*fname == '\0')
|
|
@@ -3006,7 +3108,6 @@ int PHYSFS_stat(const char *_fname, PHYSFS_Stat *stat)
|
|
{
|
|
{
|
|
DirHandle *i;
|
|
DirHandle *i;
|
|
int exists = 0;
|
|
int exists = 0;
|
|
- __PHYSFS_platformGrabMutex(stateLock);
|
|
|
|
for (i = searchPath; ((i != NULL) && (!exists)); i = i->next)
|
|
for (i = searchPath; ((i != NULL) && (!exists)); i = i->next)
|
|
{
|
|
{
|
|
char *arcfname = fname;
|
|
char *arcfname = fname;
|
|
@@ -3024,11 +3125,11 @@ int PHYSFS_stat(const char *_fname, PHYSFS_Stat *stat)
|
|
exists = 1;
|
|
exists = 1;
|
|
} /* else if */
|
|
} /* else if */
|
|
} /* for */
|
|
} /* for */
|
|
- __PHYSFS_platformReleaseMutex(stateLock);
|
|
|
|
} /* else */
|
|
} /* else */
|
|
} /* if */
|
|
} /* if */
|
|
|
|
|
|
- __PHYSFS_smallFree(fname);
|
|
|
|
|
|
+ __PHYSFS_platformReleaseMutex(stateLock);
|
|
|
|
+ __PHYSFS_smallFree(allocated_fname);
|
|
return retval;
|
|
return retval;
|
|
} /* PHYSFS_stat */
|
|
} /* PHYSFS_stat */
|
|
|
|
|