physfs.c
changeset 15 418eacc97ac8
parent 12 a4041c91d715
child 19 a0279b57398c
--- a/physfs.c	Sat Jul 07 03:47:13 2001 +0000
+++ b/physfs.c	Sat Jul 07 03:52:43 2001 +0000
@@ -25,16 +25,16 @@
     struct __PHYSFS_ERRMSGTYPE__ *next;
 } ErrMsg;
 
-typedef struct __PHYSFS_SEARCHDIRINFO__
+typedef struct __PHYSFS_DIRINFO__
 {
     char *dirName;
-    DirReader *reader;
-    struct __PHYSFS_SEARCHDIRINFO__ *next;
-} SearchDirInfo;
+    DirHandle *dirHandle;
+    struct __PHYSFS_DIRINFO__ *next;
+} DirInfo;
 
 typedef struct __PHYSFS_FILEHANDLELIST__
 {
-    FileHandle *handle;
+    PHYSFS_file *handle;
     struct __PHYSFS_FILEHANDLELIST__ *next;
 } FileHandleList;
 
@@ -73,12 +73,12 @@
 
 static int initialized = 0;
 static ErrMsg *errorMessages = NULL;
-static SearchDirInfo *searchPath = NULL;
+static DirInfo *searchPath = NULL;
+static DirInfo *writeDir = NULL;
 static FileHandleList *openWriteList = NULL;
 static FileHandleList *openReadList = NULL;
 static char *baseDir = NULL;
 static char *userDir = NULL;
-static char *writeDir = NULL;
 static int allowSymLinks = 0;
 
 
@@ -107,7 +107,12 @@
 
 void __PHYSFS_setError(const char *str)
 {
-    ErrMsg *err = findErrorForCurrentThread();
+    ErrMsg *err;
+
+    if (str == NULL)
+        return;
+
+    err = findErrorForCurrentThread();
 
     if (err == NULL)
     {
@@ -126,6 +131,19 @@
 } /* __PHYSFS_setError */
 
 
+static void freeErrorMessages(void)
+{
+    ErrMsg *i;
+    ErrMsg *next;
+
+    for (i = errorMessages; i != NULL; i = next)
+    {
+        next = i;
+        free(i);
+    } /* for */
+} /* freeErrorMessages */
+
+
 const char *PHYSFS_getLastError(void)
 {
     ErrMsg *err = findErrorForCurrentThread();
@@ -149,22 +167,88 @@
 } /* PHYSFS_getLinkedVersion */
 
 
-static const char *calculateUserDir(void)
+static DirHandle *openDirectory(const char *d, int forWriting)
+{
+    const DirFunctions **i;
+
+    for (i = dirFunctions; *i != NULL; i++)
+    {
+        if ((*i)->isArchive(d, forWriting))
+            return( (*i)->openArchive(d, forWriting) );
+    } /* for */
+
+    __PHYSFS_setError(ERR_UNSUPPORTED_ARCHIVE);
+    return(NULL);
+} /* openDirectory */
+
+
+static DirInfo *buildDirInfo(const char *newDir, int forWriting)
+{
+    DirHandle *dirHandle = NULL;
+    DirInfo *di = NULL;
+
+    BAIL_IF_MACRO(newDir == NULL, ERR_INVALID_ARGUMENT, 0);
+
+    dirHandle = openDirectory(newDir, forWriting);
+    BAIL_IF_MACRO(dirHandle == NULL, NULL, 0);
+
+    di = (DirInfo *) malloc(sizeof (DirInfo));
+    if (di == NULL)
+        dirHandle->funcs->close(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);
+        __PHYSFS_setError(ERR_OUT_OF_MEMORY);
+        return(0);
+    } /* if */
+
+    di->next = NULL;
+    di->dirHandle = dirHandle;
+    strcpy(di->dirName, newDir);
+    return(di);
+} /* buildDirInfo */
+
+
+static int freeDirInfo(DirInfo *di, FileHandleList *openList)
+{
+    FileHandleList *i;
+
+    if (di == NULL)
+        return(1);
+
+    for (i = openList; i != NULL; i = i->next)
+    {
+        const DirHandle *h = ((FileHandle *) i->handle->opaque)->dirHandle;
+        BAIL_IF_MACRO(h == di->dirHandle, ERR_FILES_STILL_OPEN, 0);
+    } /* for */
+
+    di->dirHandle->funcs->close(di->dirHandle);
+    free(di->dirName);
+    free(di);
+    return(1);
+} /* freeDirInfo */
+
+
+static char *calculateUserDir(void)
 {
     char *retval = NULL;
     const char *str = NULL;
 
     str = __PHYSFS_platformGetUserDir();
     if (str != NULL)
-        retval = str;
+        retval = (char *) str;
     else
     {
         const char *dirsep = PHYSFS_getDirSeparator();
         const char *uname = __PHYSFS_platformGetUserName();
 
         str = (uname != NULL) ? uname : "default";
-        retval = malloc(strlen(baseDir) + strlen(str) +
-                        (strlen(dirsep) * 2) + 6);
+        retval = (char *) malloc(strlen(baseDir) + strlen(str) +
+                                 (strlen(dirsep) * 2) + 6);
 
         if (retval == NULL)
             __PHYSFS_setError(ERR_OUT_OF_MEMORY);
@@ -172,21 +256,26 @@
             sprintf(retval, "%s%susers%s%s", baseDir, dirsep, dirsep, str);
 
         if (uname != NULL)
-            free(uname);
+            free((void *) uname);
     } /* else */
 
     return(retval);
 } /* calculateUserDir */
 
 
+static char *calculateBaseDir(const char *argv0)
+{
+assert(0); return(NULL);
+} /* calculateBaseDir */
+
+
 int PHYSFS_init(const char *argv0)
 {
     BAIL_IF_MACRO(initialized, ERR_IS_INITIALIZED, 0);
     BAIL_IF_MACRO(argv0 == NULL, ERR_INVALID_ARGUMENT, 0);
 
     baseDir = calculateBaseDir(argv0);
-    if (baseDir == NULL)
-        return(0);
+    BAIL_IF_MACRO(baseDir == NULL, NULL, 0);
 
     userDir = calculateUserDir();
     if (userDir == NULL)
@@ -201,42 +290,35 @@
 } /* PHYSFS_init */
 
 
-static void freeSearchDir(SearchDirInfo *sdi)
-{
-    FileHandleList *i;
-
-    assert(sdi != NULL);
-    for (i = openReadList; i != NULL; i = i->next)
-    {
-        BAIL_IF_MACRO(i->handle->dirReader == sdi->reader,
-                        ERR_FILES_OPEN_READ, 0);
-    } /* for */
-
-    sdi->reader->close(sdi->reader);
-    free(sdi->dirName);
-    free(sdi);
-} /* freeSearchDir */
-
-
-static void closeFileHandleList(FileHandleList **list)
+static int closeFileHandleList(FileHandleList **list)
 {
     FileHandleList *i;
     FileHandleList *next = NULL;
+    FileHandle *h;
 
     for (i = *list; i != NULL; i = next)
     {
         next = i->next;
-        i->handle->close(i->handle);
+        h = (FileHandle *) (i->handle->opaque);
+        if (!h->funcs->close(i->handle->opaque))
+        {
+            *list = i;
+            return(0);
+        } /* if */
+
+        free(i->handle);
+        free(i);
     } /* for */
 
     *list = NULL;
-} /* closeAllFiles */
+    return(1);
+} /* closeFileHandleList */
 
 
 static void freeSearchPath(void)
 {
-    SearchDirInfo *i;
-    SearchDirInfo *next = NULL;
+    DirInfo *i;
+    DirInfo *next = NULL;
 
     closeFileHandleList(&openReadList);
 
@@ -245,19 +327,20 @@
         for (i = searchPath; i != NULL; i = next)
         {
             next = i;
-            freeSearchDir(i);
+            freeDirInfo(i, openReadList);
         } /* for */
         searchPath = NULL;
     } /* if */
 } /* freeSearchPath */
 
 
-void PHYSFS_deinit(void)
+int PHYSFS_deinit(void)
 {
     BAIL_IF_MACRO(!initialized, ERR_NOT_INITIALIZED, 0);
 
     closeFileHandleList(&openWriteList);
-    PHYSFS_setWriteDir(NULL);
+    BAIL_IF_MACRO(!PHYSFS_setWriteDir(NULL), ERR_FILES_STILL_OPEN, 0);
+
     freeSearchPath();
     freeErrorMessages();
 
@@ -297,7 +380,7 @@
 
 const char *PHYSFS_getDirSeparator(void)
 {
-    return(__PHYSFS_pathSeparator);
+    return(__PHYSFS_platformDirSeparator);
 } /* PHYSFS_getDirSeparator */
 
 
@@ -321,96 +404,55 @@
 
 const char *PHYSFS_getWriteDir(void)
 {
-    return(writeDir);
+    if (writeDir == NULL)
+        return(NULL);
+
+    return(writeDir->dirName);
 } /* PHYSFS_getWriteDir */
 
 
 int PHYSFS_setWriteDir(const char *newDir)
 {
-    BAIL_IF_MACRO(openWriteList != NULL, ERR_FILES_OPEN_WRITE, 0);
-
     if (writeDir != NULL)
     {
-        free(writeDir);
+        BAIL_IF_MACRO(!freeDirInfo(writeDir, openWriteList), NULL, 0);
         writeDir = NULL;
     } /* if */
 
     if (newDir != NULL)
     {
-        BAIL_IF_MACRO(!createDirs_dependent(newDir), ERR_NO_DIR_CREATE, 0);
-
-        writeDir = malloc(strlen(newDir) + 1);
-        BAIL_IF_MACRO(writeDir == NULL, ERR_OUT_OF_MEMORY, 0);
-
-        strcpy(writeDir, newDir);
+        writeDir = buildDirInfo(newDir, 1);
+        return(writeDir != NULL);
     } /* if */
 
     return(1);
 } /* PHYSFS_setWriteDir */
 
 
-static DirReader *getDirReader(const char *d)
-{
-    DirFunctions **i;
-
-    for (i = dirFunctions; *i != NULL; i++)
-    {
-        if ((*i)->isArchive(d))
-            return( (*i)->openArchive(d) );
-    } /* for */
-
-    __PHYSFS_setError(ERR_UNSUPPORTED_ARCHIVE);
-    return(NULL);
-} /* getDirReader */
-
-
 int PHYSFS_addToSearchPath(const char *newDir, int appendToPath)
 {
-    char *str = NULL;
-    SearchDirInfo *sdi = NULL;
-    DirReader *dirReader = NULL;
-
-    BAIL_IF_MACRO(newDir == NULL, ERR_INVALID_ARGUMENT, 0);
-
-    reader = getDirReader(newDir); /* This sets the error message. */
-    if (reader == NULL)
-        return(0);
+    DirInfo *di = buildDirInfo(newDir, 0);
 
-    sdi = (SearchDirInfo *) malloc(sizeof (SearchDirInfo));
-    if (sdi == NULL)
-        reader->close(reader);
-    BAIL_IF_MACRO(sdi == NULL, ERR_OUT_OF_MEMORY, 0);
-
-    sdi->dirName = (char *) malloc(strlen(newDir) + 1);
-    if (sdi->dirName == NULL)
-    {
-        free(sdi);
-        reader->close(reader);
-        __PHYSFS_setError(ERR_OUT_OF_MEMORY);
-        return(0);
-    } /* if */
-
-    sdi->dirReader = dirReader;
-    strcpy(sdi->dirName, newDir);
+    BAIL_IF_MACRO(di == NULL, NULL, 0);
 
     if (appendToPath)
     {
-        sdi->next = searchPath;
-        searchPath = sdi;
+        di->next = searchPath;
+        searchPath = di;
     } /* if */
     else
     {
-        SearchDirInfo *i = searchPath;
-        SearchDirInfo *prev = NULL;
+        DirInfo *i = searchPath;
+        DirInfo *prev = NULL;
 
-        sdi->next = NULL;
+        di->next = NULL;
         while (i != NULL)
             prev = i;
 
         if (prev == NULL)
-            searchPath = sdi;
+            searchPath = di;
         else
-            prev->next = sdi;
+            prev->next = di;
     } /* else */
 
     return(1);
@@ -419,9 +461,9 @@
 
 int PHYSFS_removeFromSearchPath(const char *oldDir)
 {
-    SearchDirInfo *i;
-    SearchDirInfo *prev = NULL;
-    SearchDirInfo *next = NULL;
+    DirInfo *i;
+    DirInfo *prev = NULL;
+    DirInfo *next = NULL;
 
     BAIL_IF_MACRO(oldDir == NULL, ERR_INVALID_ARGUMENT, 0);
 
@@ -430,8 +472,7 @@
         if (strcmp(i->dirName, oldDir) == 0)
         {
             next = i->next;
-            if (!freeSearchDir(i))
-                return(0);
+            BAIL_IF_MACRO(!freeDirInfo(i, openReadList), NULL, 0);
 
             if (prev == NULL)
                 searchPath = next;
@@ -452,7 +493,7 @@
 {
     int count = 1;
     int x;
-    SearchDirInfo *i;
+    DirInfo *i;
     char **retval;
 
     for (i = searchPath; i != NULL; i = i->next)
@@ -501,13 +542,12 @@
     BAIL_IF_MACRO(str == NULL, ERR_OUT_OF_MEMORY, 0);
     sprintf(str, "%s%s.%s", userdir, dirsep, appName);
     rc = PHYSFS_setWriteDir(str);
-    if (!rc)
-        return(0);  /* error set by PHYSFS_setWriteDir() ... */
+    BAIL_IF_MACRO(!rc, NULL, 0);
 
         /* Put write dir related dirs on search path... */
     PHYSFS_addToSearchPath(str, 1);
     PHYSFS_mkdir(appName); /* don't care if this fails. */
-    strcat(str, dirSep);
+    strcat(str, dirsep);
     strcat(str, appName);
     PHYSFS_addToSearchPath(str, 1);
     free(str);
@@ -530,12 +570,12 @@
         char **i;
         for (i = cds; *i != NULL; i++)
         {
-            PHYSFS_addToSearchPath(*i);
+            PHYSFS_addToSearchPath(*i, 1);
             str = malloc(strlen(*i) + strlen(appName) + strlen(dirsep) + 1);
             if (str != NULL)
             {
                 sprintf(str, "%s%s%s", *i, dirsep, appName);
-                PHYSFS_addToSearchPath(str);
+                PHYSFS_addToSearchPath(str, 1);
                 free(str);
             } /* if */
         } /* for */
@@ -563,7 +603,7 @@
                     if (str != NULL)
                     {
                         sprintf(str, "%s%s%s", d, dirsep, *i);
-                        PHYSFS_addToSearchPath(d, str);
+                        PHYSFS_addToSearchPath(str, archivesFirst == 0);
                         free(str);
                     } /* if */
                 } /* if */
@@ -577,11 +617,16 @@
 } /* PHYSFS_setSaneConfig */
 
 
+void PHYSFS_permitSymbolicLinks(int allow)
+{
+    allowSymLinks = allow;
+} /* PHYSFS_permitSymbolicLinks */
+
+
 /* string manipulation in C makes my ass itch. */
-/*  be sure to free this crap after you're done with it. */
-static char *convertToDependentNotation(const char *prepend,
-                                        const char *dirName,
-                                        const char *append)
+char *__PHYSFS_convertToDependentNotation(const char *prepend,
+                                          const char *dirName,
+                                          const char *append)
 {
     const char *dirsep = PHYSFS_getDirSeparator();
     int sepsize = strlen(dirsep);
@@ -590,7 +635,7 @@
     char *i2;
     size_t allocSize;
 
-    allocSize = strlen(dirName) + strlen(writeDir) + sepsize + 1;
+    allocSize = strlen(dirName) + 1;
     if (prepend != NULL)
         allocSize += strlen(prepend) + sepsize;
     if (append != NULL)
@@ -599,11 +644,16 @@
         /* make sure there's enough space if the dir separator is bigger. */
     if (sepsize > 1)
     {
-        for (str = dirName; *str != '\0'; str++)
+        str = (char *) dirName;
+        do
         {
-            if (*str == '/')
+            str = strchr(str, '/');
+            if (str != NULL)
+            {
                 allocSize += (sepsize - 1);
-        } /* for */
+                str++;
+            } /* if */
+        } while (str != NULL);
     } /* if */
 
     str = (char *) malloc(allocSize);
@@ -616,7 +666,7 @@
         strcat(str, dirsep);
     } /* if */
 
-    for (i1 = dirName, i2 = str + strlen(str); *i1 != '\0'; i1++, i2++)
+    for (i1 = (char *) dirName, i2 = str + strlen(str); *i1; i1++, i2++)
     {
         if (*i1 == '/')
         {
@@ -637,78 +687,123 @@
     } /* if */
 
     return(str);
-} /* convertToDependentNotation */
+} /* __PHYSFS_convertToDependentNotation */
+
+
+int __PHYSFS_verifySecurity(DirHandle *h, const char *fname)
+{
+    int retval = 1;
+    char *start;
+    char *end;
+    char *str;
+
+    start = str = malloc(strlen(fname) + 1);
+    BAIL_IF_MACRO(str == NULL, ERR_OUT_OF_MEMORY, 0);
+    strcpy(str, fname);
+
+    while (1)
+    {
+        end = strchr(start, '/');
+        if (end != NULL)
+            *end = '\0';
+
+        if ( (strcmp(start, ".") == 0) ||
+             (strcmp(start, "..") == 0) ||
+             (strchr(start, ':') != NULL) )
+        {
+            __PHYSFS_setError(ERR_INSECURE_FNAME);
+            retval = 0;
+            break;
+        } /* if */
+
+        if ((!allowSymLinks) && (h->funcs->isSymLink(h, str)))
+        {
+            __PHYSFS_setError(ERR_SYMLINK_DISALLOWED);
+            retval = 0;
+            break;
+        } /* if */
+
+        if (end == NULL)
+            break;
+
+        *end = '/';
+        start = end + 1;
+    } /* while */
+
+    free(str);
+    return(retval);
+} /* __PHYSFS_verifySecurity */
 
 
 int PHYSFS_mkdir(const char *dirName)
 {
+    DirHandle *h;
     char *str;
-    int rc;
+    char *start;
+    char *end;
+    int retval = 0;
 
-    BAIL_IF_MACRO(writeDir == NULL, ERR_NO_WRITE_DIR, NULL);
+    BAIL_IF_MACRO(writeDir == NULL, ERR_NO_WRITE_DIR, 0);
+    h = writeDir->dirHandle;
+    BAIL_IF_MACRO(h->funcs->mkdir == NULL, ERR_NOT_SUPPORTED, 0);
+    BAIL_IF_MACRO(!__PHYSFS_verifySecurity(h, dirName), NULL, 0);
+
+    start = str = malloc(strlen(dirName) + 1);
+    BAIL_IF_MACRO(str == NULL, ERR_OUT_OF_MEMORY, 0);
+    strcpy(str, dirName);
 
-    str = convertToDependentNotation(writeDir, dirName, NULL);
-    if (str == NULL)  /* __PHYSFS_setError is called in convert call. */
-        return(0);
+    while (1)
+    {
+        end = strchr(start, '/');
+        if (end != NULL)
+            *end = '\0';
+
+        retval = h->funcs->mkdir(h, str);
+        if (!retval)
+            break;
 
-    rc = createDirs_dependent(str);
+        if (end == NULL)
+            break;
+
+        *end = '/';
+        start = end + 1;
+    } /* while */
+
     free(str);
-    return(rc);
+    return(retval);
 } /* PHYSFS_mkdir */
 
 
-int PHYSFS_delete(const char *filename)
+int PHYSFS_delete(const char *fname)
 {
-    char *str;
-    int rc;
-
-    BAIL_IF_MACRO(writeDir == NULL, ERR_NO_WRITE_DIR, NULL);
-
-    str = convertToDependentNotation(writeDir, fileName, NULL);
-    if (str == NULL)  /* __PHYSFS_setError is called in convert call. */
-        return(0);
-
-    rc = remove(str);
-    free(str);
-
-    rc = (rc == 0);
-    if (!rc)
-        __PHYSFS_setError(strerror(errno));
-
-    return(rc);
+    DirHandle *h;
+    BAIL_IF_MACRO(writeDir == NULL, ERR_NO_WRITE_DIR, 0);
+    h = writeDir->dirHandle;
+    BAIL_IF_MACRO(h->funcs->remove == NULL, ERR_NOT_SUPPORTED, 0);
+    BAIL_IF_MACRO(!__PHYSFS_verifySecurity(h, fname), NULL, 0);
+    return(h->funcs->remove(h, fname));
 } /* PHYSFS_delete */
 
 
-void PHYSFS_permitSymbolicLinks(int allow)
-{
-    allowSymLinks = allow;
-} /* PHYSFS_permitSymbolicLinks */
-
-
-/**
- * Figure out where in the search path a file resides. The file is specified
- *  in platform-independent notation. The returned filename will be the
- *  element of the search path where the file was found, which may be a
- *  directory, or an archive. Even if there are multiple matches in different
- *  parts of the search path, only the first one found is used, just like
- *  when opening a file.
- *
- * So, if you look for "maps/level1.map", and C:\mygame is in your search
- *  path and C:\mygame\maps\level1.map exists, then "C:\mygame" is returned.
- *
- * If a match is a symbolic link, and you've not explicitly permitted symlinks,
- *  then it will be ignored, and the search for a match will continue.
- *
- *     @param filename file to look for.
- *    @return READ ONLY string of element of search path containing the
- *             the file in question. NULL if not found.
- */
 const char *PHYSFS_getRealDir(const char *filename)
 {
+    DirInfo *i;
+
+    for (i = searchPath; i != NULL; i = i->next)
+    {
+        DirHandle *h = i->dirHandle;
+        if (__PHYSFS_verifySecurity(h, filename))
+        {
+            if (h->funcs->exists(h, filename))
+                return(i->dirName);
+        } /* if */
+    } /* for */
+
+    return(NULL);
 } /* PHYSFS_getRealDir */
 
 
-static void countList(LinkedStringList *list)
+static int countList(LinkedStringList *list)
 {
     int retval = 0;
     LinkedStringList *i;
@@ -797,16 +892,19 @@
 
 char **PHYSFS_enumerateFiles(const char *path)
 {
-    SearchDirInfo *i;
+    DirInfo *i;
     char **retval = NULL;
     LinkedStringList *rc;
     LinkedStringList *finalList = NULL;
 
     for (i = searchPath; i != NULL; i = i->next)
     {
-        assert(i->reader->funcs->enumerateFiles != NULL);
-        rc = i->reader->funcs->enumerateFiles(path);
-        interpolateStringLists(&finalList, rc);
+        DirHandle *h = i->dirHandle;
+        if (__PHYSFS_verifySecurity(h, path))
+        {
+            rc = h->funcs->enumerateFiles(h, path);
+            interpolateStringLists(&finalList, rc);
+        } /* if */
     } /* for */
 
     retval = convertStringListToPhysFSList(finalList);
@@ -814,6 +912,50 @@
 } /* PHYSFS_enumerateFiles */
 
 
+int PHYSFS_exists(const char *fname)
+{
+    return(PHYSFS_getRealDir(fname) != NULL);
+} /* PHYSFS_exists */
+
+
+int PHYSFS_isDirectory(const char *fname)
+{
+    DirInfo *i;
+
+    for (i = searchPath; i != NULL; i = i->next)
+    {
+        DirHandle *h = i->dirHandle;
+        if (__PHYSFS_verifySecurity(h, fname))
+        {
+            if (h->funcs->exists(h, fname))
+                return(h->funcs->isDirectory(h, fname));
+        } /* if */
+    } /* for */
+
+    return(0);
+} /* PHYSFS_isDirectory */
+
+
+int PHYSFS_isSymbolicLink(const char *fname)
+{
+    DirInfo *i;
+
+    if (!allowSymLinks)
+        return(0);
+
+    for (i = searchPath; i != NULL; i = i->next)
+    {
+        DirHandle *h = i->dirHandle;
+        if (__PHYSFS_verifySecurity(h, fname))
+        {
+            if (h->funcs->exists(h, fname))
+                return(h->funcs->isSymLink(h, fname));
+        } /* if */
+    } /* for */
+
+    return(0);
+} /* PHYSFS_isSymbolicLink */
+
 /**
  * Open a file for writing, in platform-independent notation and in relation
  *  to the write path as the root of the writable filesystem. The specified
@@ -826,6 +968,7 @@
  */
 PHYSFS_file *PHYSFS_openWrite(const char *filename)
 {
+return NULL;
 } /* PHYSFS_openWrite */
 
 
@@ -842,6 +985,7 @@
  */
 PHYSFS_file *PHYSFS_openAppend(const char *filename)
 {
+return NULL;
 } /* PHYSFS_openAppend */
 
 
@@ -857,44 +1001,31 @@
  */
 PHYSFS_file *PHYSFS_openRead(const char *filename)
 {
+return NULL;
 } /* PHYSFS_openRead */
 
 
-/**
- * Close a PhysicsFS filehandle. This call is capable of failing if the
- *  operating system was buffering writes to this file, and (now forced to
- *  write those changes to physical media) can not store the data for any
- *  reason. In such a case, the filehandle stays open. A well-written program
- *  should ALWAYS check the return value from the close call in addition to
- *  every writing call!
- *
- *   @param handle handle returned from PHYSFS_open*().
- *  @return nonzero on success, zero on error. Specifics of the error can be
- *          gleaned from PHYSFS_getLastError().
- */
 int PHYSFS_close(PHYSFS_file *handle)
 {
     FileHandle *h = (FileHandle *) handle->opaque;
     FileHandleList *i;
-    FileHandleList **lists[] = { &openWriteList, &openReadList, NULL };
+    FileHandleList *prev;
+    FileHandleList **_lists[] = { &openWriteList, &openReadList, NULL };
+    FileHandleList ***lists = _lists;  /* gay. */
     int rc;
 
-    assert(h != NULL);
-    assert(h->funcs != NULL);
-    assert(h->funcs->close != NULL);
-
     while (lists != NULL)
     {
-        for (i = *(*lists); i != NULL; i = i->next)
+        for (i = *(*lists), prev = NULL; i != NULL; prev = i, i = i->next)
         {
-            if (i->handle == h)
+            if (((FileHandle *) i->handle->opaque) == h)
             {
-                rc = h->close(h);
+                rc = h->funcs->close(h);
                 if (!rc)
                     return(0);
 
                 if (prev == NULL)
-                    *lists = i->next;
+                    *(*lists) = i->next;
                 else
                     prev->next = i->next;
                 free(i);
@@ -905,7 +1036,8 @@
         lists++;
     } /* while */
 
-    assert(0);  /* shouldn't EVER hit this. */
+    __PHYSFS_setError(ERR_NOT_A_HANDLE);
+    return(0);
 } /* PHYSFS_close */
 
 
@@ -960,5 +1092,6 @@
     return(h->funcs->seek(h, pos));
 } /* PHYSFS_seek */
 
+
 /* end of physfs.c ... */