Removed isDirectory, isSymLink and exists methods from internal code.
authorRyan C. Gordon <icculus@icculus.org>
Sun, 05 Sep 2010 02:41:13 -0400
changeset 1125 bcff76dbd9fd
parent 1124 6ef3d04af1c4
child 1126 f7877496507c
Removed isDirectory, isSymLink and exists methods from internal code. Use the PhysFS stat() interface instead.
src/archiver_dir.c
src/archiver_grp.c
src/archiver_hog.c
src/archiver_iso9660.c
src/archiver_lzma.c
src/archiver_mvl.c
src/archiver_qpak.c
src/archiver_wad.c
src/archiver_zip.c
src/physfs.c
src/physfs.h
src/physfs_internal.h
src/platform_os2.c
src/platform_pocketpc.c
src/platform_posix.c
src/platform_windows.c
test/test_physfs.c
--- a/src/archiver_dir.c	Mon Aug 30 03:09:00 2010 -0400
+++ b/src/archiver_dir.c	Sun Sep 05 02:41:13 2010 -0400
@@ -18,13 +18,17 @@
 
 static void *DIR_openArchive(PHYSFS_Io *io, const char *name, int forWriting)
 {
+    PHYSFS_Stat statbuf;
     const char *dirsep = PHYSFS_getDirSeparator();
     char *retval = NULL;
     const size_t namelen = strlen(name);
     const size_t seplen = strlen(dirsep);
+    int exists = 0;
 
     assert(io == NULL);  /* shouldn't create an Io for these. */
-    BAIL_IF_MACRO(!__PHYSFS_platformIsDirectory(name), ERR_NOT_AN_ARCHIVE, NULL);
+    BAIL_IF_MACRO(!__PHYSFS_platformStat(name, &exists, &statbuf), NULL, NULL);
+    if ((!exists) || (statbuf.filetype != PHYSFS_FILETYPE_DIRECTORY))
+        BAIL_MACRO(ERR_NOT_AN_ARCHIVE, NULL);
 
     retval = allocator.Malloc(namelen + seplen + 1);
     BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
@@ -55,46 +59,6 @@
 } /* DIR_enumerateFiles */
 
 
-static int DIR_exists(dvoid *opaque, const char *name)
-{
-    char *f = __PHYSFS_platformCvtToDependent((char *) opaque, name, NULL);
-    int retval;
-
-    BAIL_IF_MACRO(f == NULL, NULL, 0);
-    retval = __PHYSFS_platformExists(f);
-    allocator.Free(f);
-    return retval;
-} /* DIR_exists */
-
-
-static int DIR_isDirectory(dvoid *opaque, const char *name, int *fileExists)
-{
-    char *d = __PHYSFS_platformCvtToDependent((char *) opaque, name, NULL);
-    int retval = 0;
-
-    BAIL_IF_MACRO(d == NULL, NULL, 0);
-    *fileExists = __PHYSFS_platformExists(d);
-    if (*fileExists)
-        retval = __PHYSFS_platformIsDirectory(d);
-    allocator.Free(d);
-    return retval;
-} /* DIR_isDirectory */
-
-
-static int DIR_isSymLink(dvoid *opaque, const char *name, int *fileExists)
-{
-    char *f = __PHYSFS_platformCvtToDependent((char *) opaque, name, NULL);
-    int retval = 0;
-
-    BAIL_IF_MACRO(f == NULL, NULL, 0);
-    *fileExists = __PHYSFS_platformExists(f);
-    if (*fileExists)
-        retval = __PHYSFS_platformIsSymLink(f);
-    allocator.Free(f);
-    return retval;
-} /* DIR_isSymLink */
-
-
 static PHYSFS_Io *doOpen(dvoid *opaque, const char *name,
                          const int mode, int *fileExists)
 {
@@ -113,7 +77,8 @@
     allocator.Free(f);
     if (io == NULL)
     {
-        *fileExists = __PHYSFS_platformExists(f);
+        PHYSFS_Stat statbuf;
+        __PHYSFS_platformStat(f, fileExists, &statbuf);
         return NULL;
     } /* if */
 
@@ -197,9 +162,6 @@
     &__PHYSFS_ArchiveInfo_DIR,
     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     */
--- a/src/archiver_grp.c	Mon Aug 30 03:09:00 2010 -0400
+++ b/src/archiver_grp.c	Sun Sep 05 02:41:13 2010 -0400
@@ -319,26 +319,6 @@
 } /* grp_find_entry */
 
 
-static int GRP_exists(dvoid *opaque, const char *name)
-{
-    return (grp_find_entry((GRPinfo *) opaque, name) != NULL);
-} /* GRP_exists */
-
-
-static int GRP_isDirectory(dvoid *opaque, const char *name, int *fileExists)
-{
-    *fileExists = GRP_exists(opaque, name);
-    return 0;  /* never directories in a groupfile. */
-} /* GRP_isDirectory */
-
-
-static int GRP_isSymLink(dvoid *opaque, const char *name, int *fileExists)
-{
-    *fileExists = GRP_exists(opaque, name);
-    return 0;  /* never symlinks in a groupfile. */
-} /* GRP_isSymLink */
-
-
 static PHYSFS_Io *GRP_openRead(dvoid *opaque, const char *fnm, int *fileExists)
 {
     PHYSFS_Io *retval = NULL;
@@ -443,9 +423,6 @@
     &__PHYSFS_ArchiveInfo_GRP,
     GRP_openArchive,        /* openArchive() method    */
     GRP_enumerateFiles,     /* enumerateFiles() method */
-    GRP_exists,             /* exists() method         */
-    GRP_isDirectory,        /* isDirectory() method    */
-    GRP_isSymLink,          /* isSymLink() method      */
     GRP_openRead,           /* openRead() method       */
     GRP_openWrite,          /* openWrite() method      */
     GRP_openAppend,         /* openAppend() method     */
--- a/src/archiver_hog.c	Mon Aug 30 03:09:00 2010 -0400
+++ b/src/archiver_hog.c	Sun Sep 05 02:41:13 2010 -0400
@@ -335,26 +335,6 @@
 } /* hog_find_entry */
 
 
-static int HOG_exists(dvoid *opaque, const char *name)
-{
-    return (hog_find_entry((HOGinfo *) opaque, name) != NULL);
-} /* HOG_exists */
-
-
-static int HOG_isDirectory(dvoid *opaque, const char *name, int *fileExists)
-{
-    *fileExists = HOG_exists(opaque, name);
-    return 0;  /* never directories in a groupfile. */
-} /* HOG_isDirectory */
-
-
-static int HOG_isSymLink(dvoid *opaque, const char *name, int *fileExists)
-{
-    *fileExists = HOG_exists(opaque, name);
-    return 0;  /* never symlinks in a groupfile. */
-} /* HOG_isSymLink */
-
-
 static PHYSFS_Io *HOG_openRead(dvoid *opaque, const char *fnm, int *fileExists)
 {
     PHYSFS_Io *retval = NULL;
@@ -459,9 +439,6 @@
     &__PHYSFS_ArchiveInfo_HOG,
     HOG_openArchive,        /* openArchive() method    */
     HOG_enumerateFiles,     /* enumerateFiles() method */
-    HOG_exists,             /* exists() method         */
-    HOG_isDirectory,        /* isDirectory() method    */
-    HOG_isSymLink,          /* isSymLink() method      */
     HOG_openRead,           /* openRead() method       */
     HOG_openWrite,          /* openWrite() method      */
     HOG_openAppend,         /* openAppend() method     */
--- a/src/archiver_iso9660.c	Mon Aug 30 03:09:00 2010 -0400
+++ b/src/archiver_iso9660.c	Sun Sep 05 02:41:13 2010 -0400
@@ -875,16 +875,6 @@
 } /* ISO9660_enumerateFiles */
 
 
-static int ISO9660_exists(dvoid *opaque, const char *name)
-{
-    ISO9660Handle *handle = (ISO9660Handle*) opaque;
-    ISO9660FileDescriptor descriptor;
-    int exists = 0;
-    BAIL_IF_MACRO(iso_find_dir_entry(handle, name, &descriptor, &exists), NULL, -1);
-    return exists;
-} /* ISO9660_exists */
-
-
 static int ISO9660_stat(dvoid *opaque, const char *name, int *exists,
                         PHYSFS_Stat *stat)
 {
@@ -928,22 +918,6 @@
 } /* ISO9660_stat */
 
 
-static int ISO9660_isDirectory(dvoid *opaque, const char *name, int *fileExists)
-{
-    ISO9660Handle *handle = (ISO9660Handle*) opaque;
-    ISO9660FileDescriptor descriptor;
-    BAIL_IF_MACRO(iso_find_dir_entry(handle, name, &descriptor, fileExists), NULL, 0);
-    return descriptor.flags.directory;
-} /* ISO9660_isDirectory */
-
-
-static int ISO9660_isSymLink(dvoid *opaque, const char *name, int *fileExists)
-{
-    *fileExists = ISO9660_exists(opaque, name);
-    return 0;
-} /* ISO9660_isSymLink */
-
-
 /*******************************************************************************
  * Not supported functions
  ******************************************************************************/
@@ -986,9 +960,6 @@
     &__PHYSFS_ArchiveInfo_ISO9660,
     ISO9660_openArchive,        /* openArchive() method    */
     ISO9660_enumerateFiles,     /* enumerateFiles() method */
-    ISO9660_exists,             /* exists() method         */
-    ISO9660_isDirectory,        /* isDirectory() method    */
-    ISO9660_isSymLink,          /* isSymLink() method      */
     ISO9660_openRead,           /* openRead() method       */
     ISO9660_openWrite,          /* openWrite() method      */
     ISO9660_openAppend,         /* openAppend() method     */
--- a/src/archiver_lzma.c	Mon Aug 30 03:09:00 2010 -0400
+++ b/src/archiver_lzma.c	Sun Sep 05 02:41:13 2010 -0400
@@ -581,30 +581,6 @@
 } /* LZMA_enumerateFiles */
 
 
-static int LZMA_exists(dvoid *opaque, const char *name)
-{
-    LZMAarchive *archive = (LZMAarchive *) opaque;
-    return (lzma_find_file(archive, name) != NULL);
-} /* LZMA_exists */
-
-
-static int LZMA_isDirectory(dvoid *opaque, const char *name, int *fileExists)
-{
-    LZMAarchive *archive = (LZMAarchive *) opaque;
-    LZMAfile *file = lzma_find_file(archive, name);
-
-    *fileExists = (file != NULL);
-
-    return ((file == NULL) ? 0 : file->item->IsDirectory);
-} /* LZMA_isDirectory */
-
-
-static int LZMA_isSymLink(dvoid *opaque, const char *name, int *fileExists)
-{
-    BAIL_MACRO(ERR_NOT_SUPPORTED, 0);
-} /* LZMA_isSymLink */
-
-
 static PHYSFS_Io *LZMA_openRead(dvoid *opaque, const char *name, int *fileExists)
 {
     LZMAarchive *archive = (LZMAarchive *) opaque;
@@ -719,9 +695,6 @@
     &__PHYSFS_ArchiveInfo_LZMA,
     LZMA_openArchive,        /* openArchive() method    */
     LZMA_enumerateFiles,     /* enumerateFiles() method */
-    LZMA_exists,             /* exists() method         */
-    LZMA_isDirectory,        /* isDirectory() method    */
-    LZMA_isSymLink,          /* isSymLink() method      */
     LZMA_openRead,           /* openRead() method       */
     LZMA_openWrite,          /* openWrite() method      */
     LZMA_openAppend,         /* openAppend() method     */
--- a/src/archiver_mvl.c	Mon Aug 30 03:09:00 2010 -0400
+++ b/src/archiver_mvl.c	Sun Sep 05 02:41:13 2010 -0400
@@ -316,26 +316,6 @@
 } /* mvl_find_entry */
 
 
-static int MVL_exists(dvoid *opaque, const char *name)
-{
-    return (mvl_find_entry((MVLinfo *) opaque, name) != NULL);
-} /* MVL_exists */
-
-
-static int MVL_isDirectory(dvoid *opaque, const char *name, int *fileExists)
-{
-    *fileExists = MVL_exists(opaque, name);
-    return 0;  /* never directories in a groupfile. */
-} /* MVL_isDirectory */
-
-
-static int MVL_isSymLink(dvoid *opaque, const char *name, int *fileExists)
-{
-    *fileExists = MVL_exists(opaque, name);
-    return 0;  /* never symlinks in a groupfile. */
-} /* MVL_isSymLink */
-
-
 static PHYSFS_Io *MVL_openRead(dvoid *opaque, const char *fnm, int *fileExists)
 {
     PHYSFS_Io *retval = NULL;
@@ -440,9 +420,6 @@
     &__PHYSFS_ArchiveInfo_MVL,
     MVL_openArchive,        /* openArchive() method    */
     MVL_enumerateFiles,     /* enumerateFiles() method */
-    MVL_exists,             /* exists() method         */
-    MVL_isDirectory,        /* isDirectory() method    */
-    MVL_isSymLink,          /* isSymLink() method      */
     MVL_openRead,           /* openRead() method       */
     MVL_openWrite,          /* openWrite() method      */
     MVL_openAppend,         /* openAppend() method     */
--- a/src/archiver_qpak.c	Mon Aug 30 03:09:00 2010 -0400
+++ b/src/archiver_qpak.c	Sun Sep 05 02:41:13 2010 -0400
@@ -451,36 +451,6 @@
 } /* qpak_find_entry */
 
 
-static int QPAK_exists(dvoid *opaque, const char *name)
-{
-    int isDir;    
-    QPAKinfo *info = (QPAKinfo *) opaque;
-    QPAKentry *entry = qpak_find_entry(info, name, &isDir);
-    return ((entry != NULL) || (isDir));
-} /* QPAK_exists */
-
-
-static int QPAK_isDirectory(dvoid *opaque, const char *name, int *fileExists)
-{
-    QPAKinfo *info = (QPAKinfo *) opaque;
-    int isDir;
-    QPAKentry *entry = qpak_find_entry(info, name, &isDir);
-
-    *fileExists = ((isDir) || (entry != NULL));
-    if (isDir)
-        return 1; /* definitely a dir. */
-
-    BAIL_MACRO(ERR_NO_SUCH_FILE, 0);
-} /* QPAK_isDirectory */
-
-
-static int QPAK_isSymLink(dvoid *opaque, const char *name, int *fileExists)
-{
-    *fileExists = QPAK_exists(opaque, name);
-    return 0;  /* never symlinks in a quake pak. */
-} /* QPAK_isSymLink */
-
-
 static PHYSFS_Io *QPAK_openRead(dvoid *opaque, const char *fnm, int *fileExists)
 {
     PHYSFS_Io *io = NULL;
@@ -595,9 +565,6 @@
     &__PHYSFS_ArchiveInfo_QPAK,
     QPAK_openArchive,        /* openArchive() method    */
     QPAK_enumerateFiles,     /* enumerateFiles() method */
-    QPAK_exists,             /* exists() method         */
-    QPAK_isDirectory,        /* isDirectory() method    */
-    QPAK_isSymLink,          /* isSymLink() method      */
     QPAK_openRead,           /* openRead() method       */
     QPAK_openWrite,          /* openWrite() method      */
     QPAK_openAppend,         /* openAppend() method     */
--- a/src/archiver_wad.c	Mon Aug 30 03:09:00 2010 -0400
+++ b/src/archiver_wad.c	Sun Sep 05 02:41:13 2010 -0400
@@ -336,47 +336,6 @@
 } /* wad_find_entry */
 
 
-static int WAD_exists(dvoid *opaque, const char *name)
-{
-    return (wad_find_entry((WADinfo *) opaque, name) != NULL);
-} /* WAD_exists */
-
-
-static int WAD_isDirectory(dvoid *opaque, const char *name, int *fileExists)
-{
-    WADentry *entry = wad_find_entry(((WADinfo *) opaque), name);
-    const int exists = (entry != NULL);
-    *fileExists = exists;
-    if (exists)
-    {
-        char *n;
-
-        /* Can't be a directory if it's a subdirectory. */
-        if (strchr(entry->name, '/') != NULL)
-            return 0;
-
-        /* !!! FIXME: this isn't really something we should do. */
-        /* !!! FIXME: I probably broke enumeration up there, too. */
-        /* Check if it matches "MAP??" or "E?M?" ... */
-        n = entry->name;
-        if ((n[0] == 'E' && n[2] == 'M') ||
-            (n[0] == 'M' && n[1] == 'A' && n[2] == 'P' && n[6] == 0))
-        {
-            return 1;
-        } /* if */
-    } /* if */
-
-    return 0;
-} /* WAD_isDirectory */
-
-
-static int WAD_isSymLink(dvoid *opaque, const char *name, int *fileExists)
-{
-    *fileExists = WAD_exists(opaque, name);
-    return 0;  /* never symlinks in a wad. */
-} /* WAD_isSymLink */
-
-
 static PHYSFS_Io *WAD_openRead(dvoid *opaque, const char *fnm, int *fileExists)
 {
     PHYSFS_Io *retval = NULL;
@@ -481,9 +440,6 @@
     &__PHYSFS_ArchiveInfo_WAD,
     WAD_openArchive,        /* openArchive() method    */
     WAD_enumerateFiles,     /* enumerateFiles() method */
-    WAD_exists,             /* exists() method         */
-    WAD_isDirectory,        /* isDirectory() method    */
-    WAD_isSymLink,          /* isSymLink() method      */
     WAD_openRead,           /* openRead() method       */
     WAD_openWrite,          /* openWrite() method      */
     WAD_openAppend,         /* openAppend() method     */
--- a/src/archiver_zip.c	Mon Aug 30 03:09:00 2010 -0400
+++ b/src/archiver_zip.c	Sun Sep 05 02:41:13 2010 -0400
@@ -1257,51 +1257,6 @@
 } /* ZIP_enumerateFiles */
 
 
-static int ZIP_exists(dvoid *opaque, const char *name)
-{
-    int isDir;    
-    ZIPinfo *info = (ZIPinfo *) opaque;
-    ZIPentry *entry = zip_find_entry(info, name, &isDir);
-    return ((entry != NULL) || (isDir));
-} /* ZIP_exists */
-
-
-static int ZIP_isDirectory(dvoid *opaque, const char *name, int *fileExists)
-{
-    ZIPinfo *info = (ZIPinfo *) opaque;
-    int isDir;
-    ZIPentry *entry = zip_find_entry(info, name, &isDir);
-
-    *fileExists = ((isDir) || (entry != NULL));
-    if (isDir)
-        return 1; /* definitely a dir. */
-
-    /* Follow symlinks. This means we might need to resolve entries. */
-    BAIL_IF_MACRO(entry == NULL, ERR_NO_SUCH_FILE, 0);
-
-    if (entry->resolved == ZIP_UNRESOLVED_SYMLINK) /* gotta resolve it. */
-    {
-        if (!zip_resolve(info->io, info, entry))
-            return 0;
-    } /* if */
-
-    BAIL_IF_MACRO(entry->resolved == ZIP_BROKEN_SYMLINK, NULL, 0);
-    BAIL_IF_MACRO(entry->symlink == NULL, ERR_NOT_A_DIR, 0);
-
-    return (zip_find_start_of_dir(info, entry->symlink->name, 1) >= 0);
-} /* ZIP_isDirectory */
-
-
-static int ZIP_isSymLink(dvoid *opaque, const char *name, int *fileExists)
-{
-    int isDir;
-    const ZIPentry *entry = zip_find_entry((ZIPinfo *) opaque, name, &isDir);
-    *fileExists = ((isDir) || (entry != NULL));
-    BAIL_IF_MACRO(entry == NULL, NULL, 0);
-    return zip_entry_is_symlink(entry);
-} /* ZIP_isSymLink */
-
-
 static PHYSFS_Io *zip_get_io(PHYSFS_Io *io, ZIPinfo *inf, ZIPentry *entry)
 {
     int success;
@@ -1424,6 +1379,8 @@
     const ZIPinfo *info = (const ZIPinfo *) opaque;
     const ZIPentry *entry = zip_find_entry(info, filename, &isDir);
 
+    /* !!! FIXME: does this need to resolve entries here? */
+
     *exists = isDir || (entry != 0);
     if (!*exists)
         return 0;
@@ -1469,9 +1426,6 @@
     &__PHYSFS_ArchiveInfo_ZIP,
     ZIP_openArchive,        /* openArchive() method    */
     ZIP_enumerateFiles,     /* enumerateFiles() method */
-    ZIP_exists,             /* exists() method         */
-    ZIP_isDirectory,        /* isDirectory() method    */
-    ZIP_isSymLink,          /* isSymLink() method      */
     ZIP_openRead,           /* openRead() method       */
     ZIP_openWrite,          /* openWrite() method      */
     ZIP_openAppend,         /* openAppend() method     */
--- a/src/physfs.c	Mon Aug 30 03:09:00 2010 -0400
+++ b/src/physfs.c	Sun Sep 05 02:41:13 2010 -0400
@@ -859,8 +859,6 @@
 
     if (io == NULL)
     {
-        BAIL_IF_MACRO(!__PHYSFS_platformExists(d), ERR_NO_SUCH_FILE, NULL);
-
         /* DIR gets first shot (unlike the rest, it doesn't deal with files). */
         retval = tryOpenDir(io, &__PHYSFS_Archiver_DIR, d, forWriting);
         if (retval != NULL)
@@ -1830,11 +1828,14 @@
     {
         while (1)
         {
+            PHYSFS_Stat statbuf;
             int rc = 0;
             end = strchr(start, '/');
 
             if (end != NULL) *end = '\0';
-            rc = h->funcs->isSymLink(h->opaque, fname, &retval);
+            rc = h->funcs->stat(h->opaque, fname, &retval, &statbuf);
+            if (rc)
+                rc = (statbuf.filetype == PHYSFS_FILETYPE_SYMLINK);
             if (end != NULL) *end = '/';
 
             BAIL_IF_MACRO(rc, ERR_SYMLINK_DISALLOWED, 0);   /* insecure. */
@@ -1887,7 +1888,11 @@
 
         /* only check for existance if all parent dirs existed, too... */
         if (exists)
-            retval = h->funcs->isDirectory(h->opaque, dname, &exists);
+        {
+            PHYSFS_Stat statbuf;
+            const int rc = h->funcs->stat(h->opaque, dname, &exists, &statbuf);
+            retval = ((rc) && (statbuf.filetype == PHYSFS_FILETYPE_DIRECTORY));
+        } /* if */
 
         if (!exists)
             retval = h->funcs->mkdir(h->opaque, dname);
@@ -1981,9 +1986,12 @@
             } /* if */
             else if (verifyPath(i, &arcfname, 0))
             {
-                if (i->funcs->exists(i->opaque, arcfname))
+                PHYSFS_Stat statbuf;
+                int exists = 0;
+                if (i->funcs->stat(i->opaque, arcfname, &exists, &statbuf))
                 {
-                    retval = i->dirName;
+                    if (exists)
+                        retval = i->dirName;
                     break;
                 } /* if */
             } /* if */
@@ -2157,83 +2165,19 @@
 } /* PHYSFS_getLastModTime */
 
 
-int PHYSFS_isDirectory(const char *_fname)
+int PHYSFS_isDirectory(const char *fname)
 {
-    int retval = 0;
-    size_t len;
-    char *fname;
-
-    BAIL_IF_MACRO(_fname == NULL, ERR_INVALID_ARGUMENT, 0);
-    len = strlen(_fname) + 1;
-    fname = (char *) __PHYSFS_smallAlloc(len);
-    BAIL_IF_MACRO(fname == NULL, ERR_OUT_OF_MEMORY, 0);
-
-    if (!sanitizePlatformIndependentPath(_fname, fname))
-        retval = 0;
-
-    else if (*fname == '\0')
-        retval = 1;  /* Root is always a dir.  :) */
-
-    else
-    {
-        DirHandle *i;
-        int exists = 0;
-
-        __PHYSFS_platformGrabMutex(stateLock);
-        for (i = searchPath; ((i != NULL) && (!exists)); i = i->next)
-        {
-            char *arcfname = fname;
-            if ((exists = partOfMountPoint(i, arcfname)) != 0)
-                retval = 1;
-            else if (verifyPath(i, &arcfname, 0))
-                retval = i->funcs->isDirectory(i->opaque, arcfname, &exists);
-        } /* for */
-        __PHYSFS_platformReleaseMutex(stateLock);
-    } /* else */
-
-    __PHYSFS_smallFree(fname);
-    return retval;
+    PHYSFS_Stat statbuf;
+    BAIL_IF_MACRO(!PHYSFS_stat(fname, &statbuf), NULL, 0);
+    return (statbuf.filetype == PHYSFS_FILETYPE_DIRECTORY);
 } /* PHYSFS_isDirectory */
 
 
-int PHYSFS_isSymbolicLink(const char *_fname)
+int PHYSFS_isSymbolicLink(const char *fname)
 {
-    int retval = 0;
-    size_t len;
-    char *fname;
-
-    BAIL_IF_MACRO(!allowSymLinks, ERR_SYMLINK_DISALLOWED, 0);
-
-    BAIL_IF_MACRO(_fname == NULL, ERR_INVALID_ARGUMENT, 0);
-    len = strlen(_fname) + 1;
-    fname = (char *) __PHYSFS_smallAlloc(len);
-    BAIL_IF_MACRO(fname == NULL, ERR_OUT_OF_MEMORY, 0);
-
-    if (!sanitizePlatformIndependentPath(_fname, fname))
-        retval = 0;
-
-    else if (*fname == '\0')
-        retval = 1;  /* Root is never a symlink. */
-
-    else
-    {
-        DirHandle *i;
-        int fileExists = 0;
-
-        __PHYSFS_platformGrabMutex(stateLock);
-        for (i = searchPath; ((i != NULL) && (!fileExists)); i = i->next)
-        {
-            char *arcfname = fname;
-            if ((fileExists = partOfMountPoint(i, arcfname)) != 0)
-                retval = 0;  /* virtual dir...not a symlink. */
-            else if (verifyPath(i, &arcfname, 0))
-                retval = i->funcs->isSymLink(i->opaque, arcfname, &fileExists);
-        } /* for */
-        __PHYSFS_platformReleaseMutex(stateLock);
-    } /* else */
-
-    __PHYSFS_smallFree(fname);
-    return retval;
+    PHYSFS_Stat statbuf;
+    BAIL_IF_MACRO(!PHYSFS_stat(fname, &statbuf), NULL, 0);
+    return (statbuf.filetype == PHYSFS_FILETYPE_SYMLINK);
 } /* PHYSFS_isSymbolicLink */
 
 
--- a/src/physfs.h	Mon Aug 30 03:09:00 2010 -0400
+++ b/src/physfs.h	Sun Sep 05 02:41:13 2010 -0400
@@ -665,6 +665,11 @@
  *  in platform-independent notation. That is, when setting up your
  *  search and write paths, etc, symlinks are never checked for.
  *
+ * Please note that PHYSFS_stat() will always check the path specified; if
+ *  that path is a symlink, it will not be followed in any case. If symlinks
+ *  aren't permitted through this function, PHYSFS_stat() ignores them, and
+ *  would treat the query as if the path didn't exist at all.
+ *
  * Symbolic link permission can be enabled or disabled at any time after
  *  you've called PHYSFS_init(), and is disabled by default.
  *
@@ -1086,9 +1091,6 @@
  *
  *    \param fname filename in platform-independent notation.
  *   \return non-zero if filename exists. zero otherwise.
- *
- * \sa PHYSFS_isDirectory
- * \sa PHYSFS_isSymbolicLink
  */
 PHYSFS_DECL int PHYSFS_exists(const char *fname);
 
@@ -1097,6 +1099,9 @@
  * \fn int PHYSFS_isDirectory(const char *fname)
  * \brief Determine if a file in the search path is really a directory.
  *
+ * \deprecated As of PhysicsFS 2.1, use PHYSFS_stat() instead. This
+ *             function just wraps it anyhow.
+ *
  * Determine if the first occurence of (fname) in the search path is
  *  really a directory entry.
  *
@@ -1107,16 +1112,19 @@
  *    \param fname filename in platform-independent notation.
  *   \return non-zero if filename exists and is a directory.  zero otherwise.
  *
+ * \sa PHYSFS_stat
  * \sa PHYSFS_exists
- * \sa PHYSFS_isSymbolicLink
  */
-PHYSFS_DECL int PHYSFS_isDirectory(const char *fname);
+PHYSFS_DECL int PHYSFS_isDirectory(const char *fname) PHYSFS_DEPRECATED;
 
 
 /**
  * \fn int PHYSFS_isSymbolicLink(const char *fname)
  * \brief Determine if a file in the search path is really a symbolic link.
  *
+ * \deprecated As of PhysicsFS 2.1, use PHYSFS_stat() instead. This
+ *             function just wraps it anyhow.
+ *
  * Determine if the first occurence of (fname) in the search path is
  *  really a symbolic link.
  *
@@ -1127,10 +1135,10 @@
  *    \param fname filename in platform-independent notation.
  *   \return non-zero if filename exists and is a symlink.  zero otherwise.
  *
+ * \sa PHYSFS_stat
  * \sa PHYSFS_exists
- * \sa PHYSFS_isDirectory
  */
-PHYSFS_DECL int PHYSFS_isSymbolicLink(const char *fname);
+PHYSFS_DECL int PHYSFS_isSymbolicLink(const char *fname) PHYSFS_DEPRECATED;
 
 
 /**
@@ -2603,6 +2611,12 @@
  *
  * Obtain various information about a file or directory from the meta data.
  *
+ * This function will never follow symbolic links. If you haven't enabled
+ *  symlinks with PHYSFS_permitSymbolicLinks(), stat'ing a symlink will be
+ *  treated like stat'ing a non-existant file. If symlinks are enabled,
+ *  stat'ing a symlink will give you information on the link itself and not
+ *  what it points to.
+ *
  *    \param fname filename to check, in platform-indepedent notation.
  *    \param stat pointer to structure to fill in with data about (fname).
  *   \return non-zero on success, zero on failure. On failure, (stat)'s
--- a/src/physfs_internal.h	Mon Aug 30 03:09:00 2010 -0400
+++ b/src/physfs_internal.h	Sun Sep 05 02:41:13 2010 -0400
@@ -731,9 +731,9 @@
      *  openArchive() method, then pass it as the "opaque" dvoid to the
      *  others.
      *
-     * Symlinks should always be followed; PhysicsFS will use the
-     *  isSymLink() method and make a judgement on whether to
-     *  continue to call other methods based on that.
+     * Symlinks should always be followed (except in stat()); PhysicsFS will
+     *  use the stat() method to check for symlinks and make a judgement on
+     *  whether to continue to call other methods based on that.
      */
 
         /*
@@ -766,35 +766,6 @@
                             void *callbackdata);
 
         /*
-         * Returns non-zero if filename can be opened for reading.
-         *  This filename is in platform-independent notation.
-         *  You should not follow symlinks.
-         */
-    int (*exists)(dvoid *opaque, const char *name);
-
-        /*
-         * Returns non-zero if filename is really a directory.
-         *  This filename is in platform-independent notation.
-         *  Symlinks should be followed; if what the symlink points
-         *  to is missing, or isn't a directory, then the retval is zero.
-         *
-         * Regardless of success or failure, please set *fileExists to
-         *  non-zero if the file existed (even if it's a broken symlink!),
-         *  zero if it did not.
-         */
-    int (*isDirectory)(dvoid *opaque, const char *name, int *fileExists);
-
-        /*
-         * Returns non-zero if filename is really a symlink.
-         *  This filename is in platform-independent notation.
-         *
-         * Regardless of success or failure, please set *fileExists to
-         *  non-zero if the file existed (even if it's a broken symlink!),
-         *  zero if it did not.
-         */
-    int (*isSymLink)(dvoid *opaque, const char *name, int *fileExists);
-
-        /*
          * Open file for reading.
          *  This filename is in platform-independent notation.
          * If you can't handle multiple opens of the same file,
@@ -1275,28 +1246,6 @@
 void *__PHYSFS_platformGetThreadID(void);
 
 /*
- * Return non-zero if filename (in platform-dependent notation) exists.
- *  Symlinks should NOT be followed; at this stage, we do not care what the
- *  symlink points to. Please call __PHYSFS_SetError() with the details of
- *  why the file does not exist, if it doesn't; you are in a better position
- *  to know (path not found, bogus filename, file itself is missing, etc).
- */
-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.
  *
--- a/src/platform_os2.c	Mon Aug 30 03:09:00 2010 -0400
+++ b/src/platform_os2.c	Sun Sep 05 02:41:13 2010 -0400
@@ -297,31 +297,6 @@
 } /* __PHYSFS_platformGetUserDir */
 
 
-int __PHYSFS_platformExists(const char *_fname)
-{
-    const unsigned char *fname = (const unsigned char *) _fname;
-    FILESTATUS3 fs;
-    APIRET rc = DosQueryPathInfo(fname, FIL_STANDARD, &fs, sizeof (fs));
-    return (os2err(rc) == NO_ERROR);
-} /* __PHYSFS_platformExists */
-
-
-int __PHYSFS_platformIsSymLink(const char *fname)
-{
-    return 0;  /* no symlinks in OS/2. */
-} /* __PHYSFS_platformIsSymlink */
-
-
-int __PHYSFS_platformIsDirectory(const char *_fname)
-{
-    const unsigned char *fname = (const unsigned char *) _fname;
-    FILESTATUS3 fs;
-    APIRET rc = DosQueryPathInfo(fname, FIL_STANDARD, &fs, sizeof (fs));
-    BAIL_IF_MACRO(os2err(rc) != NO_ERROR, NULL, 0)
-    return ((fs.attrFile & FILE_DIRECTORY) != 0);
-} /* __PHYSFS_platformIsDirectory */
-
-
 /* !!! FIXME: can we lose the malloc here? */
 char *__PHYSFS_platformCvtToDependent(const char *prepend,
                                       const char *dirName,
@@ -598,8 +573,13 @@
 
 int __PHYSFS_platformDelete(const char *_path)
 {
+    FILESTATUS3 fs;
     const unsigned char *path = (const unsigned char *) _path;
-    if (__PHYSFS_platformIsDirectory(_path))
+    APIRET rc = os2err(DosQueryPathInfo(path, FIL_STANDARD, &fs, sizeof (fs)));
+
+    BAIL_IF_MACRO(rc != NO_ERROR, NULL, 0);
+
+    if (fs.attrFile & FILE_DIRECTORY)
         return (os2err(DosDeleteDir(path)) == NO_ERROR);
 
     return (os2err(DosDelete(path)) == NO_ERROR);
--- a/src/platform_pocketpc.c	Mon Aug 30 03:09:00 2010 -0400
+++ b/src/platform_pocketpc.c	Sun Sep 05 02:41:13 2010 -0400
@@ -167,40 +167,6 @@
 } /* __PHYSFS_platformGetThreadID */
 
 
-int __PHYSFS_platformExists(const char *fname)
-{
-    int retval = 0;
-    wchar_t *w_fname = NULL;
-
-    UTF8_TO_UNICODE_STACK_MACRO(w_fname, fname);
-    if (w_fname != NULL)
-        retval = (GetFileAttributes(w_fname) != INVALID_FILE_ATTRIBUTES);
-    __PHYSFS_smallFree(w_fname);
-
-    return retval;
-} /* __PHYSFS_platformExists */
-
-
-int __PHYSFS_platformIsSymLink(const char *fname)
-{
-    BAIL_MACRO(ERR_NOT_IMPLEMENTED, 0);
-} /* __PHYSFS_platformIsSymlink */
-
-
-int __PHYSFS_platformIsDirectory(const char *fname)
-{
-    int retval = 0;
-    wchar_t *w_fname = NULL;
-
-    UTF8_TO_UNICODE_STACK_MACRO(w_fname, fname);
-    if (w_fname != NULL)
-        retval = ((GetFileAttributes(w_fname) & FILE_ATTRIBUTE_DIRECTORY) != 0);
-    __PHYSFS_smallFree(w_fname);
-
-    return retval;
-} /* __PHYSFS_platformIsDirectory */
-
-
 char *__PHYSFS_platformCvtToDependent(const char *prepend,
                                       const char *dirName,
                                       const char *append)
--- a/src/platform_posix.c	Mon Aug 30 03:09:00 2010 -0400
+++ b/src/platform_posix.c	Sun Sep 05 02:41:13 2010 -0400
@@ -116,30 +116,6 @@
 } /* __PHYSFS_platformGetUserDir */
 
 
-int __PHYSFS_platformExists(const char *fname)
-{
-    struct stat statbuf;
-    BAIL_IF_MACRO(lstat(fname, &statbuf) == -1, strerror(errno), 0);
-    return 1;
-} /* __PHYSFS_platformExists */
-
-
-int __PHYSFS_platformIsSymLink(const char *fname)
-{
-    struct stat statbuf;
-    BAIL_IF_MACRO(lstat(fname, &statbuf) == -1, strerror(errno), 0);
-    return ( (S_ISLNK(statbuf.st_mode)) ? 1 : 0 );
-} /* __PHYSFS_platformIsSymlink */
-
-
-int __PHYSFS_platformIsDirectory(const char *fname)
-{
-    struct stat statbuf;
-    BAIL_IF_MACRO(stat(fname, &statbuf) == -1, strerror(errno), 0);
-    return ( (S_ISDIR(statbuf.st_mode)) ? 1 : 0 );
-} /* __PHYSFS_platformIsDirectory */
-
-
 char *__PHYSFS_platformCvtToDependent(const char *prepend,
                                       const char *dirName,
                                       const char *append)
@@ -213,6 +189,8 @@
 
         if (omitSymLinks)
         {
+            PHYSFS_Stat statbuf;
+            int exists = 0;
             char *p;
             int len = strlen(ent->d_name) + dlen + 1;
             if (len > bufsize)
@@ -225,8 +203,14 @@
             } /* if */
 
             strcpy(buf + dlen, ent->d_name);
-            if (__PHYSFS_platformIsSymLink(buf))
-                continue;
+
+            if (__PHYSFS_platformStat(buf, &exists, &statbuf))
+            {
+                if (!exists)
+                    continue;
+                else if (statbuf.filetype == PHYSFS_FILETYPE_SYMLINK)
+                    continue;
+            } /* if */
         } /* if */
 
         callback(callbackdata, origdir, ent->d_name);
--- a/src/platform_windows.c	Mon Aug 30 03:09:00 2010 -0400
+++ b/src/platform_windows.c	Sun Sep 05 02:41:13 2010 -0400
@@ -563,29 +563,6 @@
 } /* __PHYSFS_platformGetThreadID */
 
 
-static int doPlatformExists(LPWSTR wpath)
-{
-    BAIL_IF_MACRO
-    (
-        pGetFileAttributesW(wpath) == PHYSFS_INVALID_FILE_ATTRIBUTES,
-        winApiStrError(), 0
-    );
-    return 1;
-} /* doPlatformExists */
-
-
-int __PHYSFS_platformExists(const char *fname)
-{
-    int retval = 0;
-    LPWSTR wpath;
-    UTF8_TO_UNICODE_STACK_MACRO(wpath, fname);
-    BAIL_IF_MACRO(wpath == NULL, ERR_OUT_OF_MEMORY, 0);
-    retval = doPlatformExists(wpath);
-    __PHYSFS_smallFree(wpath);
-    return retval;
-} /* __PHYSFS_platformExists */
-
-
 static int isSymlinkAttrs(const DWORD attr, const DWORD tag)
 {
     return ( (attr & FILE_ATTRIBUTE_REPARSE_POINT) && 
@@ -593,51 +570,6 @@
 } /* isSymlinkAttrs */
 
 
-int __PHYSFS_platformIsSymLink(const char *fname)
-{
-    /* !!! FIXME:
-     * Windows Vista can have NTFS symlinks. Can older Windows releases have
-     *  them when talking to a network file server? What happens when you
-     *  mount a NTFS partition on XP that was plugged into a Vista install
-     *  that made a symlink?
-     */
-
-    int retval = 0;
-    LPWSTR wpath;
-    HANDLE dir;
-    WIN32_FIND_DATAW entw;
-
-    /* no unicode entry points? Probably no symlinks. */
-    BAIL_IF_MACRO(pFindFirstFileW == NULL, NULL, 0);
-
-    UTF8_TO_UNICODE_STACK_MACRO(wpath, fname);
-    BAIL_IF_MACRO(wpath == NULL, ERR_OUT_OF_MEMORY, 0);
-
-    /* !!! FIXME: filter wildcard chars? */
-    dir = pFindFirstFileW(wpath, &entw);
-    if (dir != INVALID_HANDLE_VALUE)
-    {
-        retval = isSymlinkAttrs(entw.dwFileAttributes, entw.dwReserved0);
-        FindClose(dir);
-    } /* if */
-
-    __PHYSFS_smallFree(wpath);
-    return retval;
-} /* __PHYSFS_platformIsSymlink */
-
-
-int __PHYSFS_platformIsDirectory(const char *fname)
-{
-    int retval = 0;
-    LPWSTR wpath;
-    UTF8_TO_UNICODE_STACK_MACRO(wpath, fname);
-    BAIL_IF_MACRO(wpath == NULL, ERR_OUT_OF_MEMORY, 0);
-    retval = ((pGetFileAttributesW(wpath) & FILE_ATTRIBUTE_DIRECTORY) != 0);
-    __PHYSFS_smallFree(wpath);
-    return retval;
-} /* __PHYSFS_platformIsDirectory */
-
-
 char *__PHYSFS_platformCvtToDependent(const char *prepend,
                                       const char *dirName,
                                       const char *append)
--- a/test/test_physfs.c	Mon Aug 30 03:09:00 2010 -0400
+++ b/test/test_physfs.c	Sun Sep 05 02:41:13 2010 -0400
@@ -751,6 +751,7 @@
 
 static int cmd_isdir(char *args)
 {
+    PHYSFS_Stat statbuf;
     int rc;
 
     if (*args == '\"')
@@ -759,7 +760,9 @@
         args[strlen(args) - 1] = '\0';
     } /* if */
 
-    rc = PHYSFS_isDirectory(args);
+    rc = PHYSFS_stat(args, &statbuf);
+    if (rc)
+        rc = (statbuf.filetype == PHYSFS_FILETYPE_DIRECTORY);
     printf("File %s a directory.\n", rc ? "is" : "is NOT");
     return 1;
 } /* cmd_isdir */
@@ -767,6 +770,7 @@
 
 static int cmd_issymlink(char *args)
 {
+    PHYSFS_Stat statbuf;
     int rc;
 
     if (*args == '\"')
@@ -775,7 +779,9 @@
         args[strlen(args) - 1] = '\0';
     } /* if */
 
-    rc = PHYSFS_isSymbolicLink(args);
+    rc = PHYSFS_stat(args, &statbuf);
+    if (rc)
+        rc = (statbuf.filetype == PHYSFS_FILETYPE_SYMLINK);
     printf("File %s a symlink.\n", rc ? "is" : "is NOT");
     return 1;
 } /* cmd_issymlink */