archivers/zip.c
changeset 53 6c3c990f006e
parent 52 bbb26eacc532
child 55 986740ba58ab
equal deleted inserted replaced
52:bbb26eacc532 53:6c3c990f006e
     6  *  This file written by Ryan C. Gordon.
     6  *  This file written by Ryan C. Gordon.
     7  */
     7  */
     8 
     8 
     9 /*
     9 /*
    10  * !!! FIXME: overall design bugs.
    10  * !!! FIXME: overall design bugs.
    11  *
       
    12  *  It'd be nice if we could remove the thread issues: I/O to individual
       
    13  *   files inside an archive are safe, but the searches over the central
       
    14  *   directory and the ZIP_openRead() call are race conditions. Basically,
       
    15  *   we need to hack something like openDir() into unzip.c, so that directory
       
    16  *   reads are separated by handles, and maybe add a openFileByName() call,
       
    17  *   or make unzOpenCurrentFile() take a handle, too.
       
    18  *
    11  *
    19  *  Make unz_file_info.version into two fields of unsigned char. That's what
    12  *  Make unz_file_info.version into two fields of unsigned char. That's what
    20  *   they are in the zipfile; heavens knows why unzip.c casts it...this causes
    13  *   they are in the zipfile; heavens knows why unzip.c casts it...this causes
    21  *   a byte ordering headache for me in entry_is_symlink().
    14  *   a byte ordering headache for me in entry_is_symlink().
    22  *
    15  *
    42 
    35 
    43 #define MAXZIPENTRYSIZE 256
    36 #define MAXZIPENTRYSIZE 256
    44 
    37 
    45 typedef struct
    38 typedef struct
    46 {
    39 {
    47     unzFile handle;
    40     char *name;
    48     uLong totalEntries;
    41     unz_file_info info;
       
    42     char *symlink;
       
    43 } ZIPentry;
       
    44 
       
    45 typedef struct
       
    46 {
    49     char *archiveName;
    47     char *archiveName;
       
    48     unz_global_info global;
       
    49     ZIPentry *entries;
    50 } ZIPinfo;
    50 } ZIPinfo;
    51 
    51 
    52 typedef struct
    52 typedef struct
    53 {
    53 {
    54     unzFile handle;
    54     unzFile handle;
    55 } ZIPfileinfo;
    55 } ZIPfileinfo;
    56 
    56 
    57 
    57 
    58 extern const DirFunctions __PHYSFS_DirFunctions_ZIP;
    58 extern const DirFunctions __PHYSFS_DirFunctions_ZIP;
    59 static const FileFunctions __PHYSFS_FileFunctions_ZIP;
    59 static const FileFunctions __PHYSFS_FileFunctions_ZIP;
       
    60 
       
    61 
       
    62 /* Number of symlinks to follow before we assume it's a recursive link... */
       
    63 #define SYMLINK_RECURSE_COUNT 20
    60 
    64 
    61 
    65 
    62 static int ZIP_read(FileHandle *handle, void *buffer,
    66 static int ZIP_read(FileHandle *handle, void *buffer,
    63                     unsigned int objSize, unsigned int objCount)
    67                     unsigned int objSize, unsigned int objCount)
    64 {
    68 {
   163 
   167 
   164     return(retval);
   168     return(retval);
   165 } /* ZIP_isArchive */
   169 } /* ZIP_isArchive */
   166 
   170 
   167 
   171 
   168 static DirHandle *ZIP_openArchive(const char *name, int forWriting)
   172 static void freeEntries(ZIPinfo *info, int count, const char *errmsg)
   169 {
   173 {
   170     unzFile unz = NULL;
   174     int i;
   171     DirHandle *retval = NULL;
   175 
   172     unz_global_info global;
   176     for (i = 0; i < count; i++)
   173 
   177     {
   174     BAIL_IF_MACRO(forWriting, ERR_ARC_IS_READ_ONLY, NULL);
   178         free(info->entries[i].name);
   175 
   179         if (info->entries[i].symlink != NULL)
   176     errno = 0;
   180             free(info->entries[i].symlink);
   177     BAIL_IF_MACRO(access(name, R_OK) != 0, strerror(errno), NULL);
   181     } /* for */
   178 
   182 
   179     retval = malloc(sizeof (DirHandle));
   183     free(info->entries);
       
   184 
       
   185     if (errmsg != NULL)
       
   186         __PHYSFS_setError(errmsg);
       
   187 } /* freeEntries */
       
   188 
       
   189 
       
   190 static char *ZIP_realpath(unzFile fh, unz_file_info *info)
       
   191 {
       
   192     char *retval = NULL;
       
   193     int size;
       
   194 
       
   195     BAIL_IF_MACRO(unzOpenCurrentFile(fh) != UNZ_OK, ERR_IO_ERROR, NULL);
       
   196     size = info->uncompressed_size;
       
   197     retval = (char *) malloc(size + 1);
   180     BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
   198     BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
   181 
   199     if (unzReadCurrentFile(fh, retval, size) != size)
   182     unz = unzOpen(name);
   200     {
   183     if ((unz == NULL) || (unzGetGlobalInfo(unz, &global) != UNZ_OK))
       
   184     {
       
   185         if (unz)
       
   186             unzClose(unz);
       
   187         free(retval);
   201         free(retval);
   188         BAIL_IF_MACRO(1, ERR_UNSUPPORTED_ARCHIVE, NULL);
   202         __PHYSFS_setError(ERR_IO_ERROR);
   189     } /* if */
   203         retval = NULL;
   190 
   204     } /* if */
   191     retval->opaque = malloc(sizeof (ZIPinfo));
   205     retval[size] = '\0';
   192     if (retval->opaque == NULL)
   206     unzCloseCurrentFile(fh);
   193     {
   207 
   194         free(retval);
   208     return(retval);
   195         unzClose(unz);
   209 } /* ZIP_realpath */
   196         BAIL_IF_MACRO(1, ERR_OUT_OF_MEMORY, NULL);
       
   197     } /* if */
       
   198 
       
   199     ((ZIPinfo *) (retval->opaque))->archiveName = malloc(strlen(name) + 1);
       
   200     if (((ZIPinfo *) (retval->opaque))->archiveName == NULL)
       
   201     {
       
   202         free(retval->opaque);
       
   203         free(retval);
       
   204         unzClose(unz);
       
   205         BAIL_IF_MACRO(1, ERR_OUT_OF_MEMORY, NULL);
       
   206     } /* if */
       
   207 
       
   208     ((ZIPinfo *) (retval->opaque))->handle = unz;
       
   209     ((ZIPinfo *) (retval->opaque))->totalEntries = global.number_entry;
       
   210     strcpy(((ZIPinfo *) (retval->opaque))->archiveName, name);
       
   211     retval->funcs = &__PHYSFS_DirFunctions_ZIP;
       
   212 
       
   213     return(retval);
       
   214 } /* ZIP_openArchive */
       
   215 
   210 
   216 
   211 
   217 /* "uLong" is defined by zlib and/or unzip.h ... */
   212 /* "uLong" is defined by zlib and/or unzip.h ... */
   218 typedef union
   213 typedef union
   219 {
   214 {
   257               (info->external_fa & 0x0120000)  /* symlink flag. */
   252               (info->external_fa & 0x0120000)  /* symlink flag. */
   258            );
   253            );
   259 } /* entry_is_symlink */
   254 } /* entry_is_symlink */
   260 
   255 
   261 
   256 
   262 static char *ZIP_realpath(unzFile fh, unz_file_info *info)
   257 static int loadZipEntries(ZIPinfo *info, unzFile unz)
   263 {
   258 {
   264     char *retval = NULL;
   259     int i, max;
   265     int size;
   260 
   266 
   261     BAIL_IF_MACRO(unzGetGlobalInfo(unz, &(info->global)) != UNZ_OK,
   267     if (entry_is_symlink(info))
   262                     ERR_IO_ERROR, 0);
   268     {
   263     BAIL_IF_MACRO(unzGoToFirstFile(unz) != UNZ_OK, ERR_IO_ERROR, 0);
   269         BAIL_IF_MACRO(unzOpenCurrentFile(fh) != UNZ_OK, ERR_IO_ERROR, NULL);
   264 
   270         size = info->uncompressed_size;
   265     max = info->global.number_entry;
   271         retval = (char *) malloc(size + 1);
   266     info->entries = (ZIPentry *) malloc(sizeof (ZIPentry) * max);
   272         BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
   267     BAIL_IF_MACRO(info->entries == NULL, ERR_OUT_OF_MEMORY, 0);
   273         if (unzReadCurrentFile(fh, retval, size) != size)
   268 
   274         {
   269     for (i = 0; i < max; i++)
   275             free(retval);
   270     {
   276             __PHYSFS_setError(ERR_IO_ERROR);
   271         unz_file_info *d = &((info->entries[i]).info);
   277             retval = NULL;
   272         if (unzGetCurrentFileInfo(unz, d, NULL, 0, NULL, 0, NULL, 0) != UNZ_OK)
   278         } /* if */
   273         {
   279         retval[size] = '\0';
   274             freeEntries(info, i, ERR_IO_ERROR);
   280         unzCloseCurrentFile(fh);
   275             return(0);
   281     } /* if */
   276         } /* if */
   282 
   277 
   283     return(retval);
   278         (info->entries[i]).name = (char *) malloc(d->size_filename + 1);
   284 } /* ZIP_realpath */
   279         if ((info->entries[i]).name == NULL)
       
   280         {
       
   281             freeEntries(info, i, ERR_OUT_OF_MEMORY);
       
   282             return(0);
       
   283         } /* if */
       
   284 
       
   285         info->entries[i].symlink = NULL;
       
   286 
       
   287         if (unzGetCurrentFileInfo(unz, NULL, (info->entries[i]).name,
       
   288                                   d->size_filename + 1, NULL, 0,
       
   289                                   NULL, 0) != UNZ_OK)
       
   290         {
       
   291             freeEntries(info, i + 1, ERR_IO_ERROR);
       
   292             return(0);
       
   293         } /* if */
       
   294 
       
   295         if (entry_is_symlink(d))
       
   296         {
       
   297             info->entries[i].symlink = ZIP_realpath(unz, d);
       
   298             if (info->entries[i].symlink == NULL)
       
   299             {
       
   300                 freeEntries(info, i + 1, NULL);
       
   301                 return(0);
       
   302             } /* if */
       
   303         } /* if */
       
   304 
       
   305         if ((unzGoToNextFile(unz) != UNZ_OK) && (i + 1 < max))
       
   306         {
       
   307             freeEntries(info, i + 1, ERR_IO_ERROR);
       
   308             return(0);
       
   309         } /* if */
       
   310     } /* for */
       
   311 
       
   312     return(1);
       
   313 } /* loadZipEntries */
       
   314 
       
   315 
       
   316 static DirHandle *ZIP_openArchive(const char *name, int forWriting)
       
   317 {
       
   318     unzFile unz = NULL;
       
   319     DirHandle *retval = NULL;
       
   320 
       
   321     BAIL_IF_MACRO(forWriting, ERR_ARC_IS_READ_ONLY, NULL);
       
   322 
       
   323     retval = malloc(sizeof (DirHandle));
       
   324     BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
       
   325 
       
   326     unz = unzOpen(name);
       
   327     if (unz == NULL)
       
   328     {
       
   329         free(retval);
       
   330         BAIL_IF_MACRO(1, ERR_UNSUPPORTED_ARCHIVE, NULL);
       
   331     } /* if */
       
   332 
       
   333     retval->opaque = malloc(sizeof (ZIPinfo));
       
   334     if (retval->opaque == NULL)
       
   335     {
       
   336         free(retval);
       
   337         unzClose(unz);
       
   338         BAIL_IF_MACRO(1, ERR_OUT_OF_MEMORY, NULL);
       
   339     } /* if */
       
   340 
       
   341     ((ZIPinfo *) (retval->opaque))->archiveName = malloc(strlen(name) + 1);
       
   342     if ( (((ZIPinfo *) (retval->opaque))->archiveName == NULL) ||
       
   343          (!loadZipEntries( (ZIPinfo *) (retval->opaque), unz)) )
       
   344     {
       
   345         if (((ZIPinfo *) (retval->opaque))->archiveName != NULL)
       
   346             free(((ZIPinfo *) (retval->opaque))->archiveName);
       
   347         free(retval->opaque);
       
   348         free(retval);
       
   349         unzClose(unz);
       
   350         BAIL_IF_MACRO(1, ERR_OUT_OF_MEMORY, NULL);
       
   351     } /* if */
       
   352 
       
   353     unzClose(unz);
       
   354     strcpy(((ZIPinfo *) (retval->opaque))->archiveName, name);
       
   355     retval->funcs = &__PHYSFS_DirFunctions_ZIP;
       
   356 
       
   357     return(retval);
       
   358 } /* ZIP_openArchive */
   285 
   359 
   286 
   360 
   287 /* !!! This is seriously ugly. */
   361 /* !!! This is seriously ugly. */
   288 static LinkedStringList *ZIP_enumerateFiles(DirHandle *h,
   362 static LinkedStringList *ZIP_enumerateFiles(DirHandle *h,
   289                                             const char *dirname,
   363                                             const char *dirname,
   290                                             int omitSymLinks)
   364                                             int omitSymLinks)
   291 {
   365 {
   292     ZIPinfo *zi = (ZIPinfo *) (h->opaque);
   366     ZIPinfo *zi = (ZIPinfo *) (h->opaque);
   293     unzFile fh = zi->handle;
       
   294     int i;
   367     int i;
   295     int dlen;
   368     int dlen;
   296     LinkedStringList *retval = NULL;
   369     LinkedStringList *retval = NULL;
   297     LinkedStringList *l = NULL;
   370     LinkedStringList *l = NULL;
   298     LinkedStringList *prev = NULL;
   371     LinkedStringList *prev = NULL;
       
   372     char *d;
       
   373     ZIPentry *entry;
   299     char buf[MAXZIPENTRYSIZE];
   374     char buf[MAXZIPENTRYSIZE];
   300     char *d;
   375 
   301     unz_file_info info;
       
   302 
       
   303         /* jump to first file entry... */
       
   304     BAIL_IF_MACRO(unzGoToFirstFile(fh) != UNZ_OK, ERR_IO_ERROR, NULL);
       
   305     dlen = strlen(dirname);
   376     dlen = strlen(dirname);
   306     d = malloc(dlen + 1);
   377     d = malloc(dlen + 1);
   307     BAIL_IF_MACRO(d == NULL, ERR_OUT_OF_MEMORY, NULL);
   378     BAIL_IF_MACRO(d == NULL, ERR_OUT_OF_MEMORY, NULL);
   308     strcpy(d, dirname);
   379     strcpy(d, dirname);
   309     if ((dlen > 0) && (d[dlen - 1] == '/'))   /* no trailing slash. */
   380     if ((dlen > 0) && (d[dlen - 1] == '/'))   /* no trailing slash. */
   310     {
   381     {
   311         dlen--;
   382         dlen--;
   312         d[dlen] = '\0';
   383         d[dlen] = '\0';
   313     } /* if */
   384     } /* if */
   314 
   385 
   315     for (i = 0; i < zi->totalEntries; i++, unzGoToNextFile(fh))
   386     for (i = 0, entry = zi->entries; i < zi->global.number_entry; i++, entry++)
   316     {
   387     {
   317         char *ptr;
   388         char *ptr;
   318         char *add_file;
   389         char *add_file;
   319         int this_dlen;
   390         int this_dlen;
   320 
   391 
   321         unzGetCurrentFileInfo(fh, &info, buf, sizeof (buf), NULL, 0, NULL, 0);
   392         if ((omitSymLinks) && (entry->symlink != NULL))
   322 
       
   323         if ((omitSymLinks) && (entry_is_symlink(&info)))
       
   324             continue;
   393             continue;
   325 
   394 
   326         buf[sizeof (buf) - 1] = '\0';  /* safety. */
   395         this_dlen = strlen(entry->name);
   327         this_dlen = strlen(buf);
   396         if (this_dlen + 1 > MAXZIPENTRYSIZE)
       
   397             continue;  /* ugh. */
       
   398 
       
   399         strcpy(buf, entry->name);
       
   400 
   328         if ((this_dlen > 0) && (buf[this_dlen - 1] == '/'))   /* no trailing slash. */
   401         if ((this_dlen > 0) && (buf[this_dlen - 1] == '/'))   /* no trailing slash. */
   329         {
   402         {
   330             this_dlen--;
   403             this_dlen--;
   331             buf[this_dlen] = '\0';
   404             buf[this_dlen] = '\0';
   332         } /* if */
   405         } /* if */
   394 /* !!! This is seriously ugly. */
   467 /* !!! This is seriously ugly. */
   395 static int ZIP_exists_symcheck(DirHandle *h, const char *name, int follow)
   468 static int ZIP_exists_symcheck(DirHandle *h, const char *name, int follow)
   396 {
   469 {
   397     char buf[MAXZIPENTRYSIZE];
   470     char buf[MAXZIPENTRYSIZE];
   398     ZIPinfo *zi = (ZIPinfo *) (h->opaque);
   471     ZIPinfo *zi = (ZIPinfo *) (h->opaque);
   399     unzFile fh = zi->handle;
       
   400     int dlen;
   472     int dlen;
   401     char *d;
   473     char *d;
   402     int i;
   474     int i;
   403     unz_file_info info;
   475     ZIPentry *entry;
   404 
   476 
   405     BAIL_IF_MACRO(unzGoToFirstFile(fh) != UNZ_OK, ERR_IO_ERROR, 0);
       
   406     dlen = strlen(name);
   477     dlen = strlen(name);
   407     d = malloc(dlen + 1);
   478     d = malloc(dlen + 1);
   408     BAIL_IF_MACRO(d == NULL, ERR_OUT_OF_MEMORY, 0);
   479     BAIL_IF_MACRO(d == NULL, ERR_OUT_OF_MEMORY, -1);
   409     strcpy(d, name);
   480     strcpy(d, name);
   410     if ((dlen > 0) && (d[dlen - 1] == '/'))   /* no trailing slash. */
   481     if ((dlen > 0) && (d[dlen - 1] == '/'))   /* no trailing slash. */
   411     {
   482     {
   412         dlen--;
   483         dlen--;
   413         d[dlen] = '\0';
   484         d[dlen] = '\0';
   414     } /* if */
   485     } /* if */
   415 
   486 
   416     for (i = 0; i < zi->totalEntries; i++, unzGoToNextFile(fh))
   487     for (i = 0, entry = zi->entries; i < zi->global.number_entry; i++, entry++)
   417     {
   488     {
   418         int this_dlen;
   489         int this_dlen = strlen(entry->name);
   419         unzGetCurrentFileInfo(fh, &info, buf, sizeof (buf), NULL, 0, NULL, 0);
   490         if (this_dlen + 1 > MAXZIPENTRYSIZE)
   420         buf[sizeof (buf) - 1] = '\0';  /* safety. */
   491             continue;  /* ugh. */
   421         this_dlen = strlen(buf);
   492 
       
   493         strcpy(buf, entry->name);
   422         if ((this_dlen > 0) && (buf[this_dlen - 1] == '/'))   /* no trailing slash. */
   494         if ((this_dlen > 0) && (buf[this_dlen - 1] == '/'))   /* no trailing slash. */
   423         {
   495         {
   424             this_dlen--;
   496             this_dlen--;
   425             buf[this_dlen] = '\0';
   497             buf[this_dlen] = '\0';
   426         } /* if */
   498         } /* if */
   427 
   499 
   428         if ( ((buf[dlen] == '/') || (buf[dlen] == '\0')) &&
   500         if ( ((buf[dlen] == '/') || (buf[dlen] == '\0')) &&
   429              (strncmp(d, buf, dlen) == 0) )
   501              (strncmp(d, buf, dlen) == 0) )
   430         {
   502         {
   431             int retval = 1;
   503             int retval = i;
   432             free(d);
   504             free(d);
   433             if (follow)  /* follow symlinks? */
   505             if (follow)  /* follow symlinks? */
   434             {
   506             {
   435                 char *real = ZIP_realpath(fh, &info);
   507                 if (entry->symlink != NULL)
   436                 if (real != NULL)
   508                     retval = ZIP_exists_symcheck(h, entry->symlink, follow-1);
   437                 {
       
   438                     retval = ZIP_exists_symcheck(h, real, follow - 1);
       
   439                     free(real);
       
   440                 } /* if */
       
   441             } /* if */
   509             } /* if */
   442             return(retval);
   510             return(retval);
   443         } /* if */
   511         } /* if */
   444     } /* for */
   512     } /* for */
   445 
   513 
   446     free(d);
   514     free(d);
   447     return(0);
   515     return(-1);
   448 } /* ZIP_exists_symcheck */
   516 } /* ZIP_exists_symcheck */
   449 
   517 
   450 
   518 
   451 static int ZIP_exists_nofollow(DirHandle *h, const char *name)
   519 static int ZIP_exists_nofollow(DirHandle *h, const char *name)
   452 {
   520 {
   454 } /* ZIP_exists_nofollow */
   522 } /* ZIP_exists_nofollow */
   455 
   523 
   456 
   524 
   457 static int ZIP_exists(DirHandle *h, const char *name)
   525 static int ZIP_exists(DirHandle *h, const char *name)
   458 {
   526 {
   459     /* follow at most 20 links to prevent recursion... */
   527     int retval = ZIP_exists_symcheck(h, name, SYMLINK_RECURSE_COUNT);
   460     int retval = ZIP_exists_symcheck(h, name, 20);
   528     int is_sym;
   461     unz_file_info info;
   529 
   462     unzFile fh = ((ZIPinfo *) (h->opaque))->handle;
   530     if (retval == -1)
   463 
   531         return(0);
   464     if (retval)
   532 
   465     {
   533     /* if it's a symlink, then we ran into a possible symlink loop. */
   466         /* current zip entry will be the file in question. */
   534     is_sym = ( ((ZIPinfo *)(h->opaque))->entries[retval].symlink != NULL );
   467         unzGetCurrentFileInfo(fh, &info, NULL, 0, NULL, 0, NULL, 0);
   535     BAIL_IF_MACRO(is_sym, ERR_TOO_MANY_SYMLINKS, 0);
   468 
   536 
   469         /* if it's a symlink, then we ran into a possible symlink loop. */
   537     return(1);
   470         BAIL_IF_MACRO(entry_is_symlink(&info), ERR_TOO_MANY_SYMLINKS, 0);
       
   471     } /* if */
       
   472 
       
   473     return(retval);
       
   474 } /* ZIP_exists */
   538 } /* ZIP_exists */
   475 
   539 
   476 
   540 
   477 static int ZIP_isDirectory(DirHandle *h, const char *name)
   541 static int ZIP_isDirectory(DirHandle *h, const char *name)
   478 {
   542 {
   479     char buf[MAXZIPENTRYSIZE];
   543     int dlen;
   480     unzFile fh = ((ZIPinfo *) (h->opaque))->handle;
   544     int is_sym;
   481     int retval = ZIP_exists(h, name);
   545     int retval = ZIP_exists_symcheck(h, name, SYMLINK_RECURSE_COUNT);
   482     int dlen = strlen(name);
   546 
   483 
   547     if (retval == -1)
   484     if (retval)
   548         return(0);
   485     {
   549 
   486         /* current zip entry will be the file in question. */
   550     /* if it's a symlink, then we ran into a possible symlink loop. */
   487         unzGetCurrentFileInfo(fh, NULL, buf, sizeof (buf), NULL, 0, NULL, 0);
   551     is_sym = ( ((ZIPinfo *)(h->opaque))->entries[retval].symlink != NULL );
   488         retval = (buf[dlen] == '/');  /* !!! yikes. */
   552     BAIL_IF_MACRO(is_sym, ERR_TOO_MANY_SYMLINKS, 0);
   489     } /* if */
   553 
   490 
   554     dlen = strlen(name);
       
   555     /* !!! yikes. Better way to check? */
       
   556     retval = (((ZIPinfo *)(h->opaque))->entries[retval].name[dlen] == '/');
   491     return(retval);
   557     return(retval);
   492 } /* ZIP_isDirectory */
   558 } /* ZIP_isDirectory */
   493 
   559 
   494 
   560 
   495 static int ZIP_isSymLink(DirHandle *h, const char *name)
   561 static int ZIP_isSymLink(DirHandle *h, const char *name)
   496 {
   562 {
   497     unzFile fh = ((ZIPinfo *) (h->opaque))->handle;
       
   498     int retval = ZIP_exists_nofollow(h, name);
   563     int retval = ZIP_exists_nofollow(h, name);
   499     unz_file_info info;
   564     if (retval == -1)
   500 
   565         return(0);
   501     if (retval)
   566 
   502     {
   567     retval = ( ((ZIPinfo *)(h->opaque))->entries[retval].symlink != NULL );
   503         /* current zip entry will be the file in question. */
       
   504         unzGetCurrentFileInfo(fh, &info, NULL, 0, NULL, 0, NULL, 0);
       
   505         retval = entry_is_symlink(&info);
       
   506     } /* if */
       
   507 
       
   508     return(retval);
   568     return(retval);
   509 } /* ZIP_isSymLink */
   569 } /* ZIP_isSymLink */
   510 
   570 
   511 
   571 
   512 static FileHandle *ZIP_openRead(DirHandle *h, const char *filename)
   572 static FileHandle *ZIP_openRead(DirHandle *h, const char *filename)
   513 {
   573 {
   514     FileHandle *retval = NULL;
   574     FileHandle *retval = NULL;
       
   575     ZIPinfo *zi = ((ZIPinfo *) (h->opaque));
   515     ZIPfileinfo *finfo = NULL;
   576     ZIPfileinfo *finfo = NULL;
   516     char *name = ((ZIPinfo *) (h->opaque))->archiveName;
       
   517     unzFile f;
   577     unzFile f;
   518 
   578 
   519     BAIL_IF_MACRO(!ZIP_exists(h, filename), ERR_NO_SUCH_FILE, NULL);
   579     BAIL_IF_MACRO(!ZIP_exists(h, filename), ERR_NO_SUCH_FILE, NULL);
   520 
   580 
   521     f = unzOpen(name);
   581     f = unzOpen(zi->archiveName);
   522     BAIL_IF_MACRO(f == NULL, ERR_IO_ERROR, NULL);
   582     BAIL_IF_MACRO(f == NULL, ERR_IO_ERROR, NULL);
   523 
   583 
   524     if ( (unzLocateFile(f, filename, 2) != UNZ_OK) ||
   584     if ( (unzLocateFile(f, filename, 2) != UNZ_OK) ||
   525          (unzOpenCurrentFile(f) != UNZ_OK) ||
   585          (unzOpenCurrentFile(f) != UNZ_OK) ||
   526          ( (finfo = (ZIPfileinfo *) malloc(sizeof (ZIPfileinfo))) == NULL ) )
   586          ( (finfo = (ZIPfileinfo *) malloc(sizeof (ZIPfileinfo))) == NULL ) )
   546 } /* ZIP_openRead */
   606 } /* ZIP_openRead */
   547 
   607 
   548 
   608 
   549 static void ZIP_dirClose(DirHandle *h)
   609 static void ZIP_dirClose(DirHandle *h)
   550 {
   610 {
   551     unzClose(((ZIPinfo *) (h->opaque))->handle);
   611     ZIPinfo *zi = (ZIPinfo *) (h->opaque);
   552     free(h->opaque);
   612     freeEntries(zi, zi->global.number_entry, NULL);
       
   613     free(zi->archiveName);
       
   614     free(zi);
   553     free(h);
   615     free(h);
   554 } /* ZIP_dirClose */
   616 } /* ZIP_dirClose */
   555 
   617 
   556 
   618 
   557 static const FileFunctions __PHYSFS_FileFunctions_ZIP =
   619 static const FileFunctions __PHYSFS_FileFunctions_ZIP =