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:
parent
8e78e4719d
commit
f1cd4d8f0d
|
@ -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 ...
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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 ... */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
50
src/physfs.c
50
src/physfs.c
|
@ -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);
|
||||
|
|
55
src/physfs.h
55
src/physfs.h
|
@ -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. */
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
||||
|
|
|
@ -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 ... */
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue