libclamav/zziplib/zzip-dir.c
b151ef55
 /*
  * Author: 
  *	Guido Draheim <guidod@gmx.de>
  *
  *	Copyright (c) 1999,2000,2001,2002 Guido Draheim
  * 	    All rights reserved,
  *	    use under the restrictions of the
  *	    Lesser GNU General Public License
  *          note the additional license information 
  *          that can be found in COPYING.ZZIP
  */
 
8b242bb9
 #if HAVE_CONFIG_H
 #include "clamav-config.h"
 #endif
 
b151ef55
 #include <zzip.h>                                   /* exported... */
 #include <zzip-file.h>
8a05efc5
 #include <stddef.h> /* offsetof */
b151ef55
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
 
 #ifdef ZZIP_HAVE_SYS_STAT_H
 #include <sys/stat.h>
 #else
 #include <stdio.h>
 #endif
 
8a05efc5
 /*
 #include "__dirent.h"
 */
089fbbbb
 
b151ef55
 #ifndef offsetof
 #pragma warning had to DEFINE offsetof as it was not in stddef.h
 #define offsetof(T,M) ((unsigned)(& ((T*)0)->M))
 #endif
 
 #ifdef ZZIP_HAVE_SYS_STAT_H
 /* MSVC does have IFbitmask but not the corresponding IStests */
 # if !defined S_ISDIR && defined S_IFDIR
 # define S_ISDIR(_X_) ((_X_) & S_IFDIR)
 # endif
 # if !defined S_ISREG && defined S_IFREG
 # define S_ISREG(_X_) ((_X_) & S_IFREG)
 # endif
 #endif
 
 /** 
  * This function is the equivalent of a => rewinddir(2) for a realdir or
  * the zipfile in place of a directory. The ZZIP_DIR handle returned from
  * => zzip_opendir has a flag saying realdir or zipfile. As for a zipfile,
  * the filenames will include the filesubpath, so take care.
  */
 void 
 zzip_rewinddir(ZZIP_DIR * dir)
 {
     if (! dir) return;
 
089fbbbb
     /*
b151ef55
     if (USE_DIRENT && dir->realdir) 
     {
         _zzip_rewinddir(dir->realdir);
         return;
     }
089fbbbb
     */
b151ef55
 
     if (dir->hdr0)
         dir->hdr = dir->hdr0;
     else
         dir->hdr = 0;
 }
 
 #if ! USE_DIRENT
 #define real_readdir(_X_) 1
 #else
 static int
 real_readdir(ZZIP_DIR* dir)
 {
     struct stat st = { 0 };
     char filename[PATH_MAX];
     struct dirent* dirent = _zzip_readdir(dir->realdir);
     if (! dirent) return 0;
 
     dir->dirent.d_name = dirent->d_name;
7cc3891c
     strcpy(filename, dir->realname);
     strcat(filename, "/");
     strcat(filename, dirent->d_name);
b151ef55
 
     if (stat(filename, &st) == -1)
         return -1;
 
     dir->dirent.d_csize = dir->dirent.st_size = st.st_size;
510c466b
     dir->dirent.d_flags = 0;
b151ef55
 
     if (st.st_mode)
     {
         if (! S_ISREG(st.st_mode))
         {
             dir->dirent.d_compr = st.st_mode;
             dir->dirent.d_compr |= 0x80000000; 
 	    /* makes it effectively negative, 
 	     * but can still be fed to S_ISXXX(x) */
         }else
         {
             dir->dirent.d_compr = 0; /* stored */
         }
     }else
     {
             dir->dirent.d_compr = 0; /* stored */
     }
 
     return 1;
 }
 #endif
 
 /**
  * This function is the equivalent of a => readdir(2) for a realdir 
  * or a zipfile referenced by the ZZIP_DIR returned from => zzip_opendir.
  *
  * The ZZIP_DIR handle (as returned by => zzip_opendir) contains a few more 
  * entries than being copied into the ZZIP_DIRENT. The only valid fields in
  * a ZZIP_DIRENT are d_name (the file name), d_compr (compression), d_csize
  * (compressed size), st_size (uncompressed size).
  */
 ZZIP_DIRENT* 
 zzip_readdir(ZZIP_DIR * dir)
 {
     if (! dir) { errno=EBADF; return 0; }
 
089fbbbb
     /*
b151ef55
     if (USE_DIRENT && dir->realdir)
     {
         if (! real_readdir(dir))
             return 0;
089fbbbb
     }else */
b151ef55
     {
         if (! dir->hdr) return 0;
 
         dir->dirent.d_name  = dir->hdr->d_name;
         dir->dirent.d_compr = dir->hdr->d_compr;
 
         dir->dirent.d_csize = dir->hdr->d_csize;
         dir->dirent.st_size = dir->hdr->d_usize;
 
510c466b
 	dir->dirent.d_flags = dir->hdr->d_flags;
 
b151ef55
         if (! dir->hdr->d_reclen) dir->hdr = 0;
         else  dir->hdr = (struct zzip_dir_hdr *)
 		  ((char *)dir->hdr + dir->hdr->d_reclen);
     }
     return &dir->dirent;
 }
 
 /** => zzip_rewinddir
  * This function is the equivalent of => telldir(2) for a realdir or zipfile.
  */
 zzip_off_t 
 zzip_telldir(ZZIP_DIR* dir)
 {
     if (! dir) { errno=EBADF; return -1; }
 
089fbbbb
     /* if (USE_DIRENT && dir->realdir)
b151ef55
     {
         return _zzip_telldir(dir->realdir);
089fbbbb
     }else*/
b151ef55
     {
     	return ((zzip_off_t) ((char*) dir->hdr - (char*) dir->hdr0));
     }
 }
 
 /** => zzip_rewinddir
  * This function is the equivalent of => seekdir(2) for a realdir or zipfile.
  */
 void
 zzip_seekdir(ZZIP_DIR* dir, zzip_off_t offset)
 {
     if (! dir) return; 
     
089fbbbb
     /*if (USE_DIRENT && dir->realdir)
b151ef55
     {
         _zzip_seekdir(dir->realdir, offset);
089fbbbb
     }else*/
b151ef55
     {
 	dir->hdr = (struct zzip_dir_hdr*) 
 	    (dir->hdr0 ? (char*) dir->hdr0 + (size_t) offset : 0);
     }
 }
 
 #if defined ZZIP_LARGEFILE_RENAME && defined EOVERFLOW && defined PIC
 #undef zzip_seekdir /* zzip_seekdir64 */
 #undef zzip_telldir /* zzip_telldir64 */
 
 long   zzip_telldir(ZZIP_DIR* dir) 
 { 
     off_t off = zzip_telldir64 (dir); 
     long offs = off;
     if (offs != off) { errno = EOVERFLOW; return -1; }
     return offs;
 }
 
 void   zzip_seekdir(ZZIP_DIR* dir, long offset) 
 { 
     zzip_seekdir64 (dir, offset); 
 }
 #endif
 
 /**
  * This function is the equivalent of => opendir(3) for a realdir or zipfile.
  * <p>
  * This function has some magic - if the given argument-path
  * is a directory, it will wrap a real => opendir(3) into the ZZIP_DIR
  * structure. Otherwise it will divert to => zzip_dir_open which 
  * can also attach a ".zip" extension if needed to find the archive.
  * <p>
  * the error-code is mapped to => errno(3).
  */
 ZZIP_DIR* 
 zzip_opendir(zzip_char_t* filename)
 {
     return zzip_opendir_ext_io (filename, 0, 0, 0);
 }
 
 /** => zzip_opendir
  * This function uses explicit ext and io instead of the internal 
  * defaults, setting them to zero is equivalent to => zzip_opendir
  */
 ZZIP_DIR* 
 zzip_opendir_ext_io(zzip_char_t* filename, int o_modes,
 		    zzip_strings_t* ext, zzip_plugin_io_t io)
 {
     zzip_error_t e;
     ZZIP_DIR* dir;
 
 #  ifdef ZZIP_HAVE_SYS_STAT_H
     struct stat st;
 #  endif
 
     if (o_modes & (ZZIP_PREFERZIP|ZZIP_ONLYZIP)) goto try_zzip;
  try_real:
 
 #  ifdef ZZIP_HAVE_SYS_STAT_H
     if (stat(filename, &st) >= 0 && S_ISDIR(st.st_mode)
     ){
089fbbbb
       	/* if (USE_DIRENT)
 	{
 	    _zzip_DIR* realdir = _zzip_opendir(filename);
 	    if (realdir)
 	    {
 		if (! (dir = (ZZIP_DIR *)calloc(1, sizeof (*dir))))
 		{ 
 		    _zzip_closedir(realdir); 
 		    return 0; 
 		}else
 		{ 
 		    dir->realdir = realdir; 
 		    dir->realname = strdup(filename);
 		    return dir; 
 		}
 	    }
         } */
b151ef55
         return 0;
     }
 #  endif /* HAVE_SYS_STAT_H */
 
  try_zzip:
     dir = zzip_dir_open_ext_io (filename, &e, ext, io);
     if (! dir && (o_modes & ZZIP_PREFERZIP)) goto try_real;
     if (e) errno = zzip_errno(e); 
     return dir;
 }
 
 /**
  * This function is the equivalent of => closedir(3) for a realdir or zipfile.
  * <p>
  * This function is magic - if the given arg-ZZIP_DIR
  * is a real directory, it will call the real => closedir(3) and then
  * free the wrapping ZZIP_DIR structure. Otherwise it will divert 
  * to => zzip_dir_close which will free the ZZIP_DIR structure.
  */
 int
 zzip_closedir(ZZIP_DIR* dir)
 {
     if (! dir) { errno = EBADF; return -1; }
 
089fbbbb
     /*if (USE_DIRENT && dir->realdir)
b151ef55
     {
         _zzip_closedir(dir->realdir);
         free(dir->realname);
         free(dir);
         return 0;
089fbbbb
     }else*/
b151ef55
     {
         zzip_dir_close(dir);
         return 0;
     }
 }
 
 /* 
  * Local variables:
  * c-file-style: "stroustrup"
  * End:
  */