From 2622be385dc8b3afefb25d3ff7837db2205b1627 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Sun, 8 Jul 2001 03:25:12 +0000 Subject: [PATCH] Implementation compiles and links with no actual archive support. No test case available at this moment. :) --- Makefile | 2 +- archivers/dir.c | 311 ++++++++++++++++++++++++++++++++++++++++++---- archivers/zip.c | 105 +++++++++++++--- physfs.c | 24 ++-- physfs_internal.h | 84 ++++++++++--- platform/unix.c | 232 +++++++++++++++++++++++++++++++++- 6 files changed, 685 insertions(+), 73 deletions(-) diff --git a/Makefile b/Makefile index 892101eb..2c7d29a8 100644 --- a/Makefile +++ b/Makefile @@ -182,7 +182,7 @@ $(MAINLIB) : $(BINDIR) $(MAINOBJS) $(BINDIR): mkdir -p $(BINDIR) - mkdir -p $(BINDIR)/archive_drivers + mkdir -p $(BINDIR)/archivers mkdir -p $(BINDIR)/platform distclean: clean diff --git a/archivers/dir.c b/archivers/dir.c index 54e7b3b5..126b397d 100644 --- a/archivers/dir.c +++ b/archivers/dir.c @@ -8,46 +8,309 @@ #include #include +#include +#include +#include +#include +#include +#include #define __PHYSICSFS_INTERNAL__ #include "physfs_internal.h" +extern const DirFunctions __PHYSFS_DirFunctions_DIR; +static const FileFunctions __PHYSFS_FileHandle_DIR; +static const FileFunctions __PHYSFS_FileHandle_DIRW; + +static int DIR_read(FileHandle *handle, void *buffer, + unsigned int objSize, unsigned int objCount) +{ + FILE *h = (FILE *) (handle->opaque); + int retval; + + errno = 0; + retval = fread(buffer, objSize, objCount, h); + if ( (retval < objCount) && (ferror(h)) ) + __PHYSFS_setError(strerror(errno)); + + return(retval); +} /* DIR_read */ + + +static int DIR_write(FileHandle *handle, void *buffer, + unsigned int objSize, unsigned int objCount) +{ + FILE *h = (FILE *) (handle->opaque); + int retval; + + errno = 0; + retval = fwrite(buffer, objSize, objCount, h); + if ( (retval < objCount) && (ferror(h)) ) + __PHYSFS_setError(strerror(errno)); + + return(retval); +} /* DIR_write */ + + +static int DIR_eof(FileHandle *handle) +{ + return(feof((FILE *) (handle->opaque))); +} /* DIR_eof */ + + +static int DIR_tell(FileHandle *handle) +{ + return(ftell((FILE *) (handle->opaque))); +} /* DIR_tell */ + + +static int DIR_seek(FileHandle *handle, int offset) +{ + return(fseek((FILE *) (handle->opaque), offset, SEEK_SET) == 0); +} /* DIR_seek */ + + +static int DIR_fileClose(FileHandle *handle) +{ + FILE *h = (FILE *) (handle->opaque); + + /* + * we manually fflush() the buffer, since that's the place fclose() will + * most likely fail, but that will leave the file handle in an undefined + * state if it fails. fflush() failures we can recover from. + */ + + /* keep trying until there's success or an unrecoverable error... */ + do { + __PHYSFS_platformTimeslice(); + errno = 0; + } while ( (fflush(h) == EOF) && ((errno == EAGAIN) || (errno == EINTR)) ); + + /* EBADF == "Not open for writing". That's fine. */ + BAIL_IF_MACRO((errno != 0) && (errno != EBADF), strerror(errno), 0); + + /* if fclose fails anyhow, we just have to pray that it's still usable. */ + errno = 0; + BAIL_IF_MACRO(fclose(h) == EOF, strerror(errno), 0); /* (*shrug*) */ + + free(handle); + return(1); +} /* DIR_fileClose */ + + +static int DIR_isArchive(const char *filename, int forWriting) +{ + /* directories ARE archives in this driver... */ + return(__PHYSFS_platformIsDirectory(filename)); +} /* DIR_isArchive */ + + +static DirHandle *DIR_openArchive(const char *name, int forWriting) +{ + const char *dirsep = __PHYSFS_platformDirSeparator; + DirHandle *retval = NULL; + int namelen = strlen(name); + int seplen = strlen(dirsep); + + BAIL_IF_MACRO(!DIR_isArchive(name, 0), ERR_UNSUPPORTED_ARCHIVE, NULL); + + retval = malloc(sizeof (DirHandle)); + BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL); + retval->opaque = malloc(namelen + seplen + 1); + if (retval->opaque == NULL) + { + free(retval); + BAIL_IF_MACRO(0, ERR_OUT_OF_MEMORY, NULL); + } /* if */ + + /* make sure there's a dir separator at the end of the string */ + strcpy((char *) (retval->opaque), name); + if (strcmp((name + namelen) - seplen, dirsep) != 0) + strcat((char *) (retval->opaque), dirsep); + + retval->funcs = &__PHYSFS_DirFunctions_DIR; + return(retval); +} /* DIR_openArchive */ + + +static LinkedStringList *DIR_enumerateFiles(DirHandle *h, const char *dname) +{ + char *d = __PHYSFS_platformCvtToDependent((char *)(h->opaque),dname,NULL); + LinkedStringList *retval; + + BAIL_IF_MACRO(d == NULL, NULL, NULL); + retval = __PHYSFS_platformEnumerateFiles(d); + free(d); + return(retval); +} /* DIR_enumerateFiles */ + + +static int DIR_exists(DirHandle *h, const char *name) +{ + char *f = __PHYSFS_platformCvtToDependent((char *)(h->opaque), name, NULL); + int retval; + + BAIL_IF_MACRO(f == NULL, NULL, 0); + retval = __PHYSFS_platformExists(f); + free(f); + return(retval); +} /* DIR_exists */ + + +static int DIR_isDirectory(DirHandle *h, const char *name) +{ + char *d = __PHYSFS_platformCvtToDependent((char *)(h->opaque), name, NULL); + int retval; + + BAIL_IF_MACRO(d == NULL, NULL, 0); + retval = __PHYSFS_platformIsDirectory(d); + free(d); + return(retval); +} /* DIR_isDirectory */ + + +static int DIR_isSymLink(DirHandle *h, const char *name) +{ + char *f = __PHYSFS_platformCvtToDependent((char *)(h->opaque), name, NULL); + int retval; + + BAIL_IF_MACRO(f == NULL, NULL, 0); /* !!! might be a problem. */ + retval = __PHYSFS_platformIsSymLink(f); + free(f); + return(retval); +} /* DIR_isSymLink */ + + +static FileHandle *doOpen(DirHandle *h, const char *name, const char *mode) +{ + char *f = __PHYSFS_platformCvtToDependent((char *)(h->opaque), name, NULL); + FILE *rc; + FileHandle *retval; + char *str; + + BAIL_IF_MACRO(f == NULL, NULL, NULL); + + retval = (FileHandle *) malloc(sizeof (FileHandle)); + if (!retval) + { + free(f); + BAIL_IF_MACRO(0, ERR_OUT_OF_MEMORY, NULL); + } /* if */ + + errno = 0; + rc = fopen(f, mode); + str = strerror(errno); + free(f); + + if (!rc) + { + free(retval); + BAIL_IF_MACRO(0, str, NULL); + } /* if */ + + retval->opaque = (void *) rc; + retval->dirHandle = h; + retval->funcs = &__PHYSFS_FileHandle_DIR; + return(retval); +} /* doOpen */ + + +static FileHandle *DIR_openRead(DirHandle *h, const char *filename) +{ + return(doOpen(h, filename, "rb")); +} /* DIR_openRead */ + + +static FileHandle *DIR_openWrite(DirHandle *h, const char *filename) +{ + return(doOpen(h, filename, "wb")); +} /* DIR_openWrite */ + + +static FileHandle *DIR_openAppend(DirHandle *h, const char *filename) +{ + return(doOpen(h, filename, "ab")); +} /* DIR_openAppend */ + + +static int DIR_remove(DirHandle *h, const char *name) +{ + char *f = __PHYSFS_platformCvtToDependent((char *)(h->opaque), name, NULL); + int retval; + + BAIL_IF_MACRO(f == NULL, NULL, 0); + + errno = 0; + retval = (remove(f) == 0); + if (!retval) + __PHYSFS_setError(strerror(errno)); + + free(f); + return(retval); +} /* DIR_remove */ + + +static int DIR_mkdir(DirHandle *h, const char *name) +{ + char *f = __PHYSFS_platformCvtToDependent((char *)(h->opaque), name, NULL); + int retval; + + BAIL_IF_MACRO(f == NULL, NULL, 0); + + errno = 0; + retval = (mkdir(f, S_IRWXU) == 0); + if (!retval) + __PHYSFS_setError(strerror(errno)); + + free(f); + return(retval); +} /* DIR_mkdir */ + + +static void DIR_dirClose(DirHandle *h) +{ + free(h->opaque); + free(h); +} /* DIR_dirClose */ + + + static const FileFunctions __PHYSFS_FileHandle_DIR = { - DIR_read, /* read() method */ - NULL, /* write() method */ - DIR_eof, /* eof() method */ - DIR_tell, /* tell() method */ - DIR_seek, /* seek() method */ - DIR_close, /* close() method */ + DIR_read, /* read() method */ + NULL, /* write() method */ + DIR_eof, /* eof() method */ + DIR_tell, /* tell() method */ + DIR_seek, /* seek() method */ + DIR_fileClose, /* fileClose() method */ }; static const FileFunctions __PHYSFS_FileHandle_DIRW = { - NULL, /* read() method */ - DIR_write, /* write() method */ - DIR_eof, /* eof() method */ - DIR_tell, /* tell() method */ - DIR_seek, /* seek() method */ - DIR_close, /* close() method */ + NULL, /* read() method */ + DIR_write, /* write() method */ + DIR_eof, /* eof() method */ + DIR_tell, /* tell() method */ + DIR_seek, /* seek() method */ + DIR_fileClose, /* fileClose() method */ }; const DirFunctions __PHYSFS_DirFunctions_DIR = { - DIR_isArchive, /* isArchive() method */ - DIR_openArchive, /* openArchive() method */ - DIR_enumerate, /* enumerateFiles() method */ - DIR_exists, /* exists() method */ - DIR_isDirectory, /* isDirectory() method */ - DIR_isSymLink, /* isSymLink() method */ - DIR_openRead, /* openRead() method */ - DIR_openWrite, /* openWrite() method */ - DIR_openAppend, /* openAppend() method */ - DIR_remove, /* remove() method */ - DIR_mkdir, /* mkdir() method */ - DIR_close, /* close() method */ + DIR_isArchive, /* isArchive() method */ + DIR_openArchive, /* openArchive() method */ + DIR_enumerateFiles, /* enumerateFiles() method */ + DIR_exists, /* exists() method */ + DIR_isDirectory, /* isDirectory() method */ + DIR_isSymLink, /* isSymLink() method */ + DIR_openRead, /* openRead() method */ + DIR_openWrite, /* openWrite() method */ + DIR_openAppend, /* openAppend() method */ + DIR_remove, /* remove() method */ + DIR_mkdir, /* mkdir() method */ + DIR_dirClose, /* dirClose() method */ }; diff --git a/archivers/zip.c b/archivers/zip.c index c1f5d87a..fae24015 100644 --- a/archivers/zip.c +++ b/archivers/zip.c @@ -16,32 +16,101 @@ #error PHYSFS_SUPPORTS_ZIP must be defined. #endif +extern const DirFunctions __PHYSFS_DirFunctions_ZIP; +extern const FileFunctions __PHYSFS_FileHandle_ZIP; + + +static int ZIP_read(FileHandle *handle, void *buffer, + unsigned int objSize, unsigned int objCount) +{ +} /* ZIP_read */ + + +static int ZIP_eof(FileHandle *handle) +{ +} /* ZIP_eof */ + + +static int ZIP_tell(FileHandle *handle) +{ +} /* ZIP_tell */ + + +static int ZIP_seek(FileHandle *handle, int offset) +{ +} /* ZIP_seek */ + + +static int ZIP_fileClose(FileHandle *handle) +{ +} /* ZIP_fileClose */ + + +static int ZIP_isArchive(const char *filename, int forWriting) +{ +} /* ZIP_isArchive */ + + +static DirHandle *ZIP_openArchive(const char *name, int forWriting) +{ +} /* ZIP_openArchive */ + + +static LinkedStringList *ZIP_enumerateFiles(DirHandle *r, const char *dirname) +{ +} /* ZIP_enumerateFiles */ + + +static int ZIP_exists(DirHandle *r, const char *name) +{ +} /* ZIP_exists */ + + +static int ZIP_isDirectory(DirHandle *r, const char *name) +{ +} /* ZIP_isDirectory */ + + +static int ZIP_isSymLink(DirHandle *r, const char *name) +{ +} /* ZIP_isSymLink */ + + +static FileHandle *ZIP_openRead(DirHandle *r, const char *filename) +{ +} /* ZIP_openRead */ + + +static void ZIP_dirClose(DirHandle *r) +{ +} /* ZIP_dirClose */ + static const FileFunctions __PHYSFS_FileHandle_ZIP = { - ZIP_read, /* read() method */ - NULL, /* write() method */ - ZIP_eof, /* eof() method */ - ZIP_tell, /* tell() method */ - ZIP_seek, /* seek() method */ - ZIP_close, /* close() method */ + ZIP_read, /* read() method */ + NULL, /* write() method */ + ZIP_eof, /* eof() method */ + ZIP_tell, /* tell() method */ + ZIP_seek, /* seek() method */ + ZIP_fileClose, /* fileClose() method */ }; const DirFunctions __PHYSFS_DirFunctions_ZIP = { - ZIP_isArchive, /* isArchive() method */ - ZIP_openArchive, /* openArchive() method */ - ZIP_enumerate, /* enumerateFiles() method */ - ZIP_exists, /* exists() method */ - ZIP_isDirectory, /* isDirectory() method */ - ZIP_isSymLink, /* isSymLink() method */ - ZIP_openRead, /* openRead() method */ - NULL, /* openWrite() method */ - NULL, /* openAppend() method */ - NULL, /* remove() method */ - NULL, /* mkdir() method */ - ZIP_close, /* close() method */ + ZIP_isArchive, /* isArchive() method */ + ZIP_openArchive, /* openArchive() method */ + ZIP_enumerateFiles, /* enumerateFiles() method */ + ZIP_exists, /* exists() method */ + ZIP_isDirectory, /* isDirectory() method */ + ZIP_isSymLink, /* isSymLink() method */ + ZIP_openRead, /* openRead() method */ + NULL, /* openWrite() method */ + NULL, /* openAppend() method */ + NULL, /* remove() method */ + NULL, /* mkdir() method */ + ZIP_dirClose, /* dirClose() method */ }; const __PHYSFS_ArchiveInfo __PHYSFS_ArchiveInfo_ZIP = diff --git a/physfs.c b/physfs.c index 44525e56..5d91f803 100644 --- a/physfs.c +++ b/physfs.c @@ -194,14 +194,14 @@ static DirInfo *buildDirInfo(const char *newDir, int forWriting) di = (DirInfo *) malloc(sizeof (DirInfo)); if (di == NULL) - dirHandle->funcs->close(dirHandle); + dirHandle->funcs->dirClose(dirHandle); BAIL_IF_MACRO(di == NULL, ERR_OUT_OF_MEMORY, 0); di->dirName = (char *) malloc(strlen(newDir) + 1); if (di->dirName == NULL) { free(di); - dirHandle->funcs->close(dirHandle); + dirHandle->funcs->dirClose(dirHandle); __PHYSFS_setError(ERR_OUT_OF_MEMORY); return(0); } /* if */ @@ -226,7 +226,7 @@ static int freeDirInfo(DirInfo *di, FileHandleList *openList) BAIL_IF_MACRO(h == di->dirHandle, ERR_FILES_STILL_OPEN, 0); } /* for */ - di->dirHandle->funcs->close(di->dirHandle); + di->dirHandle->funcs->dirClose(di->dirHandle); free(di->dirName); free(di); return(1); @@ -300,7 +300,7 @@ static int closeFileHandleList(FileHandleList **list) { next = i->next; h = (FileHandle *) (i->handle->opaque); - if (!h->funcs->close(i->handle->opaque)) + if (!h->funcs->fileClose(i->handle->opaque)) { *list = i; return(0); @@ -624,9 +624,9 @@ void PHYSFS_permitSymbolicLinks(int allow) /* string manipulation in C makes my ass itch. */ -char *__PHYSFS_convertToDependentNotation(const char *prepend, - const char *dirName, - const char *append) +char *__PHYSFS_convertToDependent(const char *prepend, + const char *dirName, + const char *append) { const char *dirsep = PHYSFS_getDirSeparator(); int sepsize = strlen(dirsep); @@ -658,13 +658,14 @@ char *__PHYSFS_convertToDependentNotation(const char *prepend, str = (char *) malloc(allocSize); BAIL_IF_MACRO(str == NULL, ERR_OUT_OF_MEMORY, NULL); - *str = '\0'; - if (prepend) + if (prepend == NULL) + *str = '\0'; + else { strcpy(str, prepend); strcat(str, dirsep); - } /* if */ + } /* else */ for (i1 = (char *) dirName, i2 = str + strlen(str); *i1; i1++, i2++) { @@ -709,6 +710,7 @@ int __PHYSFS_verifySecurity(DirHandle *h, const char *fname) if ( (strcmp(start, ".") == 0) || (strcmp(start, "..") == 0) || + (strchr(start, '\\') != NULL) || (strchr(start, ':') != NULL) ) { __PHYSFS_setError(ERR_INSECURE_FNAME); @@ -1058,7 +1060,7 @@ int PHYSFS_close(PHYSFS_file *handle) { if (i->handle == handle) { - rc = h->funcs->close(h); + rc = h->funcs->fileClose(h); if (!rc) return(0); diff --git a/physfs_internal.h b/physfs_internal.h index 412241af..3a14bdc8 100644 --- a/physfs_internal.h +++ b/physfs_internal.h @@ -17,6 +17,14 @@ struct __PHYSFS_DIRHANDLE__; struct __PHYSFS_FILEFUNCTIONS__; + +typedef struct __PHYSFS_LINKEDSTRINGLIST__ +{ + char *str; + struct __PHYSFS_LINKEDSTRINGLIST__ *next; +} LinkedStringList; + + typedef struct __PHYSFS_FILEHANDLE__ { /* @@ -79,7 +87,7 @@ typedef struct __PHYSFS_FILEFUNCTIONS__ * returns non-zero on success, zero if can't close file. * On failure, call __PHYSFS_setError(). */ - int (*close)(FileHandle *handle); + int (*fileClose)(FileHandle *handle); } FileFunctions; @@ -97,12 +105,6 @@ typedef struct __PHYSFS_DIRHANDLE__ } DirHandle; -typedef struct __PHYSFS_LINKEDSTRINGLIST__ -{ - char *str; - struct __PHYSFS_LINKEDSTRINGLIST__ *next; -} LinkedStringList; - /* * Symlinks should always be followed; PhysicsFS will use * DirFunctions->isSymLink() and make a judgement on whether to @@ -162,13 +164,17 @@ typedef struct __PHYSFS_DIRFUNCTIONS__ * This filename is in platform-independent notation. * If you can't handle multiple opens of the same file, * you can opt to fail for the second call. + * Fail if the file does not exist. * Returns NULL on failure, and calls __PHYSFS_setError(). */ FileHandle *(*openRead)(DirHandle *r, const char *filename); /* * Open file for writing, and return a FileHandle. - * This filename is in platform-independent notation. + * If the file does not exist, it should be created. If it exists, + * it should be truncated to zero bytes. The writing + * offset should be the start of the file. + * This filename is in platform-independent notation. * This method may be NULL. * If you can't handle multiple opens of the same file, * you can opt to fail for the second call. @@ -178,7 +184,9 @@ typedef struct __PHYSFS_DIRFUNCTIONS__ /* * Open file for appending, and return a FileHandle. - * This filename is in platform-independent notation. + * If the file does not exist, it should be created. The writing + * offset should be the end of the file. + * This filename is in platform-independent notation. * This method may be NULL. * If you can't handle multiple opens of the same file, * you can opt to fail for the second call. @@ -212,7 +220,7 @@ typedef struct __PHYSFS_DIRFUNCTIONS__ * the "opaque" entry. This should assume that it won't be called if * there are still files open from this DirHandle. */ - void (*close)(DirHandle *r); + void (*dirClose)(DirHandle *r); } DirFunctions; @@ -248,7 +256,7 @@ void __PHYSFS_setError(const char *err); * and append (append) to the converted string. * * So, on Win32, calling: - * __PHYSFS_convertToDependentNotation("C:\", "my/files", NULL); + * __PHYSFS_convertToDependent("C:\", "my/files", NULL); * ...will return the string "C:\my\files". * * This is a convenience function; you might want to hack something out that @@ -256,9 +264,9 @@ void __PHYSFS_setError(const char *err); * * Be sure to free() the return value when done with it. */ -char *__PHYSFS_convertToDependentNotation(const char *prepend, - const char *dirName, - const char *append); +char *__PHYSFS_convertToDependent(const char *prepend, + const char *dirName, + const char *append); /* * Verify that (fname) (in platform-independent notation), in relation @@ -336,16 +344,62 @@ int __PHYSFS_platformGetThreadID(void); */ int __PHYSFS_platformStricmp(const char *str1, const char *str2); +/* + * Return non-zero if filename (in platform-dependent notation) exists. + * Symlinks should be followed; if what the symlink points to is missing, + * then the retval is false. + */ +int __PHYSFS_platformExists(const char *fname); + /* * Return non-zero if filename (in platform-dependent notation) is a symlink. */ -int __PHYSFS_platformIsSymlink(const char *fname); +int __PHYSFS_platformIsSymLink(const char *fname); /* * Return non-zero if filename (in platform-dependent notation) is a symlink. + * Symlinks should be followed; if what the symlink points to is missing, + * or isn't a directory, then the retval is false. */ int __PHYSFS_platformIsDirectory(const char *fname); +/* + * Convert (dirName) to platform-dependent notation, then prepend (prepend) + * and append (append) to the converted string. + * + * So, on Win32, calling: + * __PHYSFS_platformCvtToDependent("C:\", "my/files", NULL); + * ...will return the string "C:\my\files". + * + * This can be implemented in a platform-specific manner, so you can get + * get a speed boost that the default implementation can't, since + * you can make assumptions about the size of strings, etc.. + * + * Platforms that choose not to implement this may just call + * __PHYSFS_convertToDependent() as a passthrough. + * + * Be sure to free() the return value when done with it. + */ +char *__PHYSFS_platformCvtToDependent(const char *prepend, + const char *dirName, + const char *append); + +/* + * Make the current thread give up a timeslice. This is called in a loop + * while waiting for various external forces to get back to us. + */ +void __PHYSFS_platformTimeslice(void); + + +/* + * Enumerate a directory of files. This follows the rules for the + * DirFunctions->enumerateFiles() method (see above), except that the + * (dirName) that is passed to this function is converted to + * platform-DEPENDENT notation by the caller. The DirFunctions version + * uses platform-independent notation. + */ +LinkedStringList *__PHYSFS_platformEnumerateFiles(const char *dirname); + #ifdef __cplusplus extern "C" { diff --git a/platform/unix.c b/platform/unix.c index 487ba3ca..fd69911e 100644 --- a/platform/unix.c +++ b/platform/unix.c @@ -6,9 +6,39 @@ * This file written by Ryan C. Gordon. */ +#if (defined __STRICT_ANSI__) +#define __PHYSFS_DOING_STRICT_ANSI__ +#endif + +/* + * We cheat a little: I want the symlink version of stat() (lstat), and + * GCC/Linux will not declare it if compiled with the -ansi flag. + * If you are really lacking symlink support on your platform, + * you should #define __PHYSFS_NO_SYMLINKS__ before compiling this + * file. That will open a security hole, though, if you really DO have + * symlinks on your platform; it renders PHYSFS_permitSymbolicLinks(0) + * useless, since every symlink will be reported as a regular file/dir. + */ +#if (defined __PHYSFS_DOING_STRICT_ANSI__) +#undef __STRICT_ANSI__ +#endif #include +#if (defined __PHYSFS_DOING_STRICT_ANSI__) +#define __STRICT_ANSI__ +#endif + #include +#include +#include #include +#include +#include +#include +#include +#include +#include +#include + #define __PHYSICSFS_INTERNAL__ #include "physfs_internal.h" @@ -18,22 +48,88 @@ const char *__PHYSFS_platformDirSeparator = "/"; char **__PHYSFS_platformDetectAvailableCDs(void) { + /* !!! write me. */ + char **retval = malloc(sizeof (char *)); + if (retval != NULL) + *retval = NULL; + + return(retval); } /* __PHYSFS_detectAvailableCDs */ char *__PHYSFS_platformCalcBaseDir(char *argv0) { - return(NULL); + return(NULL); /* default PhysicsFS behaviour is acceptable. */ } /* __PHYSFS_platformCalcBaseDir */ +static char *copyEnvironmentVariable(const char *varname) +{ + const char *envr = getenv(varname); + char *retval = NULL; + + if (envr != NULL) + { + retval = malloc(strlen(envr) + 1); + if (retval != NULL) + strcpy(retval, envr); + } /* if */ + + return(retval); +} /* copyEnvironmentVariable */ + + +static char *getUserNameByUID(void) +{ + uid_t uid = getuid(); + struct passwd *pw; + char *retval = NULL; + + pw = getpwuid(uid); + if ((pw != NULL) && (pw->pw_name != NULL)) + { + retval = malloc(strlen(pw->pw_name) + 1); + if (retval != NULL) + strcpy(retval, pw->pw_name); + } /* if */ + + return(retval); +} /* getUserNameByUID */ + + +static char *getUserDirByUID(void) +{ + uid_t uid = getuid(); + struct passwd *pw; + char *retval = NULL; + + pw = getpwuid(uid); + if ((pw != NULL) && (pw->pw_dir != NULL)) + { + retval = malloc(strlen(pw->pw_dir) + 1); + if (retval != NULL) + strcpy(retval, pw->pw_dir); + } /* if */ + + return(retval); +} /* getUserDirByUID */ + + char *__PHYSFS_platformGetUserName(void) { + char *retval = getUserNameByUID(); + if (retval == NULL) + retval = copyEnvironmentVariable("USER"); + return(retval); } /* __PHYSFS_platformGetUserName */ char *__PHYSFS_platformGetUserDir(void) { + char *retval = copyEnvironmentVariable("HOME"); + if (retval == NULL) + retval = getUserDirByUID(); + return(retval); } /* __PHYSFS_platformGetUserDir */ @@ -43,21 +139,149 @@ int __PHYSFS_platformGetThreadID(void) } /* __PHYSFS_platformGetThreadID */ -int __PHYSFS_platformStricmp(const char *str1, const char *str2) +/* -ansi and -pedantic flags prevent use of strcasecmp() on Linux. */ +int __PHYSFS_platformStricmp(const char *x, const char *y) { - return(strcasecmp(str1, str2)); + int ux, uy; + + do + { + ux = toupper((int) *x); + uy = toupper((int) *y); + if (ux > uy) + return(1); + else if (ux < uy) + return(-1); + x++; + y++; + } while ((ux) && (uy)); + + return(0); } /* __PHYSFS_platformStricmp */ -int __PHYSFS_platformIsSymlink(const char *fname) +int __PHYSFS_platformExists(const char *fname) +{ + struct stat statbuf; + return(stat(fname, &statbuf) == 0); +} /* __PHYSFS_platformExists */ + + +int __PHYSFS_platformIsSymLink(const char *fname) { +#if (defined __PHYSFS_NO_SYMLINKS__) + return(0); +#else + + struct stat statbuf; + int retval = 0; + + if (lstat(fname, &statbuf) == 0) + { + if (S_ISLNK(statbuf.st_mode)) + retval = 1; + } /* if */ + + return(retval); + +#endif } /* __PHYSFS_platformIsSymlink */ int __PHYSFS_platformIsDirectory(const char *fname) { + struct stat statbuf; + int retval = 0; + + if (stat(fname, &statbuf) == 0) + { + if (S_ISDIR(statbuf.st_mode)) + retval = 1; + } /* if */ + + return(retval); } /* __PHYSFS_platformIsDirectory */ +char *__PHYSFS_platformCvtToDependent(const char *prepend, + const char *dirName, + const char *append) +{ + int len = ((prepend) ? strlen(prepend) : 0) + + ((append) ? strlen(append) : 0) + + strlen(dirName) + 1; + char *retval = malloc(len); + + BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL); + + /* platform-independent notation is Unix-style already. :) */ + + if (prepend) + strcpy(retval, prepend); + else + retval[0] = '\0'; + + strcat(retval, dirName); + + if (append) + strcat(retval, append); + + return(retval); +} /* __PHYSFS_platformCvtToDependent */ + + +/* Much like my college days, try to sleep for 10 milliseconds at a time... */ +void __PHYSFS_platformTimeslice(void) +{ + struct timespec napTime; + napTime.tv_sec = 0; + napTime.tv_nsec = 10 * 1000 * 1000; /* specified in nanoseconds. */ + nanosleep(&napTime, NULL); /* don't care if it fails. */ +} /* __PHYSFS_platformTimeslice */ + + +LinkedStringList *__PHYSFS_platformEnumerateFiles(const char *dirname) +{ + LinkedStringList *retval = NULL; + LinkedStringList *l = NULL; + LinkedStringList *prev = NULL; + DIR *dir; + struct dirent *ent; + + errno = 0; + dir = opendir(dirname); + BAIL_IF_MACRO(dir == NULL, strerror(errno), NULL); + + while (1) + { + ent = readdir(dir); + if (ent == NULL) /* we're done. */ + break; + + l = (LinkedStringList *) malloc(sizeof (LinkedStringList)); + if (l != NULL) + break; + + l->str = (char *) malloc(strlen(ent->d_name) + 1); + if (l->str == NULL) + { + free(l); + break; + } /* if */ + + if (retval == NULL) + retval = l; + else + prev->next = l; + + prev = l; + l->next = NULL; + } /* while */ + + closedir(dir); + return(retval); +} /* __PHYSFS_platformEnumerateFiles */ + + /* end of unix.c ... */