@ -12,8 +12,6 @@
# include "physfs_internal.h"
# include "physfs_internal.h"
# if defined(_MSC_VER)
# if defined(_MSC_VER)
# include <stdarg.h>
/* this code came from https://stackoverflow.com/a/8712996 */
/* this code came from https://stackoverflow.com/a/8712996 */
int __PHYSFS_msvc_vsnprintf ( char * outBuf , size_t size , const char * format , va_list ap )
int __PHYSFS_msvc_vsnprintf ( char * outBuf , size_t size , const char * format , va_list ap )
{
{
@ -46,6 +44,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 +86,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. */
@ -101,8 +102,8 @@ static inline int __PHYSFS_atomicAdd(int *ptrval, const int val)
{
{
int retval ;
int retval ;
__PHYSFS_platformGrabMutex ( stateLock ) ;
__PHYSFS_platformGrabMutex ( stateLock ) ;
* ptrval + = val ;
retval = * ptrval ;
retval = * ptrval ;
* ptrval = retval + val ;
__PHYSFS_platformReleaseMutex ( stateLock ) ;
__PHYSFS_platformReleaseMutex ( stateLock ) ;
return retval ;
return retval ;
} /* __PHYSFS_atomicAdd */
} /* __PHYSFS_atomicAdd */
@ -920,12 +921,12 @@ static DirHandle *openDirectory(PHYSFS_Io *io, const char *d, int forWriting)
retval = tryOpenDir ( io , * i , d , forWriting , & claimed ) ;
retval = tryOpenDir ( io , * i , d , forWriting , & claimed ) ;
} /* else */
} /* else */
errcode = currentErrorCode ( ) ;
errcode = claimed ? c urrentErrorCode ( ) : PHYSFS_ERR_UNSUPPORTED ;
if ( ( ! retval ) & & ( created_io ) )
if ( ( ! retval ) & & ( created_io ) )
io - > destroy ( io ) ;
io - > destroy ( io ) ;
BAIL_IF ( ! retval , claimed ? errcode : PHYSFS_ERR_UNSUPPORTED , NULL ) ;
BAIL_IF ( ! retval , errcode , NULL ) ;
return retval ;
return retval ;
} /* openDirectory */
} /* openDirectory */
@ -980,6 +981,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
@ -1080,6 +1093,8 @@ static int freeDirHandle(DirHandle *dh, FileHandle *openList)
BAIL_IF ( i - > dirHandle = = dh , PHYSFS_ERR_FILES_STILL_OPEN , 0 ) ;
BAIL_IF ( i - > dirHandle = = dh , PHYSFS_ERR_FILES_STILL_OPEN , 0 ) ;
dh - > funcs - > closeArchive ( dh - > opaque ) ;
dh - > funcs - > closeArchive ( dh - > opaque ) ;
if ( dh - > root ) allocator . Free ( dh - > root ) ;
allocator . Free ( dh - > dirName ) ;
allocator . Free ( dh - > dirName ) ;
allocator . Free ( dh - > mountPoint ) ;
allocator . Free ( dh - > mountPoint ) ;
allocator . Free ( dh ) ;
allocator . Free ( dh ) ;
@ -1218,7 +1233,9 @@ int PHYSFS_init(const char *argv0)
if ( ! userDir ) goto initFailed ;
if ( ! userDir ) goto initFailed ;
/* Platform layer is required to append a dirsep. */
/* Platform layer is required to append a dirsep. */
# ifndef __ANDROID__ /* it's an APK file, not a directory, on Android. */
assert ( baseDir [ strlen ( baseDir ) - 1 ] = = __PHYSFS_platformDirSeparator ) ;
assert ( baseDir [ strlen ( baseDir ) - 1 ] = = __PHYSFS_platformDirSeparator ) ;
# endif
assert ( userDir [ strlen ( userDir ) - 1 ] = = __PHYSFS_platformDirSeparator ) ;
assert ( userDir [ strlen ( userDir ) - 1 ] = = __PHYSFS_platformDirSeparator ) ;
if ( ! initStaticArchivers ( ) ) goto initFailed ;
if ( ! initStaticArchivers ( ) ) goto initFailed ;
@ -1378,6 +1395,7 @@ static int doDeinit(void)
archivers = NULL ;
archivers = NULL ;
} /* if */
} /* if */
longest_root = 0 ;
allowSymLinks = 0 ;
allowSymLinks = 0 ;
initialized = 0 ;
initialized = 0 ;
@ -1417,15 +1435,60 @@ char *__PHYSFS_strdup(const char *str)
} /* __PHYSFS_strdup */
} /* __PHYSFS_strdup */
PHYSFS_uint32 __PHYSFS_hashString ( const char * str , size_t len )
PHYSFS_uint32 __PHYSFS_hashString ( const char * str )
{
{
PHYSFS_uint32 hash = 5381 ;
PHYSFS_uint32 hash = 5381 ;
while ( len - - )
hash = ( ( hash < < 5 ) + hash ) ^ * ( str + + ) ;
while ( 1 )
{
const char ch = * ( str + + ) ;
if ( ch = = 0 )
break ;
hash = ( ( hash < < 5 ) + hash ) ^ ch ;
} /* while */
return hash ;
return hash ;
} /* __PHYSFS_hashString */
} /* __PHYSFS_hashString */
PHYSFS_uint32 __PHYSFS_hashStringCaseFold ( const char * str )
{
PHYSFS_uint32 hash = 5381 ;
while ( 1 )
{
const PHYSFS_uint32 cp = __PHYSFS_utf8codepoint ( & str ) ;
if ( cp = = 0 )
break ;
else
{
PHYSFS_uint32 folded [ 3 ] ;
const int numbytes = ( int ) ( PHYSFS_caseFold ( cp , folded ) * sizeof ( PHYSFS_uint32 ) ) ;
const char * bytes = ( const char * ) folded ;
int i ;
for ( i = 0 ; i < numbytes ; i + + )
hash = ( ( hash < < 5 ) + hash ) ^ * ( bytes + + ) ;
} /* else */
} /* while */
return hash ;
} /* __PHYSFS_hashStringCaseFold */
PHYSFS_uint32 __PHYSFS_hashStringCaseFoldUSAscii ( const char * str )
{
PHYSFS_uint32 hash = 5381 ;
while ( 1 )
{
char ch = * ( str + + ) ;
if ( ch = = 0 )
break ;
else if ( ( ch > = ' A ' ) & & ( ch < = ' Z ' ) )
ch - = ( ' A ' - ' a ' ) ;
hash = ( ( hash < < 5 ) + hash ) ^ ch ;
} /* while */
return hash ;
} /* __PHYSFS_hashStringCaseFoldUSAscii */
/* MAKE SURE you hold stateLock before calling this! */
/* MAKE SURE you hold stateLock before calling this! */
static int doRegisterArchiver ( const PHYSFS_Archiver * _archiver )
static int doRegisterArchiver ( const PHYSFS_Archiver * _archiver )
{
{
@ -1684,6 +1747,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 = strlen ( i - > root ) ; /* in case sanitizePlatformIndependentPath changed subdir */
if ( longest_root < i - > rootlen )
longest_root = i - > rootlen ;
} /* 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 )
{
{
@ -2001,6 +2112,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
@ -2013,7 +2127,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. */
@ -2036,6 +2150,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 + ( isempty ? 0 : 1 ) ;
strcpy ( fname , h - > root ) ;
if ( ! isempty )
fname [ h - > rootlen ] = ' / ' ;
* _fname = fname ;
} /* if */
start = fname ;
start = fname ;
if ( ! allowSymLinks )
if ( ! allowSymLinks )
{
{
@ -2081,20 +2206,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 )
@ -2110,7 +2234,12 @@ static int doMkdir(const char *_dname, char *dname)
const int rc = h - > funcs - > stat ( h - > opaque , dname , & statbuf ) ;
const int rc = h - > funcs - > stat ( h - > opaque , dname , & statbuf ) ;
if ( ( ! rc ) & & ( currentErrorCode ( ) = = PHYSFS_ERR_NOT_FOUND ) )
if ( ( ! rc ) & & ( currentErrorCode ( ) = = PHYSFS_ERR_NOT_FOUND ) )
exists = 0 ;
exists = 0 ;
retval = ( ( rc ) & & ( statbuf . filetype = = PHYSFS_FILETYPE_DIRECTORY ) ) ;
/* verifyPath made sure that (dname) doesn't have symlinks if they aren't
allowed , but it ' s possible the mounted writeDir itself has symlinks in it ,
( for example " /var " on iOS is a symlink , and the prefpath will be somewhere
under that ) . . . if we mounted that writeDir , we must allow those symlinks here
unconditionally . */
retval = ( ( rc ) & & ( ( statbuf . filetype = = PHYSFS_FILETYPE_DIRECTORY ) | | ( statbuf . filetype = = PHYSFS_FILETYPE_SYMLINK ) ) ) ;
} /* if */
} /* if */
if ( ! exists )
if ( ! exists )
@ -2126,7 +2255,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 */
@ -2138,30 +2266,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 */
@ -2171,11 +2295,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 */
@ -2184,17 +2310,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 + 2 ;
allocated_fname = __PHYSFS_smallAlloc ( len ) ;
BAIL_IF_MUTEX ( ! allocated_fname , PHYSFS_ERR_OUT_OF_MEMORY , stateLock , NULL ) ;
fname = allocated_fname + longest_root + 1 ;
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 ;
@ -2213,10 +2342,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 */
@ -2411,15 +2540,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 + 2 ;
allocated_fname = ( char * ) __PHYSFS_smallAlloc ( len ) ;
BAIL_IF_MUTEX ( ! allocated_fname , PHYSFS_ERR_OUT_OF_MEMORY , stateLock , 0 ) ;
fname = allocated_fname + longest_root + 1 ;
if ( ! sanitizePlatformIndependentPath ( _fn , fname ) )
if ( ! sanitizePlatformIndependentPath ( _fn , fname ) )
retval = PHYSFS_ENUM_STOP ;
retval = PHYSFS_ENUM_STOP ;
else
else
@ -2427,8 +2559,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 ) ) ;
@ -2477,10 +2607,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 */
@ -2541,57 +2672,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 */
@ -2612,22 +2744,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 + 2 ;
allocated_fname = ( char * ) __PHYSFS_smallAlloc ( len ) ;
BAIL_IF_MUTEX ( ! allocated_fname , PHYSFS_ERR_OUT_OF_MEMORY , stateLock , 0 ) ;
fname = allocated_fname + longest_root + 1 ;
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 )
{
{
@ -2640,27 +2775,28 @@ 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 ) ;
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 - > forReading = 1 ;
fh - > dirHandle = i ;
fh - > next = openReadList ;
openReadList = fh ;
} /* else */
} /* if */
} /* 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 */
} /* if */
__PHYSFS_smallFree ( fname ) ;
__PHYSFS_platformReleaseMutex ( stateLock ) ;
__PHYSFS_smallFree ( allocated_fname ) ;
return ( ( PHYSFS_File * ) fh ) ;
return ( ( PHYSFS_File * ) fh ) ;
} /* PHYSFS_openRead */
} /* PHYSFS_openRead */
@ -2993,14 +3129,12 @@ int PHYSFS_flush(PHYSFS_File *handle)
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 ;
@ -3010,6 +3144,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 + 2 ;
allocated_fname = ( char * ) __PHYSFS_smallAlloc ( len ) ;
BAIL_IF_MUTEX ( ! allocated_fname , PHYSFS_ERR_OUT_OF_MEMORY , stateLock , 0 ) ;
fname = allocated_fname + longest_root + 1 ;
if ( sanitizePlatformIndependentPath ( _fname , fname ) )
if ( sanitizePlatformIndependentPath ( _fname , fname ) )
{
{
if ( * fname = = ' \0 ' )
if ( * fname = = ' \0 ' )
@ -3022,7 +3162,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 ;
@ -3040,11 +3179,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 */
@ -3142,7 +3281,7 @@ static void setDefaultAllocator(void)
} /* setDefaultAllocator */
} /* setDefaultAllocator */
int __PHYSFS_DirTreeInit ( __PHYSFS_DirTree * dt , const size_t entrylen )
int __PHYSFS_DirTreeInit ( __PHYSFS_DirTree * dt , const size_t entrylen , const int case_sensitive , const int only_usascii )
{
{
static char rootpath [ 2 ] = { ' / ' , ' \0 ' } ;
static char rootpath [ 2 ] = { ' / ' , ' \0 ' } ;
size_t alloclen ;
size_t alloclen ;
@ -3150,6 +3289,8 @@ int __PHYSFS_DirTreeInit(__PHYSFS_DirTree *dt, const size_t entrylen)
assert ( entrylen > = sizeof ( __PHYSFS_DirTreeEntry ) ) ;
assert ( entrylen > = sizeof ( __PHYSFS_DirTreeEntry ) ) ;
memset ( dt , ' \0 ' , sizeof ( * dt ) ) ;
memset ( dt , ' \0 ' , sizeof ( * dt ) ) ;
dt - > case_sensitive = case_sensitive ;
dt - > only_usascii = only_usascii ;
dt - > root = ( __PHYSFS_DirTreeEntry * ) allocator . Malloc ( entrylen ) ;
dt - > root = ( __PHYSFS_DirTreeEntry * ) allocator . Malloc ( entrylen ) ;
BAIL_IF ( ! dt - > root , PHYSFS_ERR_OUT_OF_MEMORY , 0 ) ;
BAIL_IF ( ! dt - > root , PHYSFS_ERR_OUT_OF_MEMORY , 0 ) ;
@ -3170,9 +3311,10 @@ int __PHYSFS_DirTreeInit(__PHYSFS_DirTree *dt, const size_t entrylen)
} /* __PHYSFS_DirTreeInit */
} /* __PHYSFS_DirTreeInit */
static inline PHYSFS_uint32 hashPathName ( __PHYSFS_DirTree * dt , const char * name )
static PHYSFS_uint32 hashPathName ( __PHYSFS_DirTree * dt , const char * name )
{
{
return __PHYSFS_hashString ( name , strlen ( name ) ) % dt - > hashBuckets ;
const PHYSFS_uint32 hashval = dt - > case_sensitive ? __PHYSFS_hashString ( name ) : dt - > only_usascii ? __PHYSFS_hashStringCaseFoldUSAscii ( name ) : __PHYSFS_hashStringCaseFold ( name ) ;
return hashval % dt - > hashBuckets ;
} /* hashPathName */
} /* hashPathName */
@ -3233,6 +3375,7 @@ void *__PHYSFS_DirTreeAdd(__PHYSFS_DirTree *dt, char *name, const int isdir)
/* Find the __PHYSFS_DirTreeEntry for a path in platform-independent notation. */
/* Find the __PHYSFS_DirTreeEntry for a path in platform-independent notation. */
void * __PHYSFS_DirTreeFind ( __PHYSFS_DirTree * dt , const char * path )
void * __PHYSFS_DirTreeFind ( __PHYSFS_DirTree * dt , const char * path )
{
{
const int cs = dt - > case_sensitive ;
PHYSFS_uint32 hashval ;
PHYSFS_uint32 hashval ;
__PHYSFS_DirTreeEntry * prev = NULL ;
__PHYSFS_DirTreeEntry * prev = NULL ;
__PHYSFS_DirTreeEntry * retval ;
__PHYSFS_DirTreeEntry * retval ;
@ -3243,7 +3386,8 @@ void *__PHYSFS_DirTreeFind(__PHYSFS_DirTree *dt, const char *path)
hashval = hashPathName ( dt , path ) ;
hashval = hashPathName ( dt , path ) ;
for ( retval = dt - > hash [ hashval ] ; retval ; retval = retval - > hashnext )
for ( retval = dt - > hash [ hashval ] ; retval ; retval = retval - > hashnext )
{
{
if ( strcmp ( retval - > name , path ) = = 0 )
const int cmp = cs ? strcmp ( retval - > name , path ) : PHYSFS_utf8stricmp ( retval - > name , path ) ;
if ( cmp = = 0 )
{
{
if ( prev ! = NULL ) /* move this to the front of the list */
if ( prev ! = NULL ) /* move this to the front of the list */
{
{