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.
This commit is contained in:
Ryan C. Gordon 2010-02-15 14:02:36 -05:00
parent 8e78e4719d
commit f1cd4d8f0d
19 changed files with 732 additions and 35 deletions

View File

@ -105,6 +105,10 @@ OS/2 updates:
Bug fixes:
Patrice Mandin
PHYSFS_stat() API:
Christoph Nelles
Indy Sams
Other stuff:
Your name here! Patches go to icculus@icculus.org ...

View File

@ -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"

View File

@ -243,6 +243,18 @@ static void DIR_dirClose(dvoid *opaque)
} /* 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_ArchiveInfo __PHYSFS_ArchiveInfo_DIR =
};
const PHYSFS_Archiver __PHYSFS_Archiver_DIR =
{
&__PHYSFS_ArchiveInfo_DIR,
@ -276,7 +287,8 @@ const PHYSFS_Archiver __PHYSFS_Archiver_DIR =
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 ... */

View File

@ -316,7 +316,7 @@ static void GRP_enumerateFiles(dvoid *opaque, const char *dname,
} /* 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 @@ static int GRP_mkdir(dvoid *opaque, const char *name)
} /* 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 @@ const PHYSFS_Archiver __PHYSFS_Archiver_GRP =
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 */

View File

@ -355,7 +355,7 @@ static void HOG_enumerateFiles(dvoid *opaque, const char *dname,
} /* 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 @@ static int HOG_mkdir(dvoid *opaque, const char *name)
} /* 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 @@ const PHYSFS_Archiver __PHYSFS_Archiver_HOG =
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 */

View File

@ -207,7 +207,7 @@ static void lzma_file_swap(void *_a, PHYSFS_uint32 one, PHYSFS_uint32 two)
/*
* 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 @@ static int LZMA_mkdir(dvoid *opaque, const char *name)
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 @@ const PHYSFS_Archiver __PHYSFS_Archiver_LZMA =
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 */

View File

@ -312,7 +312,7 @@ static void MVL_enumerateFiles(dvoid *opaque, const char *dname,
} /* 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 @@ static int MVL_mkdir(dvoid *opaque, const char *name)
} /* 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 @@ const PHYSFS_Archiver __PHYSFS_Archiver_MVL =
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 */

View File

@ -445,7 +445,8 @@ static void QPAK_enumerateFiles(dvoid *opaque, const char *dname,
* 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 @@ static int QPAK_mkdir(dvoid *opaque, const char *name)
} /* 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 @@ const PHYSFS_Archiver __PHYSFS_Archiver_QPAK =
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 */

View File

@ -361,7 +361,7 @@ static void WAD_enumerateFiles(dvoid *opaque, const char *dname,
} /* 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 @@ static int WAD_mkdir(dvoid *opaque, const char *name)
} /* 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 @@ const PHYSFS_Archiver __PHYSFS_Archiver_WAD =
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 */

View File

@ -509,7 +509,8 @@ static void zip_free_entries(ZIPentry *entries, PHYSFS_uint32 max)
* 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 @@ static int ZIP_mkdir(dvoid *opaque, const char *name)
} /* 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 @@ const PHYSFS_Archiver __PHYSFS_Archiver_ZIP =
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 */

View File

@ -2144,6 +2144,56 @@ int PHYSFS_flush(PHYSFS_File *handle)
} /* 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);

View File

@ -417,7 +417,6 @@ typedef struct PHYSFS_Version
} PHYSFS_Version;
#ifndef SWIG /* not available from scripting languages. */
#ifndef DOXYGEN_SHOULD_IGNORE_THIS
@ -2462,6 +2461,60 @@ PHYSFS_DECL const PHYSFS_Allocator *PHYSFS_getAllocator(void);
#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. */

View File

@ -937,6 +937,13 @@ typedef struct
* 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_platformTell(void *opaque);
*/
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.

View File

@ -631,6 +631,25 @@ int __PHYSFS_platformDelete(const char *_path)
} /* __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 @@ PHYSFS_sint64 __PHYSFS_platformGetLastModTime(const char *_fname)
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 = (PHYSFS_sint64) mktime(&tm);
retval = os2TimeToUnixTime(&fs.fdateLastWrite, &fs.ftimeLastWrite);
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;

View File

@ -561,6 +561,103 @@ int __PHYSFS_platformDelete(const char *path)
} /* __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 @@ int __PHYSFS_platformDelete(const char *path)
*/
void *__PHYSFS_platformCreateMutex(void)
{
return (void * CreateMutex(NULL, FALSE, NULL));
return ((void *) CreateMutex(NULL, FALSE, NULL));
} /* __PHYSFS_platformCreateMutex */

View File

@ -405,6 +405,52 @@ PHYSFS_sint64 __PHYSFS_platformGetLastModTime(const char *fname)
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 ... */

View File

@ -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 @@ int __PHYSFS_platformSetDefaultAllocator(PHYSFS_Allocator *a)
} /* __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 @@ void __PHYSFS_platformReleaseMutex(void *mutex)
} /* if */
} /* __PHYSFS_platformReleaseMutex */
#endif /* !PHYSFS_NO_THREAD_SUPPORT */
#endif /* !PHYSFS_NO_PTHREADS_SUPPORT */
#endif /* PHYSFS_PLATFORM_UNIX */

View File

@ -1390,6 +1390,127 @@ PHYSFS_sint64 __PHYSFS_platformGetLastModTime(const char *fname)
} /* __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)
{

View File

@ -773,7 +773,6 @@ static int cmd_filelength(char *args)
return 1;
} /* cmd_filelength */
#define WRITESTR "The cat sat on the mat.\n\n"
static int cmd_append(char *args)
@ -872,12 +871,13 @@ static int cmd_write(char *args)
} /* 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 @@ static int cmd_getlastmodtime(char *args)
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 @@ static const command_info commands[] =
{ "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 @@ int main(int argc, char **argv)
open_history_file();
printf("Enter commands. Enter \"help\" for instructions.\n");
fflush(stdout);
do
{
@ -1176,6 +1216,7 @@ int main(int argc, char **argv)
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 @@ int main(int argc, char **argv)
#endif
rc = process_command(buf);
fflush(stdout);
if (buf != NULL)
free(buf);
} while (rc);