THIS is Christoph's PHYSFS_stat() work.
I've merged some basic ideas from the other patch, which was Indy Sam's work,
and cleaned up a few things.
--- a/docs/CREDITS.txt Mon Feb 15 09:19:38 2010 -0500
+++ b/docs/CREDITS.txt Mon Feb 15 14:02:36 2010 -0500
@@ -105,6 +105,10 @@
Bug fixes:
Patrice Mandin
+PHYSFS_stat() API:
+ Christoph Nelles
+ Indy Sams
+
Other stuff:
Your name here! Patches go to icculus@icculus.org ...
--- a/extras/physfs-swig.i Mon Feb 15 09:19:38 2010 -0500
+++ b/extras/physfs-swig.i Mon Feb 15 14:02:36 2010 -0500
@@ -83,6 +83,8 @@
%rename(symbolicLinksPermitted) PHYSFS_symbolicLinksPermitted;
%rename(mount) PHYSFS_mount;
%rename(getMountPoint) PHYSFS_getMountPoint;
+%rename(Stat) PHYSFS_Stat; /* !!! FIXME: case insensitive script languages? */
+%rename(stat) PHYSFS_stat;
#endif /* SWIGPERL */
%include "../src/physfs.h"
--- a/src/archiver_dir.c Mon Feb 15 09:19:38 2010 -0500
+++ b/src/archiver_dir.c Mon Feb 15 14:02:36 2010 -0500
@@ -243,6 +243,18 @@
} /* DIR_dirClose */
+static int DIR_stat(fvoid *opaque, const char *name, int *exists,
+ PHYSFS_Stat *stat)
+{
+ char *d = __PHYSFS_platformCvtToDependent((char *) opaque, name, NULL);
+ int retval = 0;
+
+ BAIL_IF_MACRO(d == NULL, NULL, 0);
+ retval = __PHYSFS_platformStat(d, exists, stat);
+ allocator.Free(d);
+ return retval;
+} /* DIR_stat */
+
const PHYSFS_ArchiveInfo __PHYSFS_ArchiveInfo_DIR =
{
@@ -253,7 +265,6 @@
};
-
const PHYSFS_Archiver __PHYSFS_Archiver_DIR =
{
&__PHYSFS_ArchiveInfo_DIR,
@@ -276,7 +287,8 @@
DIR_tell, /* tell() method */
DIR_seek, /* seek() method */
DIR_fileLength, /* fileLength() method */
- DIR_fileClose /* fileClose() method */
+ DIR_fileClose, /* fileClose() method */
+ DIR_stat /* stat() method */
};
/* end of dir.c ... */
--- a/src/archiver_grp.c Mon Feb 15 09:19:38 2010 -0500
+++ b/src/archiver_grp.c Mon Feb 15 14:02:36 2010 -0500
@@ -316,7 +316,7 @@
} /* GRP_enumerateFiles */
-static GRPentry *grp_find_entry(GRPinfo *info, const char *name)
+static GRPentry *grp_find_entry(const GRPinfo *info, const char *name)
{
char *ptr = strchr(name, '.');
GRPentry *a = info->entries;
@@ -435,6 +435,27 @@
} /* GRP_mkdir */
+static int GRP_stat(fvoid *opaque, const char *filename, int *exists,
+ PHYSFS_Stat *stat)
+{
+ const GRPinfo *info = (const GRPinfo *) opaque;
+ const GRPentry *entry = grp_find_entry(info, filename);
+
+ *exists = (entry != 0);
+ if (!entry)
+ return 0;
+
+ stat->filesize = entry->size;
+ stat->filetype = PHYSFS_FILETYPE_REGULAR;
+ stat->modtime = info->last_mod_time;
+ stat->createtime = info->last_mod_time;
+ stat->accesstime = -1;
+ stat->readonly = 1;
+
+ return 0;
+} /* GRP_stat */
+
+
const PHYSFS_ArchiveInfo __PHYSFS_ArchiveInfo_GRP =
{
"GRP",
@@ -466,7 +487,8 @@
GRP_tell, /* tell() method */
GRP_seek, /* seek() method */
GRP_fileLength, /* fileLength() method */
- GRP_fileClose /* fileClose() method */
+ GRP_fileClose, /* fileClose() method */
+ GRP_stat /* stat() method */
};
#endif /* defined PHYSFS_SUPPORTS_GRP */
--- a/src/archiver_hog.c Mon Feb 15 09:19:38 2010 -0500
+++ b/src/archiver_hog.c Mon Feb 15 14:02:36 2010 -0500
@@ -355,7 +355,7 @@
} /* HOG_enumerateFiles */
-static HOGentry *hog_find_entry(HOGinfo *info, const char *name)
+static HOGentry *hog_find_entry(const HOGinfo *info, const char *name)
{
char *ptr = strchr(name, '.');
HOGentry *a = info->entries;
@@ -474,6 +474,27 @@
} /* HOG_mkdir */
+static int HOG_stat(fvoid *opaque, const char *filename, int *exists,
+ PHYSFS_Stat *stat)
+{
+ const HOGinfo *info = (const HOGinfo *) opaque;
+ const HOGentry *entry = hog_find_entry(info, filename);
+
+ *exists = (entry != 0);
+ if (!entry)
+ return 0;
+
+ stat->filesize = entry->size;
+ stat->filetype = PHYSFS_FILETYPE_REGULAR;
+ stat->modtime = info->last_mod_time;
+ stat->createtime = info->last_mod_time;
+ stat->accesstime = -1;
+ stat->readonly = 1;
+
+ return 0;
+} /* HOG_stat */
+
+
const PHYSFS_ArchiveInfo __PHYSFS_ArchiveInfo_HOG =
{
"HOG",
@@ -505,7 +526,8 @@
HOG_tell, /* tell() method */
HOG_seek, /* seek() method */
HOG_fileLength, /* fileLength() method */
- HOG_fileClose /* fileClose() method */
+ HOG_fileClose, /* fileClose() method */
+ HOG_stat /* stat() method */
};
#endif /* defined PHYSFS_SUPPORTS_HOG */
--- a/src/archiver_lzma.c Mon Feb 15 09:19:38 2010 -0500
+++ b/src/archiver_lzma.c Mon Feb 15 14:02:36 2010 -0500
@@ -207,7 +207,7 @@
/*
* Find entry 'name' in 'archive'
*/
-static LZMAfile * lzma_find_file(LZMAarchive *archive, const char *name)
+static LZMAfile * lzma_find_file(const LZMAarchive *archive, const char *name)
{
LZMAfile *file = bsearch(name, archive->files, archive->db.Database.NumFiles, sizeof(*archive->files), lzma_file_cmp_stdlib); /* FIXME: Should become __PHYSFS_search!!! */
@@ -695,6 +695,42 @@
BAIL_MACRO(ERR_NOT_SUPPORTED, 0);
} /* LZMA_mkdir */
+static int LZMA_stat(fvoid *opaque, const char *filename, int *exists,
+ PHYSFS_Stat *stat)
+{
+ const LZMAarchive *archive = (const LZMAarchive *) opaque;
+ const LZMAfile *file = lzma_find_file(archive, filename);
+
+ *exists = (file != 0);
+ if (!file)
+ return 0;
+
+ if(file->item->IsDirectory)
+ {
+ stat->filesize = 0;
+ stat->filetype = PHYSFS_FILETYPE_DIRECTORY;
+ } /* if */
+ else
+ {
+ stat->filesize = (PHYSFS_sint64) file->item->Size;
+ stat->filetype = PHYSFS_FILETYPE_REGULAR;
+ } /* else */
+
+ /* !!! FIXME: the 0's should be -1's? */
+ if (file->item->IsLastWriteTimeDefined)
+ stat->modtime = lzma_filetime_to_unix_timestamp(&file->item->LastWriteTime);
+ else
+ stat->modtime = 0;
+
+ /* real create and accesstype are currently not in the lzma SDK */
+ stat->createtime = stat->modtime;
+ stat->accesstime = 0;
+
+ stat->readonly = 1; /* 7zips are always read only */
+
+ return 0;
+} /* LZMA_stat */
+
const PHYSFS_ArchiveInfo __PHYSFS_ArchiveInfo_LZMA =
{
@@ -727,7 +763,8 @@
LZMA_tell, /* tell() method */
LZMA_seek, /* seek() method */
LZMA_fileLength, /* fileLength() method */
- LZMA_fileClose /* fileClose() method */
+ LZMA_fileClose, /* fileClose() method */
+ LZMA_stat /* stat() method */
};
#endif /* defined PHYSFS_SUPPORTS_7Z */
--- a/src/archiver_mvl.c Mon Feb 15 09:19:38 2010 -0500
+++ b/src/archiver_mvl.c Mon Feb 15 14:02:36 2010 -0500
@@ -312,7 +312,7 @@
} /* MVL_enumerateFiles */
-static MVLentry *mvl_find_entry(MVLinfo *info, const char *name)
+static MVLentry *mvl_find_entry(const MVLinfo *info, const char *name)
{
char *ptr = strchr(name, '.');
MVLentry *a = info->entries;
@@ -431,6 +431,27 @@
} /* MVL_mkdir */
+static int MVL_stat(fvoid *opaque, const char *filename, int *exists,
+ PHYSFS_Stat *stat)
+{
+ const MVLinfo *info = (const MVLinfo *) opaque;
+ const MVLentry *entry = mvl_find_entry(info, filename);
+
+ *exists = (entry != 0);
+ if (!entry)
+ return 0;
+
+ stat->filesize = entry->size;
+ stat->filetype = PHYSFS_FILETYPE_REGULAR;
+ stat->modtime = info->last_mod_time;
+ stat->createtime = info->last_mod_time;
+ stat->accesstime = 0;
+ stat->readonly = 1;
+
+ return 0;
+} /* MVL_stat */
+
+
const PHYSFS_ArchiveInfo __PHYSFS_ArchiveInfo_MVL =
{
"MVL",
@@ -462,7 +483,8 @@
MVL_tell, /* tell() method */
MVL_seek, /* seek() method */
MVL_fileLength, /* fileLength() method */
- MVL_fileClose /* fileClose() method */
+ MVL_fileClose, /* fileClose() method */
+ MVL_stat /* stat() method */
};
#endif /* defined PHYSFS_SUPPORTS_MVL */
--- a/src/archiver_qpak.c Mon Feb 15 09:19:38 2010 -0500
+++ b/src/archiver_qpak.c Mon Feb 15 14:02:36 2010 -0500
@@ -445,7 +445,8 @@
* notation. Directories don't have QPAKentries associated with them, but
* (*isDir) will be set to non-zero if a dir was hit.
*/
-static QPAKentry *qpak_find_entry(QPAKinfo *info, const char *path, int *isDir)
+static QPAKentry *qpak_find_entry(const QPAKinfo *info, const char *path,
+ int *isDir)
{
QPAKentry *a = info->entries;
PHYSFS_sint32 pathlen = strlen(path);
@@ -590,6 +591,37 @@
} /* QPAK_mkdir */
+static int QPAK_stat(fvoid *opaque, const char *filename, int *exists,
+ PHYSFS_Stat *stat)
+{
+ int isDir = 0;
+ const QPAKinfo *info = (const QPAKinfo *) opaque;
+ const QPAKentry *entry = qpak_find_entry(info, filename, &isDir);
+
+ *exists = ((isDir) || (entry != NULL));
+ if (!exists)
+ return 0;
+
+ if (isDir)
+ {
+ stat->filetype = PHYSFS_FILETYPE_DIRECTORY;
+ stat->filesize = 0;
+ } /* if */
+ else
+ {
+ stat->filetype = PHYSFS_FILETYPE_REGULAR;
+ stat->filesize = entry->size;
+ } /* else */
+
+ stat->modtime = info->last_mod_time;
+ stat->createtime = info->last_mod_time;
+ stat->accesstime = 0;
+ stat->readonly = 1;
+
+ return 0;
+} /* QPAK_stat */
+
+
const PHYSFS_ArchiveInfo __PHYSFS_ArchiveInfo_QPAK =
{
"PAK",
@@ -621,7 +653,8 @@
QPAK_tell, /* tell() method */
QPAK_seek, /* seek() method */
QPAK_fileLength, /* fileLength() method */
- QPAK_fileClose /* fileClose() method */
+ QPAK_fileClose, /* fileClose() method */
+ QPAK_stat /* stat() method */
};
#endif /* defined PHYSFS_SUPPORTS_QPAK */
--- a/src/archiver_wad.c Mon Feb 15 09:19:38 2010 -0500
+++ b/src/archiver_wad.c Mon Feb 15 14:02:36 2010 -0500
@@ -361,7 +361,7 @@
} /* WAD_enumerateFiles */
-static WADentry *wad_find_entry(WADinfo *info, const char *name)
+static WADentry *wad_find_entry(const WADinfo *info, const char *name)
{
WADentry *a = info->entries;
PHYSFS_sint32 lo = 0;
@@ -494,6 +494,27 @@
} /* WAD_mkdir */
+static int WAD_stat(fvoid *opaque, const char *filename, int *exists,
+ PHYSFS_Stat *stat)
+{
+ const WADinfo *info = (const WADinfo *) opaque;
+ const WADentry *entry = wad_find_entry(info, filename);
+
+ *exists = (entry != 0);
+ if (!entry)
+ return 0;
+
+ stat->filesize = entry->size;
+ stat->filetype = PHYSFS_FILETYPE_REGULAR;
+ stat->accesstime = 0;
+ stat->modtime = ((WADinfo *) opaque)->last_mod_time;
+ stat->createtime = ((WADinfo *) opaque)->last_mod_time;
+ stat->readonly = 1; /* WADs are always readonly */
+
+ return 0;
+} /* WAD_stat */
+
+
const PHYSFS_ArchiveInfo __PHYSFS_ArchiveInfo_WAD =
{
"WAD",
@@ -525,7 +546,8 @@
WAD_tell, /* tell() method */
WAD_seek, /* seek() method */
WAD_fileLength, /* fileLength() method */
- WAD_fileClose /* fileClose() method */
+ WAD_fileClose, /* fileClose() method */
+ WAD_stat /* stat() method */
};
#endif /* defined PHYSFS_SUPPORTS_WAD */
--- a/src/archiver_zip.c Mon Feb 15 09:19:38 2010 -0500
+++ b/src/archiver_zip.c Mon Feb 15 14:02:36 2010 -0500
@@ -509,7 +509,8 @@
* notation. Directories don't have ZIPentries associated with them, but
* (*isDir) will be set to non-zero if a dir was hit.
*/
-static ZIPentry *zip_find_entry(ZIPinfo *info, const char *path, int *isDir)
+static ZIPentry *zip_find_entry(const ZIPinfo *info, const char *path,
+ int *isDir)
{
ZIPentry *a = info->entries;
PHYSFS_sint32 pathlen = strlen(path);
@@ -1406,6 +1407,44 @@
} /* ZIP_mkdir */
+static int ZIP_stat(fvoid *opaque, const char *filename, int *exists,
+ PHYSFS_Stat *stat)
+{
+ int isDir = 0;
+ const ZIPinfo *info = (const ZIPinfo *) opaque;
+ const ZIPentry *entry = zip_find_entry(info, filename, &isDir);
+
+ *exists = isDir || (entry != 0);
+ if (!*exists)
+ return 0;
+
+ if (isDir)
+ {
+ stat->filesize = 0;
+ stat->filetype = PHYSFS_FILETYPE_DIRECTORY;
+ } /* if */
+
+ else if (zip_entry_is_symlink(entry))
+ {
+ stat->filesize = 0;
+ stat->filetype = PHYSFS_FILETYPE_SYMLINK;
+ } /* else if */
+
+ else
+ {
+ stat->filesize = entry->uncompressed_size;
+ stat->filetype = PHYSFS_FILETYPE_REGULAR;
+ } /* else */
+
+ stat->modtime = ((entry) ? entry->last_mod_time : 0);
+ stat->createtime = stat->modtime;
+ stat->accesstime = 0;
+ stat->readonly = 1; /* .zip files are always read only */
+
+ return 0;
+} /* ZIP_stat */
+
+
const PHYSFS_ArchiveInfo __PHYSFS_ArchiveInfo_ZIP =
{
"ZIP",
@@ -1437,7 +1476,8 @@
ZIP_tell, /* tell() method */
ZIP_seek, /* seek() method */
ZIP_fileLength, /* fileLength() method */
- ZIP_fileClose /* fileClose() method */
+ ZIP_fileClose, /* fileClose() method */
+ ZIP_stat /* stat() method */
};
#endif /* defined PHYSFS_SUPPORTS_ZIP */
--- a/src/physfs.c Mon Feb 15 09:19:38 2010 -0500
+++ b/src/physfs.c Mon Feb 15 14:02:36 2010 -0500
@@ -2144,6 +2144,56 @@
} /* PHYSFS_flush */
+int PHYSFS_stat(const char *_fname, PHYSFS_Stat *stat)
+{
+ int retval = 0;
+ char *fname;
+ size_t len;
+
+ BAIL_IF_MACRO(_fname == NULL, ERR_INVALID_ARGUMENT, -1);
+ BAIL_IF_MACRO(stat == NULL, ERR_INVALID_ARGUMENT, -1);
+ len = strlen(_fname) + 1;
+ fname = (char *) __PHYSFS_smallAlloc(len);
+ BAIL_IF_MACRO(fname == NULL, ERR_OUT_OF_MEMORY, -1);
+
+ /* !!! FIXME: what should this be set to if we fail completely? */
+ memset(stat, '\0', sizeof (PHYSFS_Stat));
+
+ if (sanitizePlatformIndependentPath(_fname, fname))
+ {
+ if (*fname == '\0')
+ {
+ stat->filetype = PHYSFS_FILETYPE_DIRECTORY;
+ stat->readonly = !writeDir; /* Writeable if we have a writeDir */
+ retval = 0;
+ } /* 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))
+ {
+ stat->readonly = !(writeDir &&
+ (strcmp(writeDir->dirName, i->dirName) == 0));
+ retval = i->funcs->stat(i->opaque, arcfname, &exists, stat);
+ } /* else if */
+ } /* for */
+ __PHYSFS_platformReleaseMutex(stateLock);
+ } /* else */
+ } /* if */
+
+ __PHYSFS_smallFree(fname);
+ return retval;
+} /* PHYSFS_stat */
+
+
int PHYSFS_setAllocator(const PHYSFS_Allocator *a)
{
BAIL_IF_MACRO(initialized, ERR_IS_INITIALIZED, 0);
--- a/src/physfs.h Mon Feb 15 09:19:38 2010 -0500
+++ b/src/physfs.h Mon Feb 15 14:02:36 2010 -0500
@@ -417,7 +417,6 @@
} PHYSFS_Version;
-
#ifndef SWIG /* not available from scripting languages. */
#ifndef DOXYGEN_SHOULD_IGNORE_THIS
@@ -2462,6 +2461,60 @@
#endif /* SWIG */
+/**
+ * \enum PHYSFS_FileType
+ * \brief Type of a File
+ *
+ * Possible types of a file.
+ *
+ * \sa PHYSFS_stat
+ */
+typedef enum PHYSFS_FileType
+{
+ PHYSFS_FILETYPE_REGULAR, /**< a normal file */
+ PHYSFS_FILETYPE_DIRECTORY, /**< a directory */
+ PHYSFS_FILETYPE_SYMLINK, /**< a symlink */
+ PHYSFS_FILETYPE_OTHER /**< something completely different like a device */
+} PHYSFS_FileType;
+
+/**
+ * \struct PHYSFS_Stat
+ * \brief Meta data for a file or directory
+ *
+ * Container for various meta data about a file in the virtual file system.
+ * PHYSFS_stat() uses this structure for returning the information. The time
+ * data will be either a real timestamp or -1 if there is none. So every value
+ * is at least epoch. The FileSize is only valid for real files. And the
+ * readonly tells you whether when you open a file for writing you are writing
+ * to the same file as if you were opening it, given you have enough
+ * filesystem rights to do that.
+ *
+ * \sa PHYSFS_stat
+ * \sa PHYSFS_FileType
+ */
+typedef struct PHYSFS_Stat
+{
+ PHYSFS_sint64 filesize; /**< size in bytes, -1 for non-files and unknown */
+ PHYSFS_sint64 modtime; /**< same value as PHYSFS_getLastModTime() */
+ PHYSFS_sint64 createtime; /**< like modtime, but for file creation time */
+ PHYSFS_sint64 accesstime; /**< like modtime, but for file access time */
+ PHYSFS_FileType filetype; /**< File? Directory? Symlink? */
+ int readonly; /**< non-zero if read only, zero if writable. */
+} PHYSFS_Stat;
+
+/**
+ * \fn int PHYSFS_stat(const char *fname, PHYSFS_Stat *stat)
+ * \brief Get various information about a directory or a file.
+ *
+ * Obtain various information about a file or directory from the meta data.
+ *
+ * \param fname filename to check, in platform-indepedent notation.
+ * \param stat pointer to structure to fill in with data about (fname).
+ * \return 0 on success, non-zero on error.
+ *
+ * \sa PHYSFS_Stat
+ */
+PHYSFS_DECL int PHYSFS_stat(const char *fname, PHYSFS_Stat *stat);
/* Everything above this line is part of the PhysicsFS 2.1 API. */
--- a/src/physfs_internal.h Mon Feb 15 09:19:38 2010 -0500
+++ b/src/physfs_internal.h Mon Feb 15 14:02:36 2010 -0500
@@ -937,6 +937,13 @@
* file. On failure, call __PHYSFS_setError().
*/
int (*fileClose)(fvoid *opaque);
+
+ /* !!! FIXME: return info (may be|is) wrong.
+ * Obtain basic file metadata.
+ * Returns non-zero on success, zero if can't close
+ * file. On failure, call __PHYSFS_setError().
+ */
+ int (*stat)(fvoid *opaque, const char *fn, int *exists, PHYSFS_Stat *stat);
} PHYSFS_Archiver;
@@ -1244,6 +1251,13 @@
*/
PHYSFS_sint64 __PHYSFS_platformFileLength(void *handle);
+
+/*
+ * !!! FIXME: comment me.
+ */
+int __PHYSFS_platformStat(const char *fn, int *exists, PHYSFS_Stat *stat);
+
+
/*
* Determine if a file is at EOF. (opaque) should be cast to whatever data
* type your platform uses.
--- a/src/platform_os2.c Mon Feb 15 09:19:38 2010 -0500
+++ b/src/platform_os2.c Mon Feb 15 14:02:36 2010 -0500
@@ -631,6 +631,25 @@
} /* __PHYSFS_platformDelete */
+/* Convert to a format PhysicsFS can grok... */
+PHYSFS_sint64 os2TimeToUnixTime(const FDATE *date, const FTIME *time)
+{
+ struct tm tm;
+
+ tm.tm_sec = ((PHYSFS_uint32) time->.twosecs) * 2;
+ tm.tm_min = time->minutes;
+ tm.tm_hour = time->hours;
+ tm.tm_mday = date->day;
+ tm.tm_mon = date->month;
+ tm.tm_year = ((PHYSFS_uint32) date->year) + 80;
+ tm.tm_wday = -1 /*st_localtz.wDayOfWeek*/;
+ tm.tm_yday = -1;
+ tm.tm_isdst = -1;
+
+ return (PHYSFS_sint64) mktime(&tm);
+} /* os2TimeToUnixTime */
+
+
PHYSFS_sint64 __PHYSFS_platformGetLastModTime(const char *_fname)
{
const unsigned char *fname = (const unsigned char *) _fname;
@@ -640,24 +659,63 @@
APIRET rc = DosQueryPathInfo(fname, FIL_STANDARD, &fs, sizeof (fs));
BAIL_IF_MACRO(os2err(rc) != NO_ERROR, NULL, -1);
- /* Convert to a format that mktime() can grok... */
- tm.tm_sec = ((PHYSFS_uint32) fs.ftimeLastWrite.twosecs) * 2;
- tm.tm_min = fs.ftimeLastWrite.minutes;
- tm.tm_hour = fs.ftimeLastWrite.hours;
- tm.tm_mday = fs.fdateLastWrite.day;
- tm.tm_mon = fs.fdateLastWrite.month;
- tm.tm_year = ((PHYSFS_uint32) fs.fdateLastWrite.year) + 80;
- tm.tm_wday = -1 /*st_localtz.wDayOfWeek*/;
- tm.tm_yday = -1;
- tm.tm_isdst = -1;
+ /* Convert to a format PhysicsFS can grok... */
+ retval = os2TimeToUnixTime(&fs.fdateLastWrite, &fs.ftimeLastWrite);
- /* Convert to a format PhysicsFS can grok... */
- retval = (PHYSFS_sint64) mktime(&tm);
BAIL_IF_MACRO(retval == -1, strerror(errno), -1);
return retval;
} /* __PHYSFS_platformGetLastModTime */
+static int __PHYSFS_platformStat(const char *_fname, int *exists,
+ PHYSFS_Stat *stat)
+{
+ struct tm tm;
+ FILESTATUS3 fs;
+ const unsigned char *fname = (const unsigned char *) _fname;
+ const APIRET rc = DosQueryPathInfo(fname, FIL_STANDARD, &fs, sizeof (fs));
+
+ if (rc != NO_ERROR)
+ {
+ if (rc == ERROR_PATH_NOT_FOUND)
+ {
+ *exists = 0;
+ return 0;
+ } /* if */
+ BAIL_MACRO(get_os2_error_string(rc), -1);
+ } /* if */
+
+ *exists = 1;
+
+ if (fs.attrFile & FILE_DIRECTORY)
+ {
+ stat->filetype = PHYSFS_FILETYPE_DIRECTORY;
+ stat->filesize = 0;
+ } /* if */
+ else
+ {
+ stat->filetype = PHYSFS_FILETYPE_REGULAR;
+ stat->filesize = fs.cbFile;
+ } /* else */
+
+ stat->modtime = os2TimeToUnixTime(&fs.fdateLastWrite, &fs.ftimeLastWrite);
+ if (stat->modtime < 0)
+ stat->modtime = 0;
+
+ stat->accesstime = os2TimeToUnixTime(&fs.fdateLastAccess, &fs.ftimeLastAccess);
+ if (stat->accesstime < 0)
+ stat->accesstime = 0;
+
+ stat->createtime = os2TimeToUnixTime(&fs.fdateCreation, &fs.ftimeCreation);
+ if (stat->createtime < 0)
+ stat->createtime = 0;
+
+ stat->readonly = ((fs.attrFile & FILE_READONLY) == FILE_READONLY);
+
+ return 0;
+} /* __PHYSFS_platformStat */
+
+
void *__PHYSFS_platformGetThreadID(void)
{
PTIB ptib;
--- a/src/platform_pocketpc.c Mon Feb 15 09:19:38 2010 -0500
+++ b/src/platform_pocketpc.c Mon Feb 15 14:02:36 2010 -0500
@@ -561,6 +561,103 @@
} /* __PHYSFS_platformDelete */
+/* Shamelessly copied from platform_windows.c */
+static PHYSFS_sint64 FileTimeToPhysfsTime(const FILETIME *ft)
+{
+ SYSTEMTIME st_utc;
+ SYSTEMTIME st_localtz;
+ TIME_ZONE_INFORMATION tzi;
+ DWORD tzid;
+ PHYSFS_sint64 retval;
+ struct tm tm;
+
+ BAIL_IF_MACRO(!FileTimeToSystemTime(ft, &st_utc), winApiStrError(), -1);
+ tzid = GetTimeZoneInformation(&tzi);
+ BAIL_IF_MACRO(tzid == TIME_ZONE_ID_INVALID, winApiStrError(), -1);
+
+ /* (This API is unsupported and fails on non-NT systems. */
+ if (!SystemTimeToTzSpecificLocalTime(&tzi, &st_utc, &st_localtz))
+ {
+ /* do it by hand. Grumble... */
+ ULARGE_INTEGER ui64;
+ FILETIME new_ft;
+ ui64.LowPart = ft->dwLowDateTime;
+ ui64.HighPart = ft->dwHighDateTime;
+
+ if (tzid == TIME_ZONE_ID_STANDARD)
+ tzi.Bias += tzi.StandardBias;
+ else if (tzid == TIME_ZONE_ID_DAYLIGHT)
+ tzi.Bias += tzi.DaylightBias;
+
+ /* convert from minutes to 100-nanosecond increments... */
+ ui64.QuadPart -= (((LONGLONG) tzi.Bias) * (600000000));
+
+ /* Move it back into a FILETIME structure... */
+ new_ft.dwLowDateTime = ui64.LowPart;
+ new_ft.dwHighDateTime = ui64.HighPart;
+
+ /* Convert to something human-readable... */
+ if (!FileTimeToSystemTime(&new_ft, &st_localtz))
+ BAIL_MACRO(winApiStrError(), -1);
+ } /* if */
+
+ /* Convert to a format that mktime() can grok... */
+ tm.tm_sec = st_localtz.wSecond;
+ tm.tm_min = st_localtz.wMinute;
+ tm.tm_hour = st_localtz.wHour;
+ tm.tm_mday = st_localtz.wDay;
+ tm.tm_mon = st_localtz.wMonth - 1;
+ tm.tm_year = st_localtz.wYear - 1900;
+ tm.tm_wday = -1 /*st_localtz.wDayOfWeek*/;
+ tm.tm_yday = -1;
+ tm.tm_isdst = -1;
+
+ /* Convert to a format PhysicsFS can grok... */
+ retval = (PHYSFS_sint64) mktime(&tm);
+ BAIL_IF_MACRO(retval == -1, strerror(errno), -1);
+ return retval;
+} /* FileTimeToPhysfsTime */
+
+
+int __PHYSFS_platformStat(const char *filename, int *exists, PHYSFS_Stat *stat)
+{
+ WIN32_FIND_DATA winstat;
+ const HANDLE searchhandle = FindFirstFile(filename, &winstat);
+
+ if (searchhandle == INVALID_HANDLE_VALUE) /* call failed? */
+ {
+ /* !!! FIXME: FindFirstFile() doesn't set errno. Use GetLastError()?. */
+ if (errno == ERROR_FILE_NOT_FOUND)
+ {
+ *exists = 0;
+ return 0;
+ } /* if */
+ BAIL_MACRO(win32strerror, -1);
+ } /* if */
+
+ FindClose(searchhandle); /* close handle, not needed anymore */
+
+ *exists = 1;
+
+ if(winstat.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+ stat->filetype = PHYSFS_FILETYPE_DIRECTORY;
+ else if (winstat.dwFileAttributes & (FILE_ATTRIBUTE_OFFLINE | FILE_ATTRIBUTE_ROMMODULE))
+ stat->filetype = PHYSFS_FILETYPE_OTHER;
+ else
+ stat->filetype = PHYSFS_FILETYPE_OTHER; /* !!! FIXME: _REGULAR? */
+
+ if (stat->filetype == PHYSFS_FILETYPE_REGULAR)
+ stat->filesize = (((PHYSFS_uint64) winstat.nFileSizeHigh) << 32) | winstat.nFileSizeLow;
+
+ stat->modtime = FileTimeToPhysfsTime(&winstat.ftLastWriteTime);
+ stat->accesstime = FileTimeToPhysfsTime(&winstat.ftLastAccessTime);
+ stat->createtime = FileTimeToPhysfsTime(&winstat.ftCreationTime);
+ stat->readonly = ((winstat.dwFileAttributes & (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_INROM)) != 0);
+
+ return 0;
+} /* __PHYSFS_platformStat */
+
+
/*
* !!! FIXME: why aren't we using Critical Sections instead of Mutexes?
* !!! FIXME: mutexes on Windows are for cross-process sync. CritSects are
@@ -568,7 +665,7 @@
*/
void *__PHYSFS_platformCreateMutex(void)
{
- return (void * CreateMutex(NULL, FALSE, NULL));
+ return ((void *) CreateMutex(NULL, FALSE, NULL));
} /* __PHYSFS_platformCreateMutex */
--- a/src/platform_posix.c Mon Feb 15 09:19:38 2010 -0500
+++ b/src/platform_posix.c Mon Feb 15 14:02:36 2010 -0500
@@ -405,6 +405,52 @@
return statbuf.st_mtime;
} /* __PHYSFS_platformGetLastModTime */
+
+int __PHYSFS_platformStat(const char *filename, int *exists, PHYSFS_Stat *st)
+{
+ struct stat statbuf;
+
+ /* !!! FIXME: lstat()? */
+ if (stat(filename, &statbuf))
+ {
+ if (errno == ENOENT)
+ {
+ *exists = 0;
+ return 0;
+ } /* if */
+ else
+ {
+ BAIL_MACRO(strerror(errno), -1);
+ } /* else */
+ } /* if */
+
+ if (S_ISREG(statbuf.st_mode))
+ {
+ st->filetype = PHYSFS_FILETYPE_REGULAR;
+ st->filesize = statbuf.st_size;
+ } /* if */
+
+ else if(S_ISDIR(statbuf.st_mode))
+ {
+ st->filetype = PHYSFS_FILETYPE_DIRECTORY;
+ st->filesize = 0;
+ } /* else if */
+
+ else
+ {
+ st->filetype = PHYSFS_FILETYPE_OTHER;
+ st->filesize = statbuf.st_size;
+ } /* else */
+
+ st->modtime = statbuf.st_mtime;
+ st->createtime = statbuf.st_ctime;
+ st->accesstime = statbuf.st_atime;
+
+ /* !!! FIXME: maybe we should just report full permissions? */
+ st->readonly = access(filename, W_OK);
+ return 0;
+} /* __PHYSFS_platformStat */
+
#endif /* PHYSFS_PLATFORM_POSIX */
/* end of posix.c ... */
--- a/src/platform_unix.c Mon Feb 15 09:19:38 2010 -0500
+++ b/src/platform_unix.c Mon Feb 15 14:02:36 2010 -0500
@@ -24,7 +24,7 @@
#include <time.h>
#include <errno.h>
-#if (!defined PHYSFS_NO_THREAD_SUPPORT)
+#if (!defined PHYSFS_NO_PTHREADS_SUPPORT)
#include <pthread.h>
#endif
@@ -345,7 +345,7 @@
} /* __PHYSFS_platformSetDefaultAllocator */
-#if (defined PHYSFS_NO_THREAD_SUPPORT)
+#if (defined PHYSFS_NO_PTHREADS_SUPPORT)
void *__PHYSFS_platformGetThreadID(void) { return ((void *) 0x0001); }
void *__PHYSFS_platformCreateMutex(void) { return ((void *) 0x0001); }
@@ -429,7 +429,7 @@
} /* if */
} /* __PHYSFS_platformReleaseMutex */
-#endif /* !PHYSFS_NO_THREAD_SUPPORT */
+#endif /* !PHYSFS_NO_PTHREADS_SUPPORT */
#endif /* PHYSFS_PLATFORM_UNIX */
--- a/src/platform_windows.c Mon Feb 15 09:19:38 2010 -0500
+++ b/src/platform_windows.c Mon Feb 15 14:02:36 2010 -0500
@@ -1390,6 +1390,127 @@
} /* __PHYSFS_platformGetLastModTime */
+static int __PHYSFS_platformStatOldWay(const char *filename, int *exists,
+ PHYSFS_Stat *stat)
+{
+ WIN32_FIND_DATA winstat;
+ const HANDLE searchhandle = FindFirstFile(filename, &winstat);
+
+ if (searchhandle == INVALID_HANDLE_VALUE) /* call failed? */
+ {
+ /* !!! FIXME: not errno...try GetLastError() */
+ if (errno == ERROR_FILE_NOT_FOUND)
+ {
+ *exists = 0;
+ return 0;
+ } /* if */
+ BAIL_MACRO(strerror(errno), -1);
+ } /* if */
+
+ FindClose(searchhandle); /* close handle, not needed anymore */
+
+ *exists = 1;
+
+ if (winstat.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+ stat->filetype = PHYSFS_FILETYPE_DIRECTORY;
+ else if (winstat.dwFileAttributes & FILE_ATTRIBUTE_OFFLINE)
+ stat->filetype = PHYSFS_FILETYPE_OTHER;
+ else
+ stat->filetype = PHYSFS_FILETYPE_OTHER; /* !!! FIXME: _REGULAR? */
+
+ if (stat->filetype == PHYSFS_FILETYPE_REGULAR)
+ stat->filesize = (((PHYSFS_uint64) winstat.nFileSizeHigh) << 32) | winstat.nFileSizeLow;
+
+ stat->modtime = FileTimeToPhysfsTime(&winstat.ftLastWriteTime);
+ stat->accesstime = FileTimeToPhysfsTime(&winstat.ftLastAccessTime);
+ stat->createtime = FileTimeToPhysfsTime(&winstat.ftCreationTime);
+ stat->readonly = ((winstat.dwFileAttributes & FILE_ATTRIBUTE_READONLY) != 0);
+
+ return 0;
+} /* __PHYSFS_platformStatOldWay */
+
+
+static int __PHYSFS_platformStatNewWay(const char *filename, int *exists,
+ PHYSFS_Stat *stat)
+{
+ WIN32_FILE_ATTRIBUTE_DATA winstat;
+ WCHAR *wstr = NULL;
+ BOOL rc = 0;
+
+ UTF8_TO_UNICODE_STACK_MACRO(wstr, filename);
+ if (!wstr) /* maybe better luck in the old way... */
+ return __PHYSFS_platformStatOldWay(filename, exists, stat);
+
+ if (pGetFileAttributesExW)
+ rc = pGetFileAttributesExW(wstr, GetFileExInfoStandard, &winstat);
+ else
+ {
+ const int len = (int) (wStrLen(wstr) + 1);
+ char *cp = (char *) __PHYSFS_smallAlloc(len);
+ if (cp)
+ {
+ WideCharToMultiByte(CP_ACP, 0, wstr, len, cp, len, 0, 0);
+ rc = pGetFileAttributesExA(cp, GetFileExInfoStandard, &winstat);
+ } /* if */
+ } /* else */
+
+ __PHYSFS_smallFree(wstr);
+
+ if (!rc)
+ {
+ if (errno == ERROR_FILE_NOT_FOUND) /* !!! FIXME: errno is wrong */
+ {
+ *exists = 0;
+ return 0;
+ } /* if */
+ else
+ {
+ BAIL_MACRO(strerror(errno), -1);
+ } /* else */
+ } /* if */
+
+ *exists = 1;
+
+ stat->modtime = FileTimeToPhysfsTime(&winstat.ftLastWriteTime);
+ stat->accesstime = FileTimeToPhysfsTime(&winstat.ftLastAccessTime);
+ stat->createtime = FileTimeToPhysfsTime(&winstat.ftCreationTime);
+
+ if(winstat.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+ {
+ stat->filetype = PHYSFS_FILETYPE_DIRECTORY;
+ stat->filesize = 0;
+ } /* if */
+
+ else if(winstat.dwFileAttributes & (FILE_ATTRIBUTE_OFFLINE | FILE_ATTRIBUTE_DEVICE))
+ {
+ /* !!! FIXME: what are reparse points? */
+ stat->filetype = PHYSFS_FILETYPE_OTHER;
+ /* !!! FIXME: don't rely on this */
+ stat->filesize = 0;
+ } /* else if */
+
+ /* !!! FIXME: check for symlinks on Vista. */
+
+ else
+ {
+ stat->filetype = PHYSFS_FILETYPE_REGULAR;
+ filesize = (((PHYSFS_uint64) winstat.nFileSizeHigh) << 32) | winstat.nFileSizeLow;
+ } /* else */
+
+ stat->readonly = ((winstat.dwFileAttributes & FILE_ATTRIBUTE_READONLY) != 0);
+
+ return 0;
+} /* __PHYSFS_platformStatNewWay */
+
+
+int __PHYSFS_platformStat(const char *filename, int *exists, PHYSFS_Stat *stat)
+{
+ if (pGetFileAttributesExW || pGetFileAttributesExA)
+ return __PHYSFS_platformStatNewWay(filename, exists, stat);
+ return __PHYSFS_platformStatOldWay(filename, exists, stat);
+} /* __PHYSFS_platformStat */
+
+
/* !!! FIXME: Don't use C runtime for allocators? */
int __PHYSFS_platformSetDefaultAllocator(PHYSFS_Allocator *a)
{
--- a/test/test_physfs.c Mon Feb 15 09:19:38 2010 -0500
+++ b/test/test_physfs.c Mon Feb 15 14:02:36 2010 -0500
@@ -773,7 +773,6 @@
return 1;
} /* cmd_filelength */
-
#define WRITESTR "The cat sat on the mat.\n\n"
static int cmd_append(char *args)
@@ -872,12 +871,13 @@
} /* cmd_write */
-static void modTimeToStr(PHYSFS_sint64 modtime, char *modstr, size_t strsize)
+static char* modTimeToStr(PHYSFS_sint64 modtime, char *modstr, size_t strsize)
{
time_t t = (time_t) modtime;
char *str = ctime(&t);
strncpy(modstr, str, strsize);
modstr[strsize-1] = '\0';
+ return modstr;
} /* modTimeToStr */
@@ -896,6 +896,44 @@
return 1;
} /* cmd_getLastModTime */
+static int cmd_stat(char *args)
+{
+ PHYSFS_Stat stat;
+ char timestring[65];
+
+ if (*args == '\"')
+ {
+ args++;
+ args[strlen(args) - 1] = '\0';
+ } /* if */
+
+ if(PHYSFS_stat(args, &stat))
+ {
+ printf("failed to stat. Reason [%s].\n", PHYSFS_getLastError());
+ return 1;
+ } /* if */
+
+ printf("Filename: %s\n", args);
+ printf("Size %d\n",(int) stat.filesize);
+
+ if(stat.filetype == PHYSFS_FILETYPE_REGULAR)
+ printf("Type: File\n");
+ else if(stat.filetype == PHYSFS_FILETYPE_DIRECTORY)
+ printf("Type: Directory\n");
+ else if(stat.filetype == PHYSFS_FILETYPE_SYMLINK)
+ printf("Type: Symlink\n");
+ else
+ printf("Type: Unknown\n");
+
+ printf("Created at: %s", modTimeToStr(stat.createtime, timestring, 64));
+ printf("Last modified at: %s", modTimeToStr(stat.modtime, timestring, 64));
+ printf("Last accessed at: %s", modTimeToStr(stat.accesstime, timestring, 64));
+ printf("Readonly: %s\n", stat.readonly ? "true" : "false");
+
+ return 1;
+} /* cmd_filelength */
+
+
/* must have spaces trimmed prior to this call. */
static int count_args(const char *str)
@@ -959,6 +997,7 @@
{ "issymlink", cmd_issymlink, 1, "<fileToCheck>" },
{ "cat", cmd_cat, 1, "<fileToCat>" },
{ "filelength", cmd_filelength, 1, "<fileToCheck>" },
+ { "stat", cmd_stat, 1, "<fileToStat>" },
{ "append", cmd_append, 1, "<fileToAppend>" },
{ "write", cmd_write, 1, "<fileToCreateOrTrash>" },
{ "getlastmodtime", cmd_getlastmodtime, 1, "<fileToExamine>" },
@@ -1166,6 +1205,7 @@
open_history_file();
printf("Enter commands. Enter \"help\" for instructions.\n");
+ fflush(stdout);
do
{
@@ -1176,6 +1216,7 @@
buf = (char *) malloc(512);
memset(buf, '\0', 512);
printf("> ");
+ fflush(stdout);
for (i = 0; i < 511; i++)
{
int ch = fgetc(stdin);
@@ -1202,6 +1243,7 @@
#endif
rc = process_command(buf);
+ fflush(stdout);
if (buf != NULL)
free(buf);
} while (rc);