From 7cc80bebc50068f0f8c493830f37e3a723c27fe5 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Sun, 14 Feb 2010 23:07:19 -0500 Subject: [PATCH] Added first work on PHYSFS_stat() API (thanks, Christoph!). --- docs/CREDITS.txt | 3 +++ extras/physfs-swig.i | 1 + src/archiver_dir.c | 15 ++++++++++++++ src/archiver_grp.c | 7 +++++++ src/archiver_hog.c | 7 +++++++ src/archiver_lzma.c | 7 +++++++ src/archiver_mvl.c | 7 +++++++ src/archiver_qpak.c | 7 +++++++ src/archiver_wad.c | 7 +++++++ src/archiver_zip.c | 7 +++++++ src/physfs.c | 44 +++++++++++++++++++++++++++++++++++++++++ src/physfs.h | 36 +++++++++++++++++++++++++++++++++ src/physfs_internal.h | 12 +++++++++++ src/platform_os2.c | 6 ++++++ src/platform_pocketpc.c | 6 ++++++ src/platform_posix.c | 21 ++++++++++++++++++++ src/platform_windows.c | 24 ++++++++++++++++++++++ 17 files changed, 217 insertions(+) diff --git a/docs/CREDITS.txt b/docs/CREDITS.txt index 7e0cc3d3..3e5945a0 100644 --- a/docs/CREDITS.txt +++ b/docs/CREDITS.txt @@ -105,6 +105,9 @@ OS/2 updates: Bug fixes: Patrice Mandin +PHYSFS_stat() API: + Christoph Nelles + Other stuff: Your name here! Patches go to icculus@icculus.org ... diff --git a/extras/physfs-swig.i b/extras/physfs-swig.i index 8f92f14c..c0ac11fd 100644 --- a/extras/physfs-swig.i +++ b/extras/physfs-swig.i @@ -83,6 +83,7 @@ %rename(symbolicLinksPermitted) PHYSFS_symbolicLinksPermitted; %rename(mount) PHYSFS_mount; %rename(getMountPoint) PHYSFS_getMountPoint; +%rename(stat) PHYSFS_stat; #endif /* SWIGPERL */ %include "../src/physfs.h" diff --git a/src/archiver_dir.c b/src/archiver_dir.c index bb842566..122ef8fe 100644 --- a/src/archiver_dir.c +++ b/src/archiver_dir.c @@ -169,6 +169,20 @@ static PHYSFS_sint64 DIR_getLastModTime(dvoid *opaque, } /* DIR_getLastModTime */ +static int DIR_stat(dvoid *opaque, const char *name, PHYSFS_Stat *st) +{ + char *d = __PHYSFS_platformCvtToDependent((char *)opaque, name, NULL); + int retval = -1; + + BAIL_IF_MACRO(d == NULL, NULL, -1); + + retval = __PHYSFS_platformStat(d, st); + + allocator.Free(d); + return(retval); +} /* DIR_stat */ + + static fvoid *doOpen(dvoid *opaque, const char *name, void *(*openFunc)(const char *filename), int *fileExists) @@ -261,6 +275,7 @@ const PHYSFS_Archiver __PHYSFS_Archiver_DIR = DIR_openArchive, /* openArchive() method */ DIR_enumerateFiles, /* enumerateFiles() method */ DIR_exists, /* exists() method */ + DIR_stat, /* stat() method */ DIR_isDirectory, /* isDirectory() method */ DIR_isSymLink, /* isSymLink() method */ DIR_getLastModTime, /* getLastModTime() method */ diff --git a/src/archiver_grp.c b/src/archiver_grp.c index a47e92ef..5bfcd29b 100644 --- a/src/archiver_grp.c +++ b/src/archiver_grp.c @@ -384,6 +384,12 @@ static PHYSFS_sint64 GRP_getLastModTime(dvoid *opaque, } /* GRP_getLastModTime */ +static int GRP_stat(dvoid *opaque, const char *name, PHYSFS_Stat *st) +{ + return -1; /* !!! FIXME: write me */ +} /* GRP_stat */ + + static fvoid *GRP_openRead(dvoid *opaque, const char *fnm, int *fileExists) { GRPinfo *info = (GRPinfo *) opaque; @@ -451,6 +457,7 @@ const PHYSFS_Archiver __PHYSFS_Archiver_GRP = GRP_openArchive, /* openArchive() method */ GRP_enumerateFiles, /* enumerateFiles() method */ GRP_exists, /* exists() method */ + GRP_stat, /* stat() method */ GRP_isDirectory, /* isDirectory() method */ GRP_isSymLink, /* isSymLink() method */ GRP_getLastModTime, /* getLastModTime() method */ diff --git a/src/archiver_hog.c b/src/archiver_hog.c index 5cea8759..61d5df6f 100644 --- a/src/archiver_hog.c +++ b/src/archiver_hog.c @@ -423,6 +423,12 @@ static PHYSFS_sint64 HOG_getLastModTime(dvoid *opaque, } /* HOG_getLastModTime */ +static int HOG_stat(dvoid *opaque, const char *name, PHYSFS_Stat *st) +{ + return -1; /* !!! FIXME: write me */ +} /* HOG_stat */ + + static fvoid *HOG_openRead(dvoid *opaque, const char *fnm, int *fileExists) { HOGinfo *info = ((HOGinfo *) opaque); @@ -490,6 +496,7 @@ const PHYSFS_Archiver __PHYSFS_Archiver_HOG = HOG_openArchive, /* openArchive() method */ HOG_enumerateFiles, /* enumerateFiles() method */ HOG_exists, /* exists() method */ + HOG_stat, /* stat() method */ HOG_isDirectory, /* isDirectory() method */ HOG_isSymLink, /* isSymLink() method */ HOG_getLastModTime, /* getLastModTime() method */ diff --git a/src/archiver_lzma.c b/src/archiver_lzma.c index cda82854..1a4c8d89 100644 --- a/src/archiver_lzma.c +++ b/src/archiver_lzma.c @@ -623,6 +623,12 @@ static PHYSFS_sint64 LZMA_getLastModTime(dvoid *opaque, } /* LZMA_getLastModTime */ +static int LZMA_stat(dvoid *opaque, const char *name, PHYSFS_Stat *st) +{ + return -1; /* !!! FIXME: write me */ +} /* LZMA_stat */ + + static int LZMA_isDirectory(dvoid *opaque, const char *name, int *fileExists) { LZMAarchive *archive = (LZMAarchive *) opaque; @@ -712,6 +718,7 @@ const PHYSFS_Archiver __PHYSFS_Archiver_LZMA = LZMA_openArchive, /* openArchive() method */ LZMA_enumerateFiles, /* enumerateFiles() method */ LZMA_exists, /* exists() method */ + LZMA_stat, /* stat() method */ LZMA_isDirectory, /* isDirectory() method */ LZMA_isSymLink, /* isSymLink() method */ LZMA_getLastModTime, /* getLastModTime() method */ diff --git a/src/archiver_mvl.c b/src/archiver_mvl.c index 18279c91..87d19b3c 100644 --- a/src/archiver_mvl.c +++ b/src/archiver_mvl.c @@ -380,6 +380,12 @@ static PHYSFS_sint64 MVL_getLastModTime(dvoid *opaque, } /* MVL_getLastModTime */ +static int MVL_stat(dvoid *opaque, const char *name, PHYSFS_Stat *st) +{ + return -1; /* !!! FIXME: write me */ +} /* MVL_stat */ + + static fvoid *MVL_openRead(dvoid *opaque, const char *fnm, int *fileExists) { MVLinfo *info = ((MVLinfo *) opaque); @@ -447,6 +453,7 @@ const PHYSFS_Archiver __PHYSFS_Archiver_MVL = MVL_openArchive, /* openArchive() method */ MVL_enumerateFiles, /* enumerateFiles() method */ MVL_exists, /* exists() method */ + MVL_stat, /* stat() method */ MVL_isDirectory, /* isDirectory() method */ MVL_isSymLink, /* isSymLink() method */ MVL_getLastModTime, /* getLastModTime() method */ diff --git a/src/archiver_qpak.c b/src/archiver_qpak.c index 2ce10fd1..f3ac4ace 100644 --- a/src/archiver_qpak.c +++ b/src/archiver_qpak.c @@ -537,6 +537,12 @@ static PHYSFS_sint64 QPAK_getLastModTime(dvoid *opaque, } /* QPAK_getLastModTime */ +static int QPAK_stat(dvoid *opaque, const char *name, PHYSFS_Stat *st) +{ + return -1; /* !!! FIXME: write me */ +} /* QPAK_stat */ + + static fvoid *QPAK_openRead(dvoid *opaque, const char *fnm, int *fileExists) { QPAKinfo *info = ((QPAKinfo *) opaque); @@ -606,6 +612,7 @@ const PHYSFS_Archiver __PHYSFS_Archiver_QPAK = QPAK_openArchive, /* openArchive() method */ QPAK_enumerateFiles, /* enumerateFiles() method */ QPAK_exists, /* exists() method */ + QPAK_stat, /* stat() method */ QPAK_isDirectory, /* isDirectory() method */ QPAK_isSymLink, /* isSymLink() method */ QPAK_getLastModTime, /* getLastModTime() method */ diff --git a/src/archiver_wad.c b/src/archiver_wad.c index c0e49da0..333faac2 100644 --- a/src/archiver_wad.c +++ b/src/archiver_wad.c @@ -443,6 +443,12 @@ static PHYSFS_sint64 WAD_getLastModTime(dvoid *opaque, } /* WAD_getLastModTime */ +static int WAD_stat(dvoid *opaque, const char *name, PHYSFS_Stat *st) +{ + return -1; /* !!! FIXME: write me */ +} /* WAD_stat */ + + static fvoid *WAD_openRead(dvoid *opaque, const char *fnm, int *fileExists) { WADinfo *info = ((WADinfo *) opaque); @@ -510,6 +516,7 @@ const PHYSFS_Archiver __PHYSFS_Archiver_WAD = WAD_openArchive, /* openArchive() method */ WAD_enumerateFiles, /* enumerateFiles() method */ WAD_exists, /* exists() method */ + WAD_stat, /* stat() method */ WAD_isDirectory, /* isDirectory() method */ WAD_isSymLink, /* isSymLink() method */ WAD_getLastModTime, /* getLastModTime() method */ diff --git a/src/archiver_zip.c b/src/archiver_zip.c index 6023d1b7..d815bb4a 100644 --- a/src/archiver_zip.c +++ b/src/archiver_zip.c @@ -1264,6 +1264,12 @@ static PHYSFS_sint64 ZIP_getLastModTime(dvoid *opaque, } /* ZIP_getLastModTime */ +static int ZIP_stat(dvoid *opaque, const char *name, PHYSFS_Stat *st) +{ + return -1; /* !!! FIXME: write me */ +} /* ZIP_stat */ + + static int ZIP_isDirectory(dvoid *opaque, const char *name, int *fileExists) { ZIPinfo *info = (ZIPinfo *) opaque; @@ -1422,6 +1428,7 @@ const PHYSFS_Archiver __PHYSFS_Archiver_ZIP = ZIP_openArchive, /* openArchive() method */ ZIP_enumerateFiles, /* enumerateFiles() method */ ZIP_exists, /* exists() method */ + ZIP_stat, /* stat() method */ ZIP_isDirectory, /* isDirectory() method */ ZIP_isSymLink, /* isSymLink() method */ ZIP_getLastModTime, /* getLastModTime() method */ diff --git a/src/physfs.c b/src/physfs.c index 74fd464f..8d1692b9 100644 --- a/src/physfs.c +++ b/src/physfs.c @@ -1620,6 +1620,50 @@ int PHYSFS_exists(const char *fname) return (PHYSFS_getRealDir(fname) != NULL); } /* PHYSFS_exists */ +int PHYSFS_stat(const char *_fname, PHYSFS_Stat *st) +{ + char *fname; + size_t len; + int retval = -1; + + BAIL_IF_MACRO(_fname == NULL, ERR_INVALID_ARGUMENT, -1); + BAIL_IF_MACRO(st == NULL, ERR_INVALID_ARGUMENT, -1); + + memset(st, 0, sizeof(PHYSFS_Stat)); + len = strlen(_fname) + 1; + fname = (char *) __PHYSFS_smallAlloc(len); + BAIL_IF_MACRO(fname == NULL, ERR_OUT_OF_MEMORY, -1); + + if (sanitizePlatformIndependentPath(_fname, fname)) + { + if (*fname == '\0') /* eh...punt if it's the root dir. */ + { + retval = 0; /* !!! FIXME: Maybe this should be an error? */ + st->is_dir = 1; + } /* if */ + else + { + DirHandle *i; + int exists = 0; + __PHYSFS_platformGrabMutex(stateLock); + for (i = searchPath; ((i != NULL) && (!exists)); i = i->next) + { + char *arcfname = fname; + exists = partOfMountPoint(i, arcfname); + if (exists) + retval = 1; /* !!! FIXME: What's the right value? */ + else if (verifyPath(i, &arcfname, 0)) + { + retval = i->funcs->stat(i->opaque, arcfname, st); + } /* else if */ + } /* for */ + __PHYSFS_platformReleaseMutex(stateLock); + } /* else */ + } /* if */ + + __PHYSFS_smallFree(fname); + return(retval); +} PHYSFS_sint64 PHYSFS_getLastModTime(const char *_fname) { diff --git a/src/physfs.h b/src/physfs.h index 015d7ec2..e57f7ed6 100644 --- a/src/physfs.h +++ b/src/physfs.h @@ -2463,6 +2463,42 @@ PHYSFS_DECL const PHYSFS_Allocator *PHYSFS_getAllocator(void); #endif /* SWIG */ +/** + * \struct PHYSFS_Stat + * \brief Information on a file in a PhysicsFS filesystem. + * + * Created as a way to get a file's information without repeated calls and + * without having to open the file. + * + * \sa PHYSFS_stat + */ +typedef struct PHYSFS_Stat +{ + int is_dir; + int is_symlink; + PHYSFS_sint64 size; + PHYSFS_sint64 atime; + PHYSFS_sint64 mtime; + PHYSFS_sint64 ctime; +} PHYSFS_Stat; + + +/** + * \fn int PHYSFS_stat(const char *fname, PHYSFS_Stat * st) + * \brief Get information on a file in the search path. + * + * \param fname filename in platform-independent notation. + * \param st pointer to an PHYSFS_Stat structure. + * \return 0 on success (file exists and information retreived successfully), + * non-zero otherwise. + * + * !!! FIXME: have to distinguish between "unsupported", "missing" and + * !!! FIXME: "failure" results. + * + * \sa PHYSFS_Stat + */ +PHYSFS_DECL int PHYSFS_stat(const char *fname, PHYSFS_Stat *st); + /* Everything above this line is part of the PhysicsFS 2.1 API. */ diff --git a/src/physfs_internal.h b/src/physfs_internal.h index 898793d9..72d660aa 100644 --- a/src/physfs_internal.h +++ b/src/physfs_internal.h @@ -773,6 +773,12 @@ typedef struct */ int (*exists)(dvoid *opaque, const char *name); + /* + * Returns zero if filename can be opened for reading and + * information was retreived. Non-zero otherwise. + */ + int (*stat)(dvoid *opaque, const char *name, PHYSFS_Stat *st); + /* * Returns non-zero if filename is really a directory. * This filename is in platform-independent notation. @@ -1345,6 +1351,12 @@ int __PHYSFS_platformIsSymLink(const char *fname); int __PHYSFS_platformIsDirectory(const char *fname); +/* + * !!! FIXME: comment me. + */ +int __PHYSFS_platformStat(const char *fname, PHYSFS_Stat *st); + + /* * Convert (dirName) to platform-dependent notation, then prepend (prepend) * and append (append) to the converted string. diff --git a/src/platform_os2.c b/src/platform_os2.c index affc0180..d7dba639 100644 --- a/src/platform_os2.c +++ b/src/platform_os2.c @@ -322,6 +322,12 @@ int __PHYSFS_platformIsDirectory(const char *_fname) } /* __PHYSFS_platformIsDirectory */ +int __PHYSFS_platformStat(const char *fname, PHYSFS_Stat *st) +{ + return -1; /* !!! FIXME: write me */ +} /* __PHYSFS_platformStat */ + + /* !!! FIXME: can we lose the malloc here? */ char *__PHYSFS_platformCvtToDependent(const char *prepend, const char *dirName, diff --git a/src/platform_pocketpc.c b/src/platform_pocketpc.c index 32c7f1ec..6a2e72be 100644 --- a/src/platform_pocketpc.c +++ b/src/platform_pocketpc.c @@ -201,6 +201,12 @@ int __PHYSFS_platformIsDirectory(const char *fname) } /* __PHYSFS_platformIsDirectory */ +int __PHYSFS_platformStat(const char *fname, PHYSFS_Stat *st) +{ + return -1; /* !!! FIXME: write me */ +} /* __PHYSFS_platformStat */ + + char *__PHYSFS_platformCvtToDependent(const char *prepend, const char *dirName, const char *append) diff --git a/src/platform_posix.c b/src/platform_posix.c index 9d5754de..c615686d 100644 --- a/src/platform_posix.c +++ b/src/platform_posix.c @@ -127,6 +127,27 @@ int __PHYSFS_platformIsDirectory(const char *fname) } /* __PHYSFS_platformIsDirectory */ +int __PHYSFS_platformStat(const char *fname, PHYSFS_Stat *st) +{ + int retval = 0; + struct stat pstat; + + /* !!! FIXME: lstat()? */ + retval = stat(fname, &pstat); + if (retval == 0) + { + st->size = pstat.st_size; + st->mtime = pstat.st_mtime; + st->atime = pstat.st_atime; + st->ctime = pstat.st_ctime; + st->is_symlink = S_ISLNK(pstat.st_mode) ? 1 : 0; + st->is_dir = S_ISDIR(pstat.st_mode) ? 1 : 0; + } /* if */ + + return(retval); +} /* __PHYSFS_platformStat */ + + char *__PHYSFS_platformCvtToDependent(const char *prepend, const char *dirName, const char *append) diff --git a/src/platform_windows.c b/src/platform_windows.c index e669618c..df2a0cba 100644 --- a/src/platform_windows.c +++ b/src/platform_windows.c @@ -23,6 +23,7 @@ #include #include #include +#include #include "physfs_internal.h" @@ -587,6 +588,29 @@ int __PHYSFS_platformExists(const char *fname) return retval; } /* __PHYSFS_platformExists */ +int __PHYSFS_platformStat(const char *fname, PHYSFS_Stat *st) +{ + int retval = 0; + LPWSTR wpath; + struct _stat64 pstat; + UTF8_TO_UNICODE_STACK_MACRO(wpath, fname); + BAIL_IF_MACRO(wpath == NULL, ERR_OUT_OF_MEMORY, -1); + + retval = _wstat64(wpath, &pstat); + if (retval == 0) + { + st->size = pstat.st_size; + st->mtime = pstat.st_mtime; + st->atime = pstat.st_atime; + st->ctime = pstat.st_ctime; + st->is_dir = (pstat.st_mode & _S_IFDIR) ? 1:0; + st->is_symlink = 0; + } /* if */ + + __PHYSFS_smallFree(wpath); + return(retval); +} /* __PHYSFS_platformStat */ + static int isSymlinkAttrs(const DWORD attr, const DWORD tag) {