Files
commandergenius/project/jni/zzip/zzip/dir.c
T
2010-11-29 12:44:44 +02:00

335 lines
7.9 KiB
C

/*
* Author:
* Guido Draheim <guidod@gmx.de>
*
* Copyright (c) 1999,2000,2001,2002,2003 Guido Draheim
* All rights reserved,
* use under the restrictions of the
* Lesser GNU General Public License
* or alternatively the restrictions
* of the Mozilla Public License 1.1
*/
#include <zzip/lib.h> /* exported... */
#include <zzip/file.h>
#include <stddef.h> /*offsetof */
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#ifdef ZZIP_HAVE_SYS_STAT_H
#include <sys/stat.h>
#else
#include <stdio.h>
#endif
#include <zzip/__dirent.h>
#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;
if (USE_DIRENT && dir->realdir)
{
_zzip_rewinddir(dir->realdir);
return;
}
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;
strcpy(filename, dir->realname);
strcat(filename, "/");
strcat(filename, dirent->d_name);
if (stat(filename, &st) == -1)
return -1;
dir->dirent.d_csize = dir->dirent.st_size = st.st_size;
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; }
if (USE_DIRENT && dir->realdir)
{
if (! real_readdir(dir))
return 0;
} else
{
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;
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.
*/
#ifndef ANDROID
zzip_off_t
zzip_telldir(ZZIP_DIR * dir)
{
if (! dir)
{ errno=EBADF; return -1; }
if (USE_DIRENT && dir->realdir)
{
return _zzip_telldir(dir->realdir);
} else
{
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;
if (USE_DIRENT && dir->realdir)
{
_zzip_seekdir(dir->realdir, offset);
} else
{
dir->hdr = (struct zzip_dir_hdr *)
(dir->hdr0 ? (char *) dir->hdr0 + (size_t) offset : 0);
}
}
#ifndef EOVERFLOW
#define EOVERFLOW EFBIG
#endif
/** => zzip_rewinddir
* This function is provided for users who can not use any largefile-mode.
*/
long
zzip_telldir32(ZZIP_DIR * dir)
{
if (sizeof(zzip_off_t) == sizeof(long))
{
return zzip_telldir(dir);
} else
{
off_t off = zzip_telldir(dir);
if (off >= 0) {
register long off32 = off;
if (off32 == off) return off32;
errno = EOVERFLOW;
}
return -1;
}
}
/** => zzip_rewinddir
* This function is provided for users who can not use any largefile-mode.
*/
void
zzip_seekdir32(ZZIP_DIR * dir, long offset)
{
zzip_seekdir(dir, offset);
}
#endif
#if defined ZZIP_LARGEFILE_RENAME && defined EOVERFLOW && defined PIC
#undef zzip_seekdir /* zzip_seekdir64 */
#undef zzip_telldir /* zzip_telldir64 */
/* DLL compatibility layer - so that 32bit code can link with a 64on32 too */
long zzip_telldir(ZZIP_DIR * dir) { return zzip_telldir32(dir); }
void zzip_seekdir(ZZIP_DIR * dir, long offset) { zzip_seekdir32(dir, offset); }
#endif
/**
* This function is the equivalent of => opendir(3) for a realdir or zipfile.
*
* 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.
*
* 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))
{
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;
}
}
}
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.
*
* 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; }
if (USE_DIRENT && dir->realdir)
{
_zzip_closedir(dir->realdir);
free(dir->realname);
free(dir);
return 0;
} else
{
zzip_dir_close(dir);
return 0;
}
}
/*
* Local variables:
* c-file-style: "stroustrup"
* End:
*/