archivers/dir.c
changeset 20 efdde0d21521
parent 17 7337737f5120
child 21 b1ea58d70a56
--- 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       */
 };