From a80261989e6b517167889ea035711a9eb4ca2e12 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Thu, 26 Oct 2017 14:21:36 -0400 Subject: [PATCH] Fixed mounting a symlink to a real directory. (transplanted from f3459eaad51bbbed4fc2768c0ec65b3005a7f490) --- src/physfs.c | 2 +- src/physfs.h | 6 +++++- src/physfs_archiver_dir.c | 7 ++++--- src/physfs_internal.h | 5 +++-- src/physfs_platform_os2.c | 2 +- src/physfs_platform_posix.c | 8 ++++---- src/physfs_platform_windows.c | 4 ++-- 7 files changed, 20 insertions(+), 14 deletions(-) diff --git a/src/physfs.c b/src/physfs.c index 992ae31e..3a166268 100644 --- a/src/physfs.c +++ b/src/physfs.c @@ -1595,7 +1595,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)) { diff --git a/src/physfs.h b/src/physfs.h index e9ef93d8..f50d1566 100644 --- a/src/physfs.h +++ b/src/physfs.h @@ -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 diff --git a/src/physfs_archiver_dir.c b/src/physfs_archiver_dir.c index 582ef8ce..61c0da3f 100644 --- a/src/physfs_archiver_dir.c +++ b/src/physfs_archiver_dir.c @@ -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 */ diff --git a/src/physfs_internal.h b/src/physfs_internal.h index 62e83355..003ecc58 100644 --- a/src/physfs_internal.h +++ b/src/physfs_internal.h @@ -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 diff --git a/src/physfs_platform_os2.c b/src/physfs_platform_os2.c index c6c472d8..8cc8044c 100644 --- a/src/physfs_platform_os2.c +++ b/src/physfs_platform_os2.c @@ -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; diff --git a/src/physfs_platform_posix.c b/src/physfs_platform_posix.c index 0ecc8824..fa2159cd 100644 --- a/src/physfs_platform_posix.c +++ b/src/physfs_platform_posix.c @@ -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 */ diff --git a/src/physfs_platform_windows.c b/src/physfs_platform_windows.c index a490c2ff..e777235d 100644 --- a/src/physfs_platform_windows.c +++ b/src/physfs_platform_windows.c @@ -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);