diff --git a/archivers/dir.c b/archivers/dir.c index 14ec788..1c47393 100644 --- a/archivers/dir.c +++ b/archivers/dir.c @@ -38,6 +38,7 @@ static int DIR_exists(DirHandle *h, const char *name); static int DIR_isDirectory(DirHandle *h, const char *name); static int DIR_isSymLink(DirHandle *h, const char *name); static FileHandle *DIR_openRead(DirHandle *h, const char *filename); +static PHYSFS_sint64 DIR_getLastModTime(DirHandle *h, const char *name); static FileHandle *DIR_openWrite(DirHandle *h, const char *filename); static FileHandle *DIR_openAppend(DirHandle *h, const char *filename); static int DIR_remove(DirHandle *h, const char *name); @@ -77,6 +78,7 @@ const DirFunctions __PHYSFS_DirFunctions_DIR = DIR_exists, /* exists() method */ DIR_isDirectory, /* isDirectory() method */ DIR_isSymLink, /* isSymLink() method */ + DIR_getLastModTime, /* getLastModTime() method */ DIR_openRead, /* openRead() method */ DIR_openWrite, /* openWrite() method */ DIR_openAppend, /* openAppend() method */ @@ -241,6 +243,18 @@ static int DIR_isSymLink(DirHandle *h, const char *name) } /* DIR_isSymLink */ +static PHYSFS_sint64 DIR_getLastModTime(DirHandle *h, const char *name) +{ + char *d = __PHYSFS_platformCvtToDependent((char *)(h->opaque), name, NULL); + PHYSFS_sint64 retval; + + BAIL_IF_MACRO(d == NULL, NULL, 0); + retval = __PHYSFS_platformGetMtime(d); + free(d); + return(retval); +} /* DIR_getLastModTime */ + + static FileHandle *doOpen(DirHandle *h, const char *name, void *(*openFunc)(const char *filename), const FileFunctions *fileFuncs) diff --git a/archivers/grp.c b/archivers/grp.c index e5d2115..6959735 100644 --- a/archivers/grp.c +++ b/archivers/grp.c @@ -98,6 +98,7 @@ const DirFunctions __PHYSFS_DirFunctions_GRP = GRP_exists, /* exists() method */ GRP_isDirectory, /* isDirectory() method */ GRP_isSymLink, /* isSymLink() method */ + NULL, /* getLastModTime() method */ GRP_openRead, /* openRead() method */ NULL, /* openWrite() method */ NULL, /* openAppend() method */ diff --git a/archivers/zip.c b/archivers/zip.c index 7afd117..b118344 100644 --- a/archivers/zip.c +++ b/archivers/zip.c @@ -99,6 +99,7 @@ const DirFunctions __PHYSFS_DirFunctions_ZIP = ZIP_exists, /* exists() method */ ZIP_isDirectory, /* isDirectory() method */ ZIP_isSymLink, /* isSymLink() method */ + NULL, /* getLastModTime() method */ /* !!! FIXME: This can be determined in a zipfile. */ ZIP_openRead, /* openRead() method */ NULL, /* openWrite() method */ NULL, /* openAppend() method */ diff --git a/physfs.c b/physfs.c index 5fe8fb6..6696588 100644 --- a/physfs.c +++ b/physfs.c @@ -1146,6 +1146,37 @@ int PHYSFS_exists(const char *fname) } /* PHYSFS_exists */ +PHYSFS_sint64 PHYSFS_getLastModTime(const char *fname) +{ + PhysDirInfo *i; + + BAIL_IF_MACRO(fname == NULL, ERR_INVALID_ARGUMENT, 0); + while (*fname == '/') + fname++; + + if (*fname == '\0') /* eh...punt if it's the root dir. */ + return(1); + + __PHYSFS_platformGrabMutex(stateLock); + for (i = searchPath; i != NULL; i = i->next) + { + DirHandle *h = i->dirHandle; + if (__PHYSFS_verifySecurity(h, fname)) + { + if (h->funcs->exists(h, fname)) + { + PHYSFS_sint64 retval = h->funcs->getLastModTime(h, fname); + __PHYSFS_platformReleaseMutex(stateLock); + return(retval); + } /* if */ + } /* if */ + } /* for */ + __PHYSFS_platformReleaseMutex(stateLock); + + return(0); +} /* PHYSFS_getLastModTime */ + + int PHYSFS_isDirectory(const char *fname) { PhysDirInfo *i; @@ -1405,6 +1436,7 @@ PHYSFS_sint64 PHYSFS_fileLength(PHYSFS_file *handle) assert(h != NULL); assert(h->funcs != NULL); BAIL_IF_MACRO(h->funcs->fileLength == NULL, ERR_NOT_SUPPORTED, 0); + return(h->funcs->fileLength(h)); } /* PHYSFS_filelength */ diff --git a/physfs.h b/physfs.h index cc25786..3eea197 100644 --- a/physfs.h +++ b/physfs.h @@ -783,6 +783,19 @@ __EXPORT__ PHYSFS_file *PHYSFS_openRead(const char *filename); __EXPORT__ int PHYSFS_close(PHYSFS_file *handle); +/** + * Get the last modification time of a file. This is returned as a + * number of seconds since the epoch (Jan 1, 1970). The exact derivation + * and accuracy of this time depends on the particular archiver. If there + * is no reasonable way to obtain this information for a particular archiver, + * or there was some sort of error, this function returns (-1). + * + * @param filename filename to check. + * @return last modified time of the file. -1 if it can't be determined. + */ +__EXPORT__ PHYSFS_sint64 PHYSFS_getLastModTime(const char *filename); + + /** * Read data from a PhysicsFS filehandle. The file must be opened for reading. * diff --git a/physfs_internal.h b/physfs_internal.h index 4995593..7a54260 100644 --- a/physfs_internal.h +++ b/physfs_internal.h @@ -175,6 +175,14 @@ typedef struct __PHYSFS_DIRFUNCTIONS__ */ int (*isSymLink)(DirHandle *r, const char *name); + /* + * Retrieve the last modification time (mtime) of a file. + * Returns -1 on failure, or the file's mtime in seconds since + * the epoch (Jan 1, 1970) on success. + * This filename is in platform-independent notation. + */ + PHYSFS_sint64 (*getLastModTime)(DirHandle *r, const char *filename); + /* * Open file for reading, and return a FileHandle. * This filename is in platform-independent notation. @@ -267,6 +275,7 @@ typedef struct __PHYSFS_DIRFUNCTIONS__ #define ERR_NOT_A_DIR "Not a directory" #define ERR_FILE_NOT_FOUND "File not found" + /* * Call this to set the message returned by PHYSFS_getLastError(). * Please only use the ERR_* constants above, or add new constants to the @@ -343,6 +352,7 @@ extern const char *__PHYSFS_platformDirSeparator; */ int __PHYSFS_platformInit(void); + /* * Deinitialize the platform. This is called when PHYSFS_deinit() is called * from the application. You can use this to clean up anything you've @@ -353,6 +363,7 @@ int __PHYSFS_platformInit(void); */ int __PHYSFS_platformDeinit(void); + /* * Open a file for reading. (filename) is in platform-dependent notation. The * file pointer should be positioned on the first byte of the file. @@ -368,6 +379,7 @@ int __PHYSFS_platformDeinit(void); */ void *__PHYSFS_platformOpenRead(const char *filename); + /* * Open a file for writing. (filename) is in platform-dependent notation. If * the file exists, it should be truncated to zero bytes, and if it doesn't @@ -384,6 +396,7 @@ void *__PHYSFS_platformOpenRead(const char *filename); */ void *__PHYSFS_platformOpenWrite(const char *filename); + /* * Open a file for appending. (filename) is in platform-dependent notation. If * the file exists, the file pointer should be place just past the end of the @@ -401,6 +414,7 @@ void *__PHYSFS_platformOpenWrite(const char *filename); */ void *__PHYSFS_platformOpenAppend(const char *filename); + /* * Read more data from a platform-specific file handle. (opaque) should be * cast to whatever data type your platform uses. Read a maximum of (count) @@ -441,6 +455,7 @@ PHYSFS_sint64 __PHYSFS_platformWrite(void *opaque, const void *buffer, */ int __PHYSFS_platformSeek(void *opaque, PHYSFS_uint64 pos); + /* * Get the file pointer's position, in an 8-bit byte offset from the start of * the file. (opaque) should be cast to whatever data type your platform @@ -453,6 +468,7 @@ int __PHYSFS_platformSeek(void *opaque, PHYSFS_uint64 pos); */ PHYSFS_sint64 __PHYSFS_platformTell(void *opaque); + /* * Determine the current size of a file, in 8-bit bytes, from an open file. * @@ -543,11 +559,21 @@ int __PHYSFS_platformStricmp(const char *str1, const char *str2); */ int __PHYSFS_platformExists(const char *fname); +/* + * Return the last modified time (in seconds since the epoch) of a file. + * Returns -1 on failure. (fname) is in platform-dependent notation. + * Symlinks should be followed; if what the symlink points to is missing, + * then the retval is -1. + */ +PHYSFS_sint64 __PHYSFS_platformGetLastModTime(const char *fname); + + /* * Return non-zero if filename (in platform-dependent notation) is a symlink. */ int __PHYSFS_platformIsSymLink(const char *fname); + /* * Return non-zero if filename (in platform-dependent notation) is a symlink. * Symlinks should be followed; if what the symlink points to is missing, @@ -555,6 +581,7 @@ int __PHYSFS_platformIsSymLink(const char *fname); */ int __PHYSFS_platformIsDirectory(const char *fname); + /* * Convert (dirName) to platform-dependent notation, then prepend (prepend) * and append (append) to the converted string. @@ -577,6 +604,7 @@ char *__PHYSFS_platformCvtToDependent(const char *prepend, const char *dirName, const char *append); + /* * Make the current thread give up a timeslice. This is called in a loop * while waiting for various external forces to get back to us. @@ -626,6 +654,7 @@ char *__PHYSFS_platformRealPath(const char *path); */ int __PHYSFS_platformMkDir(const char *path); + /* * Remove a file or directory entry in the actual filesystem. (path) is * specified in platform-dependent notation. Note that this deletes files diff --git a/platform/macclassic.c b/platform/macclassic.c index b9c96cb..35c980d 100644 --- a/platform/macclassic.c +++ b/platform/macclassic.c @@ -805,5 +805,11 @@ void __PHYSFS_platformReleaseMutex(void *mutex) /* no mutexes on MacOS Classic. */ } /* __PHYSFS_platformReleaseMutex */ + +PHYSFS_sint64 __PHYSFS_platformGetLastModTime(const char *fname) +{ + BAIL_MACRO(ERR_NOT_IMPLEMENTED, -1); /* !!! FIXME! */ +} /* __PHYSFS_platformGetLastModTime */ + /* end of macclassic.c ... */ diff --git a/platform/posix.c b/platform/posix.c index c87d2eb..9c38092 100644 --- a/platform/posix.c +++ b/platform/posix.c @@ -470,5 +470,13 @@ int __PHYSFS_platformDelete(const char *path) return(1); } /* __PHYSFS_platformDelete */ + +PHYSFS_sint64 __PHYSFS_platformGetLastModTime(const char *fname) +{ + struct stat statbuf; + BAIL_IF_MACRO(stat(fname, &statbuf) < 0, strerror(errno), -1); + return statbuf.st_mtime; +} /* __PHYSFS_platformGetLastModTime */ + /* end of posix.c ... */ diff --git a/platform/skeleton.c b/platform/skeleton.c index 052dd37..0509dc8 100644 --- a/platform/skeleton.c +++ b/platform/skeleton.c @@ -221,5 +221,11 @@ void __PHYSFS_platformReleaseMutex(void *mutex) /* not implemented, but can't call __PHYSFS_setError! */ } /* __PHYSFS_platformReleaseMutex */ + +PHYSFS_sint64 __PHYSFS_platformGetLastModTime(const char *fname) +{ + BAIL_MACRO(ERR_NOT_IMPLEMENTED, -1); +} /* __PHYSFS_platformGetLastModTime */ + /* end of skeleton.c ... */ diff --git a/platform/win32.c b/platform/win32.c index d5e3024..92a312c 100644 --- a/platform/win32.c +++ b/platform/win32.c @@ -886,5 +886,12 @@ static int doNTInit(void) return 1; } #endif + + +PHYSFS_sint64 __PHYSFS_platformGetLastModTime(const char *fname) +{ + BAIL_MACRO(ERR_NOT_IMPLEMENTED, -1); /* !!! FIXME! */ +} /* __PHYSFS_platformGetLastModTime */ + /* end of win32.c ... */