Implementation compiles and links with no actual archive support. No test
authorRyan C. Gordon <icculus@icculus.org>
Sun, 08 Jul 2001 03:25:12 +0000
changeset 20 efdde0d21521
parent 19 a0279b57398c
child 21 b1ea58d70a56
Implementation compiles and links with no actual archive support. No test case available at this moment. :)
Makefile
archivers/dir.c
archivers/zip.c
physfs.c
physfs_internal.h
platform/unix.c
--- a/Makefile	Sat Jul 07 09:05:19 2001 +0000
+++ b/Makefile	Sun Jul 08 03:25:12 2001 +0000
@@ -182,7 +182,7 @@
 
 $(BINDIR):
 	mkdir -p $(BINDIR)
-	mkdir -p $(BINDIR)/archive_drivers
+	mkdir -p $(BINDIR)/archivers
 	mkdir -p $(BINDIR)/platform
 
 distclean: clean
--- a/archivers/dir.c	Sat Jul 07 09:05:19 2001 +0000
+++ b/archivers/dir.c	Sun Jul 08 03:25:12 2001 +0000
@@ -8,46 +8,309 @@
 
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
 
 #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       */
 };
 
 
--- a/archivers/zip.c	Sat Jul 07 09:05:19 2001 +0000
+++ b/archivers/zip.c	Sun Jul 08 03:25:12 2001 +0000
@@ -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 =
--- a/physfs.c	Sat Jul 07 09:05:19 2001 +0000
+++ b/physfs.c	Sun Jul 08 03:25:12 2001 +0000
@@ -194,14 +194,14 @@
 
     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 @@
         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 @@
     {
         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 @@
 
 
 /* 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 @@
 
     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 @@
 
         if ( (strcmp(start, ".") == 0) ||
              (strcmp(start, "..") == 0) ||
+             (strchr(start, '\\') != NULL) ||
              (strchr(start, ':') != NULL) )
         {
             __PHYSFS_setError(ERR_INSECURE_FNAME);
@@ -1058,7 +1060,7 @@
         {
             if (i->handle == handle)
             {
-                rc = h->funcs->close(h);
+                rc = h->funcs->fileClose(h);
                 if (!rc)
                     return(0);
 
--- a/physfs_internal.h	Sat Jul 07 09:05:19 2001 +0000
+++ b/physfs_internal.h	Sun Jul 08 03:25:12 2001 +0000
@@ -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 @@
          *  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 @@
 } 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 @@
          *  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 @@
 
         /*
          * 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 @@
          *  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 @@
  *  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 @@
  *
  * 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
@@ -337,15 +345,61 @@
 int __PHYSFS_platformStricmp(const char *str1, const char *str2);
 
 /*
- * Return non-zero if filename (in platform-dependent notation) is a symlink.
+ * 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_platformIsSymlink(const char *fname);
+int __PHYSFS_platformExists(const char *fname);
 
 /*
  * Return non-zero if filename (in platform-dependent notation) is a symlink.
  */
+int __PHYSFS_platformIsSymLink(const char *fname);
+
+/*
+ * Return non-zero if filename (in platform-dependent notation) is a symlink.
+ *  Symlinks should be followed; if what the symlink points to is missing,
+ *  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" {
--- a/platform/unix.c	Sat Jul 07 09:05:19 2001 +0000
+++ b/platform/unix.c	Sun Jul 08 03:25:12 2001 +0000
@@ -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 <stdio.h>
+#if (defined __PHYSFS_DOING_STRICT_ANSI__)
+#define __STRICT_ANSI__
+#endif
+
 #include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
 #include <pthread.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <pwd.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <time.h>
+#include <errno.h>
+
 
 #define __PHYSICSFS_INTERNAL__
 #include "physfs_internal.h"
@@ -18,22 +48,88 @@
 
 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 @@
 } /* __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 ... */