Compare commits
7 Commits
main
...
release-3.
Author | SHA1 | Date |
---|---|---|
Ryan C. Gordon | 9ea364e46e | |
Ryan C. Gordon | 179bd1d40a | |
Ryan C. Gordon | a80261989e | |
Ryan C. Gordon | b8aa7dab87 | |
Ryan C. Gordon | b9fd9e8100 | |
Ryan C. Gordon | e290b8d0a0 | |
Ryan C. Gordon | 12b7a80640 |
|
@ -12,7 +12,7 @@
|
|||
cmake_minimum_required(VERSION 2.8.4)
|
||||
|
||||
project(PhysicsFS)
|
||||
set(PHYSFS_VERSION 3.0.0)
|
||||
set(PHYSFS_VERSION 3.0.1)
|
||||
|
||||
# Increment this if/when we break backwards compatibility.
|
||||
set(PHYSFS_SOVERSION 1)
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
The API documentation is readable in a few ways:
|
||||
|
||||
- Read physfs.h; it's _heavily_ documented and the primary source of reference
|
||||
documentation for the library.
|
||||
- Run Doxygen over the header, which produces nicer-to-browse documentation in
|
||||
HTML, LaTeX, manpage, etc formats. This is done for you if Doxygen is
|
||||
installed and you build the "docs" target in whatever project files CMake
|
||||
generated for you.
|
||||
- Too much trouble? We generated the HTML reference for you, online here:
|
||||
|
||||
https://icculus.org/physfs/docs/
|
||||
|
||||
- We would love well-written tutorials for the latest version of PhysicsFS!
|
||||
If you write one, we would love to list it here. Drop me a line about it:
|
||||
icculus@icculus.org ... Thanks!
|
||||
|
||||
--ryan.
|
||||
|
28
src/physfs.c
28
src/physfs.c
|
@ -939,6 +939,10 @@ static int sanitizePlatformIndependentPath(const char *src, char *dst)
|
|||
while (*src == '/') /* skip initial '/' chars... */
|
||||
src++;
|
||||
|
||||
/* Make sure the entire string isn't "." or ".." */
|
||||
if ((strcmp(src, ".") == 0) || (strcmp(src, "..") == 0))
|
||||
BAIL(PHYSFS_ERR_BAD_FILENAME, 0);
|
||||
|
||||
prev = dst;
|
||||
do
|
||||
{
|
||||
|
@ -1012,6 +1016,8 @@ static DirHandle *createDirHandle(PHYSFS_Io *io, const char *newDir,
|
|||
DirHandle *dirHandle = NULL;
|
||||
char *tmpmntpnt = NULL;
|
||||
|
||||
assert(newDir != NULL); /* should have caught this higher up. */
|
||||
|
||||
if (mountPoint != NULL)
|
||||
{
|
||||
const size_t len = strlen(mountPoint) + 1;
|
||||
|
@ -1025,15 +1031,9 @@ static DirHandle *createDirHandle(PHYSFS_Io *io, const char *newDir,
|
|||
dirHandle = openDirectory(io, newDir, forWriting);
|
||||
GOTO_IF_ERRPASS(!dirHandle, badDirHandle);
|
||||
|
||||
if (newDir == NULL)
|
||||
dirHandle->dirName = NULL;
|
||||
else
|
||||
{
|
||||
dirHandle->dirName = (char *) allocator.Malloc(strlen(newDir) + 1);
|
||||
if (!dirHandle->dirName)
|
||||
GOTO(PHYSFS_ERR_OUT_OF_MEMORY, badDirHandle);
|
||||
GOTO_IF(!dirHandle->dirName, PHYSFS_ERR_OUT_OF_MEMORY, badDirHandle);
|
||||
strcpy(dirHandle->dirName, newDir);
|
||||
} /* else */
|
||||
|
||||
if ((mountPoint != NULL) && (*mountPoint != '\0'))
|
||||
{
|
||||
|
@ -1599,7 +1599,7 @@ const char *PHYSFS_getPrefDir(const char *org, const char *app)
|
|||
assert(*endstr == dirsep);
|
||||
*endstr = '\0'; /* mask out the final dirsep for now. */
|
||||
|
||||
if (!__PHYSFS_platformStat(prefDir, &statbuf))
|
||||
if (!__PHYSFS_platformStat(prefDir, &statbuf, 1))
|
||||
{
|
||||
for (ptr = strchr(prefDir, dirsep); ptr; ptr = strchr(ptr+1, dirsep))
|
||||
{
|
||||
|
@ -1684,13 +1684,13 @@ static int doMount(PHYSFS_Io *io, const char *fname,
|
|||
DirHandle *prev = NULL;
|
||||
DirHandle *i;
|
||||
|
||||
BAIL_IF(!fname, PHYSFS_ERR_INVALID_ARGUMENT, 0);
|
||||
|
||||
if (mountPoint == NULL)
|
||||
mountPoint = "/";
|
||||
|
||||
__PHYSFS_platformGrabMutex(stateLock);
|
||||
|
||||
if (fname != NULL)
|
||||
{
|
||||
for (i = searchPath; i != NULL; i = i->next)
|
||||
{
|
||||
/* already in search path? */
|
||||
|
@ -1698,7 +1698,6 @@ static int doMount(PHYSFS_Io *io, const char *fname,
|
|||
BAIL_MUTEX_ERRPASS(stateLock, 1);
|
||||
prev = i;
|
||||
} /* for */
|
||||
} /* if */
|
||||
|
||||
dh = createDirHandle(io, fname, mountPoint, 0);
|
||||
BAIL_IF_MUTEX_ERRPASS(!dh, stateLock, 0);
|
||||
|
@ -1725,6 +1724,7 @@ int PHYSFS_mountIo(PHYSFS_Io *io, const char *fname,
|
|||
const char *mountPoint, int appendToPath)
|
||||
{
|
||||
BAIL_IF(!io, PHYSFS_ERR_INVALID_ARGUMENT, 0);
|
||||
BAIL_IF(!fname, PHYSFS_ERR_INVALID_ARGUMENT, 0);
|
||||
BAIL_IF(io->version != 0, PHYSFS_ERR_UNSUPPORTED, 0);
|
||||
return doMount(io, fname, mountPoint, appendToPath);
|
||||
} /* PHYSFS_mountIo */
|
||||
|
@ -1738,6 +1738,7 @@ int PHYSFS_mountMemory(const void *buf, PHYSFS_uint64 len, void (*del)(void *),
|
|||
PHYSFS_Io *io = NULL;
|
||||
|
||||
BAIL_IF(!buf, PHYSFS_ERR_INVALID_ARGUMENT, 0);
|
||||
BAIL_IF(!fname, PHYSFS_ERR_INVALID_ARGUMENT, 0);
|
||||
|
||||
io = __PHYSFS_createMemoryIo(buf, len, del);
|
||||
BAIL_IF_ERRPASS(!io, 0);
|
||||
|
@ -1760,7 +1761,8 @@ int PHYSFS_mountHandle(PHYSFS_File *file, const char *fname,
|
|||
int retval = 0;
|
||||
PHYSFS_Io *io = NULL;
|
||||
|
||||
BAIL_IF(file == NULL, PHYSFS_ERR_INVALID_ARGUMENT, 0);
|
||||
BAIL_IF(!file, PHYSFS_ERR_INVALID_ARGUMENT, 0);
|
||||
BAIL_IF(!fname, PHYSFS_ERR_INVALID_ARGUMENT, 0);
|
||||
|
||||
io = __PHYSFS_createHandleIo(file);
|
||||
BAIL_IF_ERRPASS(!io, 0);
|
||||
|
@ -1785,7 +1787,7 @@ int PHYSFS_mount(const char *newDir, const char *mountPoint, int appendToPath)
|
|||
|
||||
int PHYSFS_addToSearchPath(const char *newDir, int appendToPath)
|
||||
{
|
||||
return doMount(NULL, newDir, NULL, appendToPath);
|
||||
return PHYSFS_mount(newDir, NULL, appendToPath);
|
||||
} /* PHYSFS_addToSearchPath */
|
||||
|
||||
|
||||
|
|
71
src/physfs.h
71
src/physfs.h
|
@ -434,7 +434,7 @@ typedef struct PHYSFS_Version
|
|||
#ifndef DOXYGEN_SHOULD_IGNORE_THIS
|
||||
#define PHYSFS_VER_MAJOR 3
|
||||
#define PHYSFS_VER_MINOR 0
|
||||
#define PHYSFS_VER_PATCH 0
|
||||
#define PHYSFS_VER_PATCH 1
|
||||
#endif /* DOXYGEN_SHOULD_IGNORE_THIS */
|
||||
|
||||
|
||||
|
@ -2176,11 +2176,15 @@ PHYSFS_DECL int PHYSFS_setAllocator(const PHYSFS_Allocator *allocator);
|
|||
* 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.
|
||||
* than those familiar with the Unix concept of "mounting" may 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.
|
||||
*
|
||||
* Specifying a symbolic link to an archive or directory is allowed here,
|
||||
* regardless of the state of PHYSFS_permitSymbolicLinks(). That function
|
||||
* only deals with symlinks inside the mounted directory or archive.
|
||||
*
|
||||
* \param newDir directory or archive to add to the path, in
|
||||
* platform-dependent notation.
|
||||
* \param mountPoint Location in the interpolated tree that this archive
|
||||
|
@ -2760,6 +2764,12 @@ PHYSFS_DECL int PHYSFS_enumerate(const char *dir, PHYSFS_EnumerateCallback c,
|
|||
* This call will fail (and fail to remove from the path) if the element still
|
||||
* has files open in it.
|
||||
*
|
||||
* \warning This function wants the path to the archive or directory that was
|
||||
* mounted (the same string used for the "newDir" argument of
|
||||
* PHYSFS_addToSearchPath or any of the mount functions), not the
|
||||
* path where it is mounted in the tree (the "mountPoint" argument
|
||||
* to any of the mount functions).
|
||||
*
|
||||
* \param oldDir dir/archive to remove.
|
||||
* \return nonzero on success, zero on failure. Use
|
||||
* PHYSFS_getLastErrorCode() to obtain the specific error.
|
||||
|
@ -3188,7 +3198,7 @@ typedef struct PHYSFS_Io
|
|||
|
||||
|
||||
/**
|
||||
* \fn int PHYSFS_mountIo(PHYSFS_Io *io, const char *fname, const char *mountPoint, int appendToPath)
|
||||
* \fn int PHYSFS_mountIo(PHYSFS_Io *io, const char *newDir, const char *mountPoint, int appendToPath)
|
||||
* \brief Add an archive, built on a PHYSFS_Io, to the search path.
|
||||
*
|
||||
* \warning Unless you have some special, low-level need, you should be using
|
||||
|
@ -3198,11 +3208,14 @@ typedef struct PHYSFS_Io
|
|||
* instead of a pathname. Behind the scenes, PHYSFS_mount() calls this
|
||||
* function with a physical-filesystem-based PHYSFS_Io.
|
||||
*
|
||||
* (filename) is only used here to optimize archiver selection (if you name it
|
||||
* XXXXX.zip, we might try the ZIP archiver first, for example). It doesn't
|
||||
* need to refer to a real file at all, and can even be NULL. If the filename
|
||||
* isn't helpful, the system will try every archiver until one works or none
|
||||
* of them do.
|
||||
* (newDir) must be a unique string to identify this archive. It is used
|
||||
* to optimize archiver selection (if you name it XXXXX.zip, we might try
|
||||
* the ZIP archiver first, for example, or directly choose an archiver that
|
||||
* can only trust the data is valid by filename extension). It doesn't
|
||||
* need to refer to a real file at all. If the filename extension isn't
|
||||
* helpful, the system will try every archiver until one works or none
|
||||
* of them do. This filename must be unique, as the system won't allow you
|
||||
* to have two archives with the same name.
|
||||
*
|
||||
* (io) must remain until the archive is unmounted. When the archive is
|
||||
* unmounted, the system will call (io)->destroy(io), which will give you
|
||||
|
@ -3211,7 +3224,7 @@ typedef struct PHYSFS_Io
|
|||
* If this function fails, (io)->destroy(io) is not called.
|
||||
*
|
||||
* \param io i/o instance for archive to add to the path.
|
||||
* \param fname Filename that can represent this stream. Can be NULL.
|
||||
* \param newDir Filename that can represent this stream.
|
||||
* \param mountPoint Location in the interpolated tree that this archive
|
||||
* will be "mounted", in platform-independent notation.
|
||||
* NULL or "" is equivalent to "/".
|
||||
|
@ -3224,12 +3237,12 @@ typedef struct PHYSFS_Io
|
|||
* \sa PHYSFS_getSearchPath
|
||||
* \sa PHYSFS_getMountPoint
|
||||
*/
|
||||
PHYSFS_DECL int PHYSFS_mountIo(PHYSFS_Io *io, const char *fname,
|
||||
PHYSFS_DECL int PHYSFS_mountIo(PHYSFS_Io *io, const char *newDir,
|
||||
const char *mountPoint, int appendToPath);
|
||||
|
||||
|
||||
/**
|
||||
* \fn int PHYSFS_mountMemory(const void *buf, PHYSFS_uint64 len, void (*del)(void *), const char *fname, const char *mountPoint, int appendToPath)
|
||||
* \fn int PHYSFS_mountMemory(const void *buf, PHYSFS_uint64 len, void (*del)(void *), const char *newDir, const char *mountPoint, int appendToPath)
|
||||
* \brief Add an archive, contained in a memory buffer, to the search path.
|
||||
*
|
||||
* \warning Unless you have some special, low-level need, you should be using
|
||||
|
@ -3239,11 +3252,14 @@ PHYSFS_DECL int PHYSFS_mountIo(PHYSFS_Io *io, const char *fname,
|
|||
* instead of a pathname. This buffer contains all the data of the archive,
|
||||
* and is used instead of a real file in the physical filesystem.
|
||||
*
|
||||
* (filename) is only used here to optimize archiver selection (if you name it
|
||||
* XXXXX.zip, we might try the ZIP archiver first, for example). It doesn't
|
||||
* need to refer to a real file at all, and can even be NULL. If the filename
|
||||
* isn't helpful, the system will try every archiver until one works or none
|
||||
* of them do.
|
||||
* (newDir) must be a unique string to identify this archive. It is used
|
||||
* to optimize archiver selection (if you name it XXXXX.zip, we might try
|
||||
* the ZIP archiver first, for example, or directly choose an archiver that
|
||||
* can only trust the data is valid by filename extension). It doesn't
|
||||
* need to refer to a real file at all. If the filename extension isn't
|
||||
* helpful, the system will try every archiver until one works or none
|
||||
* of them do. This filename must be unique, as the system won't allow you
|
||||
* to have two archives with the same name.
|
||||
*
|
||||
* (ptr) must remain until the archive is unmounted. When the archive is
|
||||
* unmounted, the system will call (del)(ptr), which will notify you that
|
||||
|
@ -3256,7 +3272,7 @@ PHYSFS_DECL int PHYSFS_mountIo(PHYSFS_Io *io, const char *fname,
|
|||
* \param buf Address of the memory buffer containing the archive data.
|
||||
* \param len Size of memory buffer, in bytes.
|
||||
* \param del A callback that triggers upon unmount. Can be NULL.
|
||||
* \param fname Filename that can represent this stream. Can be NULL.
|
||||
* \param newDir Filename that can represent this stream.
|
||||
* \param mountPoint Location in the interpolated tree that this archive
|
||||
* will be "mounted", in platform-independent notation.
|
||||
* NULL or "" is equivalent to "/".
|
||||
|
@ -3269,12 +3285,12 @@ PHYSFS_DECL int PHYSFS_mountIo(PHYSFS_Io *io, const char *fname,
|
|||
* \sa PHYSFS_getMountPoint
|
||||
*/
|
||||
PHYSFS_DECL int PHYSFS_mountMemory(const void *buf, PHYSFS_uint64 len,
|
||||
void (*del)(void *), const char *fname,
|
||||
void (*del)(void *), const char *newDir,
|
||||
const char *mountPoint, int appendToPath);
|
||||
|
||||
|
||||
/**
|
||||
* \fn int PHYSFS_mountHandle(PHYSFS_File *file, const char *fname, const char *mountPoint, int appendToPath)
|
||||
* \fn int PHYSFS_mountHandle(PHYSFS_File *file, const char *newDir, const char *mountPoint, int appendToPath)
|
||||
* \brief Add an archive, contained in a PHYSFS_File handle, to the search path.
|
||||
*
|
||||
* \warning Unless you have some special, low-level need, you should be using
|
||||
|
@ -3297,11 +3313,14 @@ PHYSFS_DECL int PHYSFS_mountMemory(const void *buf, PHYSFS_uint64 len,
|
|||
* but isn't necessarily. The most popular use for this is likely to mount
|
||||
* archives stored inside other archives.
|
||||
*
|
||||
* (filename) is only used here to optimize archiver selection (if you name it
|
||||
* XXXXX.zip, we might try the ZIP archiver first, for example). It doesn't
|
||||
* need to refer to a real file at all, and can even be NULL. If the filename
|
||||
* isn't helpful, the system will try every archiver until one works or none
|
||||
* of them do.
|
||||
* (newDir) must be a unique string to identify this archive. It is used
|
||||
* to optimize archiver selection (if you name it XXXXX.zip, we might try
|
||||
* the ZIP archiver first, for example, or directly choose an archiver that
|
||||
* can only trust the data is valid by filename extension). It doesn't
|
||||
* need to refer to a real file at all. If the filename extension isn't
|
||||
* helpful, the system will try every archiver until one works or none
|
||||
* of them do. This filename must be unique, as the system won't allow you
|
||||
* to have two archives with the same name.
|
||||
*
|
||||
* (file) must remain until the archive is unmounted. When the archive is
|
||||
* unmounted, the system will call PHYSFS_close(file). If you need this
|
||||
|
@ -3311,7 +3330,7 @@ PHYSFS_DECL int PHYSFS_mountMemory(const void *buf, PHYSFS_uint64 len,
|
|||
* If this function fails, PHYSFS_close(file) is not called.
|
||||
*
|
||||
* \param file The PHYSFS_File handle containing archive data.
|
||||
* \param fname Filename that can represent this stream. Can be NULL.
|
||||
* \param newDir Filename that can represent this stream.
|
||||
* \param mountPoint Location in the interpolated tree that this archive
|
||||
* will be "mounted", in platform-independent notation.
|
||||
* NULL or "" is equivalent to "/".
|
||||
|
@ -3323,7 +3342,7 @@ PHYSFS_DECL int PHYSFS_mountMemory(const void *buf, PHYSFS_uint64 len,
|
|||
* \sa PHYSFS_getSearchPath
|
||||
* \sa PHYSFS_getMountPoint
|
||||
*/
|
||||
PHYSFS_DECL int PHYSFS_mountHandle(PHYSFS_File *file, const char *fname,
|
||||
PHYSFS_DECL int PHYSFS_mountHandle(PHYSFS_File *file, const char *newDir,
|
||||
const char *mountPoint, int appendToPath);
|
||||
|
||||
|
||||
|
|
|
@ -49,7 +49,8 @@ static void *DIR_openArchive(PHYSFS_Io *io, const char *name,
|
|||
const size_t seplen = 1;
|
||||
|
||||
assert(io == NULL); /* shouldn't create an Io for these. */
|
||||
BAIL_IF_ERRPASS(!__PHYSFS_platformStat(name, &st), NULL);
|
||||
BAIL_IF_ERRPASS(!__PHYSFS_platformStat(name, &st, 1), NULL);
|
||||
|
||||
if (st.filetype != PHYSFS_FILETYPE_DIRECTORY)
|
||||
BAIL(PHYSFS_ERR_UNSUPPORTED, NULL);
|
||||
|
||||
|
@ -97,7 +98,7 @@ static PHYSFS_Io *doOpen(void *opaque, const char *name, const int mode)
|
|||
{
|
||||
const PHYSFS_ErrorCode err = PHYSFS_getLastErrorCode();
|
||||
PHYSFS_Stat statbuf;
|
||||
__PHYSFS_platformStat(f, &statbuf);
|
||||
__PHYSFS_platformStat(f, &statbuf, 0); /* !!! FIXME: why are we stating here? */
|
||||
PHYSFS_setErrorCode(err);
|
||||
} /* if */
|
||||
|
||||
|
@ -164,7 +165,7 @@ static int DIR_stat(void *opaque, const char *name, PHYSFS_Stat *stat)
|
|||
|
||||
CVT_TO_DEPENDENT(d, opaque, name);
|
||||
BAIL_IF_ERRPASS(!d, 0);
|
||||
retval = __PHYSFS_platformStat(d, stat);
|
||||
retval = __PHYSFS_platformStat(d, stat, 0);
|
||||
__PHYSFS_smallFree(d);
|
||||
return retval;
|
||||
} /* DIR_stat */
|
||||
|
|
|
@ -151,18 +151,25 @@ static int iso9660LoadEntries(PHYSFS_Io *io, const int joliet,
|
|||
|
||||
/* recordlen = 0 -> no more entries or fill entry */
|
||||
BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &recordlen, 1), 0);
|
||||
if (recordlen == 0)
|
||||
if (recordlen > 0)
|
||||
readpos += recordlen; /* ready to seek to next record. */
|
||||
else
|
||||
{
|
||||
PHYSFS_uint64 nextpos;
|
||||
|
||||
/* if we are in the last sector of the directory & it's 0 -> end */
|
||||
if ((dirend - 2048) <= (readpos - 1))
|
||||
break; /* finished */
|
||||
|
||||
/* else skip to the next sector & continue; */
|
||||
readpos = (((readpos - 1) / 2048) + 1) * 2048;
|
||||
continue;
|
||||
} /* if */
|
||||
nextpos = (((readpos - 1) / 2048) + 1) * 2048;
|
||||
|
||||
readpos += recordlen; /* ready to seek to next record. */
|
||||
/* whoops, can't make forward progress! */
|
||||
BAIL_IF(nextpos == readpos, PHYSFS_ERR_CORRUPT, 0);
|
||||
|
||||
readpos = nextpos;
|
||||
continue; /* start back at upper loop. */
|
||||
} /* else */
|
||||
|
||||
BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &extattrlen, 1), 0);
|
||||
BAIL_IF_ERRPASS(!__PHYSFS_readAll(io, &extent, 4), 0);
|
||||
|
@ -203,6 +210,10 @@ static int iso9660LoadEntries(PHYSFS_Io *io, const int joliet,
|
|||
timestamp = (PHYSFS_sint64) mktime(&t);
|
||||
|
||||
extent += extattrlen; /* skip extended attribute record. */
|
||||
|
||||
/* infinite loop, corrupt file? */
|
||||
BAIL_IF((extent * 2048) == dirstart, PHYSFS_ERR_CORRUPT, 0);
|
||||
|
||||
if (!iso9660AddEntry(io, joliet, isdir, base, fname, fnamelen,
|
||||
timestamp, extent * 2048, datalen, unpkarc))
|
||||
{
|
||||
|
|
|
@ -455,6 +455,7 @@ static PHYSFS_Io *ZIP_duplicate(PHYSFS_Io *io)
|
|||
finfo->io = zip_get_io(origfinfo->io, NULL, finfo->entry);
|
||||
GOTO_IF_ERRPASS(!finfo->io, failed);
|
||||
|
||||
initializeZStream(&finfo->stream);
|
||||
if (finfo->entry->compression_method != COMPMETH_NONE)
|
||||
{
|
||||
finfo->buffer = (PHYSFS_uint8 *) allocator.Malloc(ZIP_READBUFSIZE);
|
||||
|
|
|
@ -549,11 +549,12 @@ PHYSFS_sint64 __PHYSFS_platformFileLength(void *handle);
|
|||
*
|
||||
* This needs to fill in all the fields of (stat). For fields that might not
|
||||
* mean anything on a platform (access time, perhaps), choose a reasonable
|
||||
* default.
|
||||
* default. if (follow), we want to follow symlinks and stat what they
|
||||
* link to and not the link itself.
|
||||
*
|
||||
* Return zero on failure, non-zero on success.
|
||||
*/
|
||||
int __PHYSFS_platformStat(const char *fn, PHYSFS_Stat *stat);
|
||||
int __PHYSFS_platformStat(const char *fn, PHYSFS_Stat *stat, const int follow);
|
||||
|
||||
/*
|
||||
* Flush any pending writes to disk. (opaque) should be cast to whatever data
|
||||
|
|
|
@ -721,7 +721,7 @@ PHYSFS_sint64 os2TimeToUnixTime(const FDATE *date, const FTIME *time)
|
|||
} /* os2TimeToUnixTime */
|
||||
|
||||
|
||||
int __PHYSFS_platformStat(const char *filename, PHYSFS_Stat *stat)
|
||||
int __PHYSFS_platformStat(const char *filename, PHYSFS_Stat *stat, const int follow)
|
||||
{
|
||||
char *cpfname = cvtUtf8ToCodepage(filename);
|
||||
FILESTATUS3 fs;
|
||||
|
|
|
@ -296,11 +296,11 @@ int __PHYSFS_platformDelete(const char *path)
|
|||
} /* __PHYSFS_platformDelete */
|
||||
|
||||
|
||||
int __PHYSFS_platformStat(const char *filename, PHYSFS_Stat *st)
|
||||
int __PHYSFS_platformStat(const char *fname, PHYSFS_Stat *st, const int follow)
|
||||
{
|
||||
struct stat statbuf;
|
||||
|
||||
BAIL_IF(lstat(filename, &statbuf) == -1, errcodeFromErrno(), 0);
|
||||
const int rc = follow ? stat(fname, &statbuf) : lstat(fname, &statbuf);
|
||||
BAIL_IF(rc == -1, errcodeFromErrno(), 0);
|
||||
|
||||
if (S_ISREG(statbuf.st_mode))
|
||||
{
|
||||
|
@ -330,7 +330,7 @@ int __PHYSFS_platformStat(const char *filename, PHYSFS_Stat *st)
|
|||
st->createtime = statbuf.st_ctime;
|
||||
st->accesstime = statbuf.st_atime;
|
||||
|
||||
st->readonly = (access(filename, W_OK) == -1);
|
||||
st->readonly = (access(fname, W_OK) == -1);
|
||||
return 1;
|
||||
} /* __PHYSFS_platformStat */
|
||||
|
||||
|
|
|
@ -960,7 +960,7 @@ static int isSymlink(const WCHAR *wpath, const DWORD attr)
|
|||
} /* isSymlink */
|
||||
|
||||
|
||||
int __PHYSFS_platformStat(const char *filename, PHYSFS_Stat *st)
|
||||
int __PHYSFS_platformStat(const char *filename, PHYSFS_Stat *st, const int follow)
|
||||
{
|
||||
WIN32_FILE_ATTRIBUTE_DATA winstat;
|
||||
WCHAR *wstr = NULL;
|
||||
|
@ -975,7 +975,7 @@ int __PHYSFS_platformStat(const char *filename, PHYSFS_Stat *st)
|
|||
if (!rc)
|
||||
err = GetLastError();
|
||||
else /* check for symlink while wstr is still available */
|
||||
issymlink = isSymlink(wstr, winstat.dwFileAttributes);
|
||||
issymlink = !follow && isSymlink(wstr, winstat.dwFileAttributes);
|
||||
|
||||
__PHYSFS_smallFree(wstr);
|
||||
BAIL_IF(!rc, errcodeFromWinApiError(err), 0);
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
|
||||
#define TEST_VERSION_MAJOR 3
|
||||
#define TEST_VERSION_MINOR 0
|
||||
#define TEST_VERSION_PATCH 0
|
||||
#define TEST_VERSION_PATCH 1
|
||||
|
||||
static FILE *history_file = NULL;
|
||||
static PHYSFS_uint32 do_buffer_size = 0;
|
||||
|
|
Loading…
Reference in New Issue