Added PHYSFS_setRoot().
This commit is contained in:
parent
7d194a8a62
commit
73d66441e3
300
src/physfs.c
300
src/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 int longest_root = 0;
|
||||
|
||||
/* mutexes ... */
|
||||
static void *errorLock = NULL; /* protects error message list. */
|
||||
|
@ -980,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
|
||||
|
@ -1378,6 +1393,7 @@ static int doDeinit(void)
|
|||
archivers = NULL;
|
||||
} /* if */
|
||||
|
||||
longest_root = 0;
|
||||
allowSymLinks = 0;
|
||||
initialized = 0;
|
||||
|
||||
|
@ -1684,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)
|
||||
{
|
||||
|
@ -2001,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
|
||||
|
@ -2013,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. */
|
||||
|
@ -2036,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)
|
||||
{
|
||||
|
@ -2081,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)
|
||||
|
@ -2126,7 +2203,6 @@ static int doMkdir(const char *_dname, char *dname)
|
|||
start = end + 1;
|
||||
} /* while */
|
||||
|
||||
__PHYSFS_platformReleaseMutex(stateLock);
|
||||
return retval;
|
||||
} /* doMkdir */
|
||||
|
||||
|
@ -2138,30 +2214,27 @@ 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 */
|
||||
|
||||
|
||||
|
@ -2171,11 +2244,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 */
|
||||
|
@ -2184,17 +2259,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;
|
||||
|
@ -2213,10 +2291,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 */
|
||||
|
||||
|
@ -2411,15 +2489,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
|
||||
|
@ -2427,8 +2508,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));
|
||||
|
@ -2477,10 +2556,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 */
|
||||
|
@ -2541,57 +2621,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 */
|
||||
|
@ -2612,22 +2693,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)
|
||||
{
|
||||
|
@ -2640,27 +2724,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 */
|
||||
|
||||
|
@ -2984,14 +3067,12 @@ int PHYSFS_flush(PHYSFS_File *handle)
|
|||
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;
|
||||
|
@ -3001,6 +3082,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')
|
||||
|
@ -3013,7 +3100,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;
|
||||
|
@ -3031,11 +3117,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 */
|
||||
|
||||
|
|
40
src/physfs.h
40
src/physfs.h
|
@ -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
|
||||
|
|
|
@ -288,6 +288,53 @@ static int cmd_getmountpoint(char *args)
|
|||
return 1;
|
||||
} /* cmd_getmountpoint */
|
||||
|
||||
|
||||
static int cmd_setroot(char *args)
|
||||
{
|
||||
char *archive;
|
||||
char *subdir;
|
||||
char *ptr;
|
||||
|
||||
archive = args;
|
||||
if (*archive == '\"')
|
||||
{
|
||||
archive++;
|
||||
ptr = strchr(archive, '\"');
|
||||
if (ptr == NULL)
|
||||
{
|
||||
printf("missing string terminator in argument.\n");
|
||||
return 1;
|
||||
} /* if */
|
||||
*(ptr) = '\0';
|
||||
} /* if */
|
||||
else
|
||||
{
|
||||
ptr = strchr(archive, ' ');
|
||||
*ptr = '\0';
|
||||
} /* else */
|
||||
|
||||
subdir = ptr + 1;
|
||||
if (*subdir == '\"')
|
||||
{
|
||||
subdir++;
|
||||
ptr = strchr(subdir, '\"');
|
||||
if (ptr == NULL)
|
||||
{
|
||||
printf("missing string terminator in argument.\n");
|
||||
return 1;
|
||||
} /* if */
|
||||
*(ptr) = '\0';
|
||||
} /* if */
|
||||
|
||||
if (PHYSFS_setRoot(archive, subdir))
|
||||
printf("Successful.\n");
|
||||
else
|
||||
printf("Failure. reason: %s.\n", PHYSFS_getLastError());
|
||||
|
||||
return 1;
|
||||
} /* cmd_setroot */
|
||||
|
||||
|
||||
static int cmd_removearchive(char *args)
|
||||
{
|
||||
if (*args == '\"')
|
||||
|
@ -1340,6 +1387,7 @@ static const command_info commands[] =
|
|||
{ "stressbuffer", cmd_stressbuffer, 1, "<bufferSize>" },
|
||||
{ "crc32", cmd_crc32, 1, "<fileToHash>" },
|
||||
{ "getmountpoint", cmd_getmountpoint, 1, "<dir>" },
|
||||
{ "setroot", cmd_setroot, 2, "<archiveLocation> <root>" },
|
||||
{ NULL, NULL, -1, NULL }
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue