From 92e8a536326df45479efd345a3139b472a5139f8 Mon Sep 17 00:00:00 2001 From: Guido Draheim Date: Mon, 18 Aug 2003 12:59:04 +0000 Subject: [PATCH] This commit was generated by cvs2svn to compensate for changes in r93, which included commits to RCS files with non-trunk default branches. --- docs/zzip-xor.htm | 154 ++++++++++++++++++ zzip/__dirent.h | 393 ++++++++++++++++++++++++++++++++++++++++++++++ zzip/__mmap.h | 107 +++++++++++++ zzip/dir.c | 291 ++++++++++++++++++++++++++++++++++ zzip/err.c | 154 ++++++++++++++++++ zzip/file.h | 81 ++++++++++ zzip/format.h | 159 +++++++++++++++++++ zzip/info.c | 161 +++++++++++++++++++ zzip/lib.h | 94 +++++++++++ zzip/stat.c | 76 +++++++++ 10 files changed, 1670 insertions(+) create mode 100644 docs/zzip-xor.htm create mode 100644 zzip/__dirent.h create mode 100644 zzip/__mmap.h create mode 100644 zzip/dir.c create mode 100644 zzip/err.c create mode 100644 zzip/file.h create mode 100644 zzip/format.h create mode 100644 zzip/info.c create mode 100644 zzip/lib.h create mode 100644 zzip/stat.c diff --git a/docs/zzip-xor.htm b/docs/zzip-xor.htm new file mode 100644 index 0000000..9eb8e25 --- /dev/null +++ b/docs/zzip-xor.htm @@ -0,0 +1,154 @@ +

ZIP Obfuscation

Using obfuscations like XOR. + + 15. July 2002 + +

The EXT/IO calls

+ +

+ You really should read the section about the + EXT/IO feature of the zziplib since the + obfuscation routines are built on top of it. In order to use obfuscation, + you will generally need to use all the three additional argument that + can be passsed to _open_ext_io functions. For the XOR-example, only one + IO-handler is modified being the read()-call that will simply xor each + data byte upon read with a specific value. It two advantages - doing an + xor twice does yield the same data, so as a developer you do not have + to wonder about the encryption/decryption pair, and it is a stateless + obfuscation that does not need to know about the current position + within the zip-datafile or zippedfile-datatream. +

+ The examples provided just use a simple routine for xoring data that + is defined in all the three of the example programs:

+      static int xor_value = 0x55;
+      static zzip_ssize_t xor_read (int f, void* p, zzip_size_t l)
+      {
+          zzip_size_t r = read(f, p, l);
+	  zzip_size_t i;     char* q = p;
+          for (x=0; x < r; x++) q[x] ^= xor_value;
+          return r;
+      }
+  
+ and place this routine into the io-handlers after initializing + the structure:
+    zzip_init_io (&xor_handlers, 0); xor_handlers.read = &xor_read;
+  
+

+ +

The examples

+ +

+ There are three example programs. The first one is + zzxorcopy.c which actually is not a zziplib + based program. It just opens a file via stdio, loops through all data bytes + it can read thereby xor'ing it, and writes it out to the output file. A + call like "zzxorcopy file.zip file.dat" will + create an obfuscated dat-file from a zip-file that has been possibly + create with the normal infozip tools or any other archive program to + generate a zip-file. The output dat-file is not recognized by normal + zip-enabled apps - the filemagic is obfuscated too. This output + dat-file however is subject to the other two example programs. +

+ The zzxordir.c program will open such an obfuscated + zip file and decode the central directory of that zip. Everything is + still there in just the way it can be shown with the normal unzip + programs and routines. And the zzxorcat.c program + can extract data from this obfuscated zip - and print it un-obfuscated + to the screen. These example programs can help you jumpstart with + your own set of obfuscator routines, possibly more complex ones. +

+ By the way, just compare those with their non-xor counterparts that + you can find in zzdir.c and + zzxorcat.c. Notice that the difference is + in the setup part until the _open_ call after which one can just + use the normal zzip_ routines on that obfuscated file. This is + great for developing since you can start of with the magic-wrappers + working on real-files then slowly turning to pack-files that hold + most of the data and finally ending with a zip-only and obfuscated + dat-file for your project. +

+ +

Some rationale

+ +

+ Some people might ask why not adding standard zip-encryption. Well, + first of all the standard zip-encryption has not been strong enough + for modern computers, and there are hacker tools that even a + half-literate computer-user can use to crack the password of a + zip-archive. Furthermore, adding real encryption is a heavy weight + that many people do not need, see the last argument for seeing the + standard one is useless anyway, and adding a non-standard one + should not be the case of the standard zziplib either, ye know. +

+ On the other hand, obfuscation is a means to fear off half-literates + just as well - there are no premade tools for the obfuscation you + can invent from the xor examples. And a hacker that can de-obfuscate + such a dat-file is able to dissassemble your program as well thereby + going to see your decryption routine and the decryption key. + Although there is a difference, it just ranges on about times and + exprience, not magnitudes. Remember the old saying: you can irritate + some people for some time but not irritate all people for all the time. + As for encryption of artwork and AI scripts in games and applications, + just keep in mind that the final recipient has the decryption key on + his system anyway, just obfuscated. So each such encryption is nothing + more than just a clever form of obfuscation, nothing mathemetical strong. +

+ Some other people might ask why to obfuscate anyway. Well, the reason + is theft. Even people who write opensource free software generally + like to get some reward for what they do, some fame or atleast some + sweet dream to have helped the world go a bit easier in the future. + As for program text this is quite natural for the programmers who + pick up some code from somewhere else - it happens that most of them + have gone through some formation and they know how hard it is to get + even some lines of code out of your brain. This is not the case for + some artwork and AI parameters, people do not have much respect for + those - they just pick it up, put it under their umbrella, and + that's it - they even claim they could have done that themselves, + and in most cases it is that they never have been really trying to + do it and think of it as being comparable to that action-art they've + seen on TV. +

+ Just be sure that there is nothing wrong with obfuscating + things for a binary distribution of your program even for the + opensource case - the program text itself is an obfuscation in its + source form when being compiled into cpu instructions. Still, the + interested people can get hold of the source code since you provide + it somewhere and actually the original programmers like to hear + from literate people who could help with modifying the project. The + same is true for you artwork and AI scripts, the interested people + can still see them in the opensource project material, but only + those will look who dare to, not just the halfwit next door. +

+ Well, you do not need to that on the other hand - ID software has + shown that it can be very helpful since people will start to + write new maps and new bots, pack them and publish them. An open + data format is a form of attraction for people who can use a + graphics program and an editor but who do not know how to program. + And if you use obfuscation within an opensource program, it is + surely enought to just use the xor-format presented here, so that + it easy for third people to get involved if they want to, they + just have to rewrite their new datapacks with zzxorcopy, and + that's it. +

+ As for the non-opensource projects, be aware that there are + some ways to even staticlink the zziplib into your project, so + you can even hide that you used zip tools to create your dat files. + This is well enough for anyone to do - as soon as a hacker will + get to the point to notice you used a zip format, he would have + had found any other deobfusation or decryption routine as well. + If you are frightened, just encrypt the executable with tools + you bought from somewhere else. On the other hand, should there + be problems or bugs, you have an easier time to find them when + they could be caused by your dat entries, and it is again easy + to send a fixup file to your clients, since the command line + tools are just a breeze compared with some other anti-hacking + tools you'll find on the market. +

+ Well, hope this is enough rationale to tell you that I do not + see a need to implement anything more than obfuscation within + zziplib - if you need real encryption, use real encryption + software and its fileformat that supports it, not zip files. +

+ +

+staticlinking? +

diff --git a/zzip/__dirent.h b/zzip/__dirent.h new file mode 100644 index 0000000..fc3e08f --- /dev/null +++ b/zzip/__dirent.h @@ -0,0 +1,393 @@ +#ifndef ZZIP_INTERNAL_DIRENT_H +#define ZZIP_INTERNAL_DIRENT_H +#include + +/* + * DO NOT USE THIS CODE. + * + * It is an internal header file for zziplib that carries some inline + * functions (or just static members) and a few defines, simply to be + * able to reuse these across - and have everything in a specific place. + * + * Copyright (c) 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 + */ + +#ifdef ZZIP_HAVE_DIRENT_H +#define USE_DIRENT 1 + +#define _zzip_opendir opendir +#define _zzip_readdir readdir +#define _zzip_closedir closedir +#define _zzip_rewinddir rewinddir +#define _zzip_telldir telldir +#define _zzip_seekdir seekdir +#define _zzip_DIR DIR + +#include + +#elif defined ZZIP_HAVE_WINBASE_H +#define USE_DIRENT 2 + +#define _zzip_opendir win32_opendir +#define _zzip_readdir win32_readdir +#define _zzip_closedir win32_closedir +#define _zzip_rewinddir win32_rewinddir +#define _zzip_telldir win32_telldir +#define _zzip_seekdir win32_seekdir +#define _zzip_DIR DIR + +/* + * DIRENT.H (formerly DIRLIB.H) + * + * by M. J. Weinstein Released to public domain 1-Jan-89 + * + * Because I have heard that this feature (opendir, readdir, closedir) + * it so useful for programmers coming from UNIX or attempting to port + * UNIX code, and because it is reasonably light weight, I have included + * it in the Mingw32 package. I have also added an implementation of + * rewinddir, seekdir and telldir. + * - Colin Peters + * + * This code is distributed in the hope that is will be useful but + * WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY + * DISCLAMED. This includeds but is not limited to warranties of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + */ + +#include + +struct dirent +{ + long d_ino; /* Always zero. */ + unsigned short d_reclen; /* Always zero. */ + unsigned short d_namlen; /* Length of name in d_name. */ + char* d_name; /* File name. */ + /* NOTE: The name in the dirent structure points to the name in the + * finddata_t structure in the DIR. */ +}; + +/* + * This is an internal data structure. Good programmers will not use it + * except as an argument to one of the functions below. + */ +typedef struct +{ + /* disk transfer area for this dir */ + struct _finddata_t dd_dta; + + /* dirent struct to return from dir (NOTE: this makes this thread + * safe as long as only one thread uses a particular DIR struct at + * a time) */ + struct dirent dd_dir; + + /* _findnext handle */ + long dd_handle; + + /* + * Status of search: + * 0 = not started yet (next entry to read is first entry) + * -1 = off the end + * positive = 0 based index of next entry + */ + short dd_stat; + + /* given path for dir with search pattern (struct is extended) */ + char dd_name[1]; +} DIR; + +/* + * dirent.c + * + * Derived from DIRLIB.C by Matt J. Weinstein + * This note appears in the DIRLIB.H + * DIRLIB.H by M. J. Weinstein Released to public domain 1-Jan-89 + * + * Updated by Jeremy Bettis + * Significantly revised and rewinddir, seekdir and telldir added by Colin + * Peters + */ + +#include +#include +#include +#include +#include +#include + +#define win32_SUFFIX "*" +#define win32_SLASH "\\" + +#ifndef S_ISDIR +#define S_ISDIR(m) ((m & S_IFMT) == S_IFDIR) /* is a directory */ +#endif S_ISDIR + + +/* + opendir + + Returns a pointer to a DIR structure appropriately filled in to begin + searching a directory. +*/ +static DIR* +win32_opendir (const char *szPath) +{ + DIR *nd; + struct _stat statDir; + + errno = 0; + + if (!szPath) { + errno = EFAULT; + return (DIR *) 0; + } + + if (szPath[0] == '\0') { + errno = ENOTDIR; + return (DIR *) 0; + } + + /* Attempt to determine if the given path really is a directory. */ + if (_stat (szPath, &statDir)) { + /* Error, stat should have set an error value. */ + return (DIR *) 0; + } + + if (!S_ISDIR (statDir.st_mode)) { + /* Error, stat reports not a directory. */ + errno = ENOTDIR; + return (DIR *) 0; + } + + /* Allocate enough space to store DIR structure and the complete * + directory path given. */ + nd = (DIR *) calloc (1, sizeof (DIR) + strlen (szPath) + + strlen (win32_SLASH) + strlen (win32_SUFFIX)); + + if (!nd) { + /* Error, out of memory. */ + errno = ENOMEM; + return (DIR *) 0; + } + + /* Create the search expression. */ + strcpy (nd->dd_name, szPath); + + /* Add on a slash if the path does not end with one. */ + if (nd->dd_name[0] != '\0' && + nd->dd_name[strlen (nd->dd_name) - 1] != '/' && + nd->dd_name[strlen (nd->dd_name) - 1] != '\\') { + strcat (nd->dd_name, win32_SLASH); + } + + /* Add on the search pattern */ + strcat (nd->dd_name, win32_SUFFIX); + + /* Initialize handle to -1 so that a premature closedir doesn't try * to + call _findclose on it. */ + nd->dd_handle = -1; + + /* Initialize the status. */ + nd->dd_stat = 0; + + /* Initialize the dirent structure. ino and reclen are invalid under * + Win32, and name simply points at the appropriate part of the * + findfirst_t structure. */ + nd->dd_dir.d_ino = 0; + nd->dd_dir.d_reclen = 0; + nd->dd_dir.d_namlen = 0; + nd->dd_dir.d_name = nd->dd_dta.name; + + return nd; +} + +/* + readdir + + Return a pointer to a dirent structure filled with the information on the + next entry in the directory. +*/ +static struct dirent * +win32_readdir (DIR * dirp) +{ + errno = 0; + + /* Check for valid DIR struct. */ + if (!dirp) { + errno = EFAULT; + return (struct dirent *) 0; + } + + if (dirp->dd_dir.d_name != dirp->dd_dta.name) { + /* The structure does not seem to be set up correctly. */ + errno = EINVAL; + return (struct dirent *) 0; + } + + if (dirp->dd_stat < 0) { + /* We have already returned all files in the directory * (or the + structure has an invalid dd_stat). */ + return (struct dirent *) 0; + } else if (dirp->dd_stat == 0) { + /* We haven't started the search yet. */ + /* Start the search */ + dirp->dd_handle = _findfirst (dirp->dd_name, &(dirp->dd_dta)); + + if (dirp->dd_handle == -1) { + /* Whoops! Seems there are no files in that * directory. */ + dirp->dd_stat = -1; + } else { + dirp->dd_stat = 1; + } + } else { + /* Get the next search entry. */ + if (_findnext (dirp->dd_handle, &(dirp->dd_dta))) { + /* We are off the end or otherwise error. */ + _findclose (dirp->dd_handle); + dirp->dd_handle = -1; + dirp->dd_stat = -1; + } else { + /* Update the status to indicate the correct * number. */ + dirp->dd_stat++; + } + } + + if (dirp->dd_stat > 0) { + /* Successfully got an entry. Everything about the file is * already + appropriately filled in except the length of the * file name. */ + dirp->dd_dir.d_namlen = (unsigned short) strlen (dirp->dd_dir.d_name); + return &dirp->dd_dir; + } + + return (struct dirent *) 0; +} + +/* + closedir + + Frees up resources allocated by opendir. +*/ +static int +win32_closedir (DIR * dirp) +{ + int rc; + + errno = 0; + rc = 0; + + if (!dirp) { + errno = EFAULT; + return -1; + } + + if (dirp->dd_handle != -1) { + rc = _findclose (dirp->dd_handle); + } + + /* Delete the dir structure. */ + free (dirp); + + return rc; +} + +/* + rewinddir + + Return to the beginning of the directory "stream". We simply call findclose + and then reset things like an opendir. +*/ +static void +win32_rewinddir (DIR * dirp) +{ + errno = 0; + + if (!dirp) { + errno = EFAULT; + return; + } + + if (dirp->dd_handle != -1) { + _findclose (dirp->dd_handle); + } + + dirp->dd_handle = -1; + dirp->dd_stat = 0; +} + +/* + telldir + + Returns the "position" in the "directory stream" which can be used with + seekdir to go back to an old entry. We simply return the value in stat. +*/ +static long +win32_telldir (DIR * dirp) +{ + errno = 0; + + if (!dirp) { + errno = EFAULT; + return -1; + } + return dirp->dd_stat; +} + +/* + seekdir + + Seek to an entry previously returned by telldir. We rewind the directory + and call readdir repeatedly until either dd_stat is the position number + or -1 (off the end). This is not perfect, in that the directory may + have changed while we weren't looking. But that is probably the case with + any such system. +*/ +static void +win32_seekdir (DIR * dirp, long lPos) +{ + errno = 0; + + if (!dirp) { + errno = EFAULT; + return; + } + + if (lPos < -1) { + /* Seeking to an invalid position. */ + errno = EINVAL; + return; + } else if (lPos == -1) { + /* Seek past end. */ + if (dirp->dd_handle != -1) { + _findclose (dirp->dd_handle); + } + dirp->dd_handle = -1; + dirp->dd_stat = -1; + } else { + /* Rewind and read forward to the appropriate index. */ + win32_rewinddir (dirp); + + while ((dirp->dd_stat < lPos) && win32_readdir (dirp)); + } +} + +#else +#define USE_DIRENT 0 + +#define _zzip_opendir(_N_) 0 +#define _zzip_readdir(_D_) 0 +#define _zzip_closedir(_D_) /* omit return code */ +#define _zzip_rewinddir(_D_) +#define _zzip_telldir(_D_) 0 +#define _zzip_seekdir(_D_,_V_) /* omit return code */ +#define _zzip_DIR void* + +/* end of DIRENT implementation */ +#endif + +/* once */ +#endif diff --git a/zzip/__mmap.h b/zzip/__mmap.h new file mode 100644 index 0000000..d43d279 --- /dev/null +++ b/zzip/__mmap.h @@ -0,0 +1,107 @@ +#ifndef __ZZIP_INTERNAL_MMAP_H +#define __ZZIP_INTERNAL_MMAP_H +#include + +/* + * DO NOT USE THIS CODE. + * + * It is an internal header file for zziplib that carries some inline + * functions (or just static members) and a few defines, simply to be + * able to reuse these across - and have everything in a specific place. + * + * Copyright (c) 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 + */ + +#ifdef _USE_MMAP +#if defined ZZIP_HAVE_SYS_MMAN_H +#include +#define USE_POSIX_MMAP 1 +#elif defined ZZIP_HAVE_WINBASE_H || defined WIN32 +#include +#define USE_WIN32_MMAP 1 +#else +#undef _USE_MMAP +#endif +#endif + +/* -------------- specify MMAP function imports --------------------------- */ + +#if defined USE_POSIX_MMAP +#define USE_MMAP 1 + +#define _zzip_mmap(user, fd, offs, len) \ + mmap (0, len, PROT_READ, MAP_SHARED, fd, offs) +#define _zzip_munmap(user, ptr, len) \ + munmap (ptr, len) +#define _zzip_getpagesize(user) getpagesize() + +#ifndef MAP_FAILED /* hpux10.20 does not have it */ +#define MAP_FAILED ((void*)(-1)) +#endif + +#elif defined USE_WIN32_MMAP +#define USE_MMAP 1 +#ifndef MAP_FAILED +#define MAP_FAILED 0 +#endif +/* we (ab)use the "*user" variable to store the FileMapping handle */ + /* which assumes (sizeof(long) == sizeof(HANDLE)) */ + +static size_t win32_getpagesize () +{ + SYSTEM_INFO si; GetSystemInfo (&si); + return si.dwAllocationGranularity; +} +static void* win32_mmap (long* user, int fd, zzip_off_t offs, size_t len) +{ + if (! user || *user != 1) /* || offs % getpagesize() */ + return 0; + { + HANDLE hFile = (HANDLE)_get_osfhandle(fd); + if (hFile) + *user = (int) CreateFileMapping (hFile, 0, PAGE_READONLY, 0, 0, NULL); + if (*user) + { + char* p = 0; + p = MapViewOfFile(*(HANDLE*)user, FILE_MAP_READ, 0, offs, len); + if (p) return p + offs; + CloseHandle (*(HANDLE*)user); *user = 1; + } + return MAP_FAILED; + } +} +static void win32_munmap (long* user, char* fd_map, size_t len) +{ + UnmapViewOfFile (fd_map); + CloseHandle (*(HANDLE*)user); *user = 1; +} + +#define _zzip_mmap(user, fd, offs, len) \ + win32_mmap ((long*) &(user), fd, offs, len) +#define _zzip_munmap(user, ptr, len) \ + win32_munmap ((long*) &(user), ptr, len) +#define _zzip_getpagesize(user) win32_getpagesize() + +#else /* disable */ +#define USE_MMAP 0 +/* USE_MAP is intentional: we expect the compiler to do some "code removal" + * on any source code enclosed in if (USE_MMAP) {...} i.e. the unreachable + * branch of an if (0) {....} is not emitted to the final object binary. */ + +#ifndef MAP_FAILED +#define MAP_FAILED 0 +#endif + +#define _zzip_mmap(user, fd, offs, len) (MAP_FAILED) +#define _zzip_munmap(user, ptr, len) {} +#define _zzip_getpagesize(user) 1 + +#endif /* USE_MMAP defines */ + + +#endif diff --git a/zzip/dir.c b/zzip/dir.c new file mode 100644 index 0000000..aaf874e --- /dev/null +++ b/zzip/dir.c @@ -0,0 +1,291 @@ +/* + * Author: + * Guido Draheim + * + * 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 /* exported... */ +#include +#include /*offsetof*/ +#include +#include +#include + +#ifdef ZZIP_HAVE_SYS_STAT_H +#include +#else +#include +#endif + +#include + +#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. + */ +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); + } +} + +#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. + *

+ * 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: + */ diff --git a/zzip/err.c b/zzip/err.c new file mode 100644 index 0000000..299c44e --- /dev/null +++ b/zzip/err.c @@ -0,0 +1,154 @@ +/* + * Author: + * Guido Draheim + * Tomi Ollila + * + * 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 /* exported... */ +#include + +#include +#include + +#include + +static struct errlistentry { int code; const char* mesg; } +errlist[] = +{ + { ZZIP_NO_ERROR, "No error" }, + { ZZIP_OUTOFMEM, "could not get temporary memory for internal structures" }, + { ZZIP_DIR_OPEN, "Failed to open zip-file %s" }, + { ZZIP_DIR_STAT, "Failed to fstat zip-file %s" }, + { ZZIP_DIR_SEEK, "Failed to lseek zip-file %s" }, + { ZZIP_DIR_READ, "Failed to read zip-file %s"}, + { ZZIP_DIR_TOO_SHORT, "zip-file %s too short" }, + { ZZIP_DIR_EDH_MISSING, "zip-file central directory not found" }, + { ZZIP_DIRSIZE, "Directory size too big..." }, + { ZZIP_ENOENT, "No such file found in zip-file %s" }, + { ZZIP_UNSUPP_COMPR, "Unsupported compression format" }, + { ZZIP_CORRUPTED, "Zipfile corrupted" }, + { ZZIP_UNDEF, "Some undefined error occurred" }, + { 0, 0 }, +}; + +#define errlistSIZE (sizeof(errlist)/sizeof(*errlist)) + +/** + * returns the static string for the given error code. The + * error code can be either a normal system error (a + * positive error code will flag this), it can be => libz + * error code (a small negative error code will flag this) + * or it can be an error code from => libzzip, which is an + * negative value lower than => ZZIP_ERROR + */ +zzip_char_t* +zzip_strerror(int errcode) +{ + if (errcode < ZZIP_ERROR && errcode > ZZIP_ERROR-32) + { + struct errlistentry* err = errlist; + for (; err->mesg ; err++) + { + if (err->code == errcode) + return err->mesg; + } + errcode = EINVAL; + } + + if (errcode < 0) + { + if (errcode == -1) + return strerror(errcode); + else + return zError(errcode); + } + + return strerror (errcode); +} + +/** => zzip_strerror + * This function fetches the errorcode from the => DIR-handle and + * runs it through => zzip_strerror to obtain the static string + * describing the error. + */ +zzip_char_t* +zzip_strerror_of(ZZIP_DIR* dir) +{ + if (! dir) return strerror (errno); + return zzip_strerror(dir->errcode); +} + +static struct errnolistentry { int code; int e_no; } +errnolist[] = +{ + { Z_STREAM_ERROR, EPIPE }, + { Z_DATA_ERROR, ESPIPE }, + { Z_MEM_ERROR, ENOMEM }, + { Z_BUF_ERROR, EMFILE }, + { Z_VERSION_ERROR, ENOEXEC }, + + { ZZIP_DIR_OPEN, ENOTDIR }, + { ZZIP_DIR_STAT, EREMOTE }, + { ZZIP_DIR_SEEK, ESPIPE }, +# ifdef ESTRPIPE + { ZZIP_DIR_READ, ESTRPIPE}, +# else + { ZZIP_DIR_READ, EPIPE}, +# endif + { ZZIP_DIR_TOO_SHORT, ENOEXEC }, +# ifdef ENOMEDIUM + { ZZIP_DIR_EDH_MISSING, ENOMEDIUM }, +# else + { ZZIP_DIR_EDH_MISSING, EIO }, +# endif + { ZZIP_DIRSIZE, EFBIG }, + { ZZIP_OUTOFMEM, ENOMEM }, + { ZZIP_ENOENT, ENOENT }, +# ifdef EPFNOSUPPORT + { ZZIP_UNSUPP_COMPR, EPFNOSUPPORT }, +# else + { ZZIP_UNSUPP_COMPR, EACCES }, +# endif +# ifdef EILSEQ + { ZZIP_CORRUPTED, EILSEQ }, +# else + { ZZIP_CORRUPTED, ELOOP }, +# endif + { ZZIP_UNDEF, EINVAL }, + { 0, 0 }, +}; + +/** + * map the error code to a system error code. This is used + * for the drop-in replacement functions to return a value + * that can be interpreted correctly by code sections that + * are unaware of the fact they their => open(2) call had been + * diverted to a file inside a zip-archive. + */ +int +zzip_errno(int errcode) +{ + if (errcode >= -1) return errno; + + { struct errnolistentry* err = errnolist; + for (; err->code ; err++) + { + if (err->code == errcode) + return err->e_no; + } + } + return EINVAL; +} + +/* + * Local variables: + * c-file-style: "stroustrup" + * End: + */ diff --git a/zzip/file.h b/zzip/file.h new file mode 100644 index 0000000..e3b3497 --- /dev/null +++ b/zzip/file.h @@ -0,0 +1,81 @@ +/* + * this is an internal header file - the structure contains two off_t + * atleast making it LARGEFILE_SENSITIVE on linux2 and solaris systems + * whereas about all functions just return a ZZIP_FILE* in zzip/zzip.h + * + * and so, this structure should be handled version-specific and + * subject to change - it had been kept binary-compatible for quite + * a while now so perhaps some program sources have errnously taken + * advantage of this file. + * + * Author: + * Guido Draheim + * Tomi Ollila + * + * Copyright (c) 1999,2000,2001,2002 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 + */ + +#ifndef _ZZIP_FILE_H /* zzip-file.h */ +#define _ZZIP_FILE_H 1 + +#ifndef ZZIP_32K +#ifdef __GNUC__ +/* include zzip/lib.h beforehand in order to suppress the following warning */ +#warning zzip/file.h is an internal header, do not use it freely +#endif +#endif + +#include +#include + +#ifdef ZZIP_HAVE_UNISTD_H +#include +#else +#include +# ifdef ZZIP_HAVE_SYS_TYPES_H +# include +# endif +#endif + +#ifdef ZZIP_HAVE_SYS_PARAM_H +#include /* PATH_MAX */ +#endif + +#ifndef PATH_MAX +# ifdef MAX_PATH /* windows */ +# define PATH_MAX MAX_PATH +# else +# define PATH_MAX 512 +# endif +#endif +/* + * ZZIP_FILE structure... currently no need to unionize, since structure needed + * for inflate is superset of structure needed for unstore. + * + * Don't make this public. Instead, create methods for needed operations. + */ + +struct zzip_file +{ + struct zzip_dir* dir; + int fd; + int method; + zzip_size_t restlen; + zzip_size_t crestlen; + zzip_size_t usize; + zzip_size_t csize; + /* added dataoffset member - data offset from start of zipfile*/ + zzip_off_t dataoffset; + char* buf32k; + zzip_off_t offset; /* offset from the start of zipfile... */ + z_stream d_stream; + zzip_plugin_io_t io; +}; + +#endif /* _ZZIP_FILE_H */ + diff --git a/zzip/format.h b/zzip/format.h new file mode 100644 index 0000000..06ad5dd --- /dev/null +++ b/zzip/format.h @@ -0,0 +1,159 @@ +/* + * Author: + * Guido Draheim + * + * Copyright (c) 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 + * + * The information was taken from appnote-981119-iz.zip + * at http://www.freesoftware.com/pub/infozip/doc/ + * which in turn is based on PKWARE's appnote.txt + */ +#ifndef _ZZIP_FORMAT_H /* zzipformat.h */ +#define _ZZIP_FORMAT_H + +#include +/* we have ICO C 9X types defined */ + +/* + * Overall zipfile format + * [local file header + file data + data descriptr] ... [central directory] [EOD record] + */ + +# ifdef _MSC_VER +# pragma pack(push, 1) +# endif + +struct zzip_version +{ + char version[1]; + char ostype[1]; +} __attribute__((packed)); + +struct zzip_dostime +{ + char time[2]; + char date[2]; +} __attribute__((packed)); + +#define ZZIP_CHECKMAGIC(__p,__A,__B,__C,__D) \ + ( (((char*)(__p))[0]==(__A)) && \ + (((char*)(__p))[1]==(__B)) && \ + (((char*)(__p))[2]==(__C)) && \ + (((char*)(__p))[3]==(__D)) ) + +/* A. Local file header */ +struct zzip_file_header +{ +# define ZZIP_FILE_HEADER_MAGIC 0x04034b50 +# define ZZIP_FILE_HEADER_CHECKMAGIC(__p) ZZIP_CHECKMAGIC(__p,'P','K','\3','\4') + char z_magic[4]; /* local file header signature (0x04034b50) */ + struct zzip_version z_extract; /* version needed to extract */ + char z_flags[2]; /* general purpose bit flag */ + char z_compr[2]; /* compression method */ + struct zzip_dostime z_dostime; /* last mod file time (dos format) */ + char z_crc32[4]; /* crc-32 */ + char z_csize[4]; /* compressed size */ + char z_usize[4]; /* uncompressed size */ + char z_namlen[2]; /* filename length (null if stdin) */ + char z_extras[2]; /* extra field length */ + /* followed by filename (of variable size) */ + /* followed by extra field (of variable size) */ +} __attribute__((packed)); + +/* B. data descriptor + * the data descriptor exists only if bit 3 of z_flags is set. It is byte aligned + * and immediately follows the last byte of compressed data. It is only used if + * the output media of the compressor was not seekable, eg. standard output. + */ +struct zzip_file_trailer +{ +# define ZZIP_FILE_TRAILER_MAGIC 0x08074B50 +# define ZZIP_FILE_TRAILER_CHECKMAGIC(__p) ZZIP_CHECKMAGIC(__p,'P','K','\7','\8') + uint32_t z_magic; /* data descriptor signature (0x08074b50) */ + uint32_t z_crc32; /* crc-32 */ + uint32_t z_csize; /* compressed size */ + uint32_t z_usize; /* uncompressed size */ +} __attribute__((packed)); + +/* C. central directory structure: + [file header] . . . end of central dir record +*/ + +/* directory file header + * - a single entry including filename, extras and comment may not exceed 64k. + */ + +struct zzip_root_dirent +{ +# define ZZIP_ROOT_DIRENT_MAGIC 0x02014b50 +# define ZZIP_ROOT_DIRENT_CHECKMAGIC(__p) ZZIP_CHECKMAGIC(__p,'P','K','\1','\2') + char z_magic[4]; /* central file header signature (0x02014b50) */ + struct zzip_version z_encoder; /* version made by */ + struct zzip_version z_extract; /* version need to extract */ + char z_flags[2]; /* general purpose bit flag */ + char z_compr[2]; /* compression method */ + struct zzip_dostime z_dostime; /* last mod file time&date (dos format) */ + char z_crc32[4]; /* crc-32 */ + char z_csize[4]; /* compressed size */ + char z_usize[4]; /* uncompressed size */ + char z_namlen[2]; /* filename length (null if stdin) */ + char z_extras[2]; /* extra field length */ + char z_comment[2]; /* file comment length */ + char z_diskstart[2]; /* disk number of start (if spanning zip over multiple disks) */ + char z_filetype[2]; /* internal file attributes, bit0 = ascii */ + char z_filemode[4]; /* extrnal file attributes, eg. msdos attrib byte */ + char z_off[4]; /* relative offset of local file header, seekval if singledisk */ + /* followed by filename (of variable size) */ + /* followed by extra field (of variable size) */ + /* followed by file comment (of variable size) */ +} __attribute__((packed)); + +/* end of central dir record */ +struct zzip_disk_trailer +{ +# define ZZIP_DISK_TRAILER_MAGIC 0x06054b50 +# define ZZIP_DISK_TRAILER_CHECKMAGIC(__p) ZZIP_CHECKMAGIC(__p,'P','K','\5','\6') + char z_magic[4]; /* end of central dir signature (0x06054b50) */ + char z_disk[2]; /* number of this disk */ + char z_finaldisk[2]; /* number of the disk with the start of the central dir */ + char z_entries[2]; /* total number of entries in the central dir on this disk */ + char z_finalentries[2]; /* total number of entries in the central dir */ + char z_rootsize[4]; /* size of the central directory */ + char z_rootseek[4]; /* offset of start of central directory with respect to * + * the starting disk number */ + char z_comment[2]; /* zipfile comment length */ + /* followed by zipfile comment (of variable size) */ +} __attribute__((packed)); + +/* z_flags */ +#define ZZIP_IS_ENCRYPTED(p) ((*(unsigned char*)p)&1) +#define ZZIP_IS_COMPRLEVEL(p) (((*(unsigned char*)p)>>1)&3) +#define ZZIP_IS_STREAMED(p) (((*(unsigned char*)p)>>3)&1) + +/* z_compr */ +#define ZZIP_IS_STORED 0 +#define ZZIP_IS_SHRUNK 1 +#define ZZIP_IS_REDUCEDx1 2 +#define ZZIP_IS_REDUCEDx2 3 +#define ZZIP_IS_REDUCEDx3 4 +#define ZZIP_IS_REDUCEDx4 5 +#define ZZIP_IS_IMPLODED 6 +#define ZZIP_IS_TOKENIZED 7 +#define ZZIP_IS_DEFLATED 8 +#define ZZIP_IS_DEFLATED_BETTER 9 +#define ZZIP_IS_IMPLODED_BETTER 10 + +# ifdef _MSC_VER +# pragma pack(pop) +# endif + +#endif /* _ZZIPFORMAT_H */ + + + + diff --git a/zzip/info.c b/zzip/info.c new file mode 100644 index 0000000..144b163 --- /dev/null +++ b/zzip/info.c @@ -0,0 +1,161 @@ +/* + * Author: + * Guido Draheim + * + * Copyright (c) 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 /* exported... */ +#include +#include + +#ifdef ZZIP_HAVE_SYS_STAT_H +#include +#else +#include +#include +#endif + +/** + * just returns dir->errcode of the ZZIP_DIR handle + * see: => zzip_dir_open, => zzip_diropen, => zzip_readdir, => zzip_dir_read + */ +int +zzip_error(ZZIP_DIR * dir) +{ + return dir->errcode; +} + +/** => zzip_error + * This function just does dir->errcode = errcode + */ +void +zzip_seterror(ZZIP_DIR * dir, int errcode) +{ dir->errcode = errcode; } + +/** + * This function will just return fp->dir + * + * If a ZZIP_FILE is contained within a zip-file that one will be a valid + * pointer, otherwise a NULL is returned and the ZZIP_FILE wraps a real file. + */ +ZZIP_DIR * +zzip_dirhandle(ZZIP_FILE * fp) +{ + return fp->dir; +} + +/** => zzip_dirhandle + * This function will just return dir->fd + * + * If a ZZIP_DIR does point to a zipfile then the file-descriptor of that + * zipfile is returned, otherwise a NULL is returned and the ZZIP_DIR wraps + * a real directory DIR (if you have dirent on your system). + */ +int +zzip_dirfd(ZZIP_DIR* dir) +{ + return dir->fd; +} + +/** + * return static const string of the known compression methods, + * otherwise just "zipped" is returned + */ +zzip_char_t* +zzip_compr_str(int compr) +{ + switch(compr) + { + case ZZIP_IS_STORED: return "stored"; + case ZZIP_IS_SHRUNK: return "shrunk"; + case ZZIP_IS_REDUCEDx1: + case ZZIP_IS_REDUCEDx2: + case ZZIP_IS_REDUCEDx3: + case ZZIP_IS_REDUCEDx4: return "reduced"; + case ZZIP_IS_IMPLODED: return "imploded"; + case ZZIP_IS_TOKENIZED: return "tokenized"; + case ZZIP_IS_DEFLATED: return "deflated"; + case ZZIP_IS_DEFLATED_BETTER: return "deflatedX"; + case ZZIP_IS_IMPLODED_BETTER: return "implodedX"; + default: + if (0 < compr && compr < 256) return "zipped"; + else + { +# ifdef S_ISDIR + if (S_ISDIR(compr)) return "directory"; +# endif +# ifdef S_ISCHR + if (S_ISCHR(compr)) return "is/chr"; +# endif +# ifdef S_ISBLK + if (S_ISBLK(compr)) return "is/blk"; +# endif +# ifdef S_ISFIFO + if (S_ISFIFO(compr)) return "is/fifo"; +# endif +# ifdef S_ISSOCK + if (S_ISSOCK(compr)) return "is/sock"; +# endif +# ifdef S_ISLNK + if (S_ISLNK(compr)) return "is/lnk"; +# endif + return "special"; + } + }/*switch*/ +} + +/** => zzip_file_real + * This function checks if the ZZIP_DIR-handle is wrapping + * a real directory or a zip-archive. + * Returns 1 for a stat'able directory, and 0 for a handle to zip-archive. + */ +int +zzip_dir_real(ZZIP_DIR* dir) +{ + return dir->realdir != 0; +} + +/** + * This function checks if the ZZIP_FILE-handle is wrapping + * a real file or a zip-contained file. + * Returns 1 for a stat'able file, and 0 for a file inside a zip-archive. + */ +int +zzip_file_real(ZZIP_FILE* fp) +{ + return fp->dir == 0; /* ie. not dependent on a zip-arch-dir */ +} + +/** => zzip_file_real + * This function returns the posix DIR* handle (if one exists). + * Check before with => zzip_dir_real if the + * the ZZIP_DIR points to a real directory. + */ +void* +zzip_realdir(ZZIP_DIR* dir) +{ + return dir->realdir; +} + +/** => zzip_file_real + * This function returns the posix file descriptor (if one exists). + * Check before with => zzip_file_real if the + * the ZZIP_FILE points to a real file. + */ +int +zzip_realfd(ZZIP_FILE* fp) +{ + return fp->fd; +} + +/* + * Local variables: + * c-file-style: "stroustrup" + * End: + */ diff --git a/zzip/lib.h b/zzip/lib.h new file mode 100644 index 0000000..8ff1333 --- /dev/null +++ b/zzip/lib.h @@ -0,0 +1,94 @@ +/* + * Author: + * Guido Draheim + * Tomi Ollila + * + * 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 + * + * This is the private header containing definitions that are not + * use by a libzzip user application. Writing an extension lib that + * uses libzzip will still want to include this. The extension + * write should make way to have the ISO C9X integer types defined. + */ +#ifndef _ZZIP_LIB_H /* zzip.h */ +#define _ZZIP_LIB_H + +#include +#include +#include + +/* + * this structure cannot be wildly enlarged... (see zzip-zip.c) + */ +struct zzip_dir_hdr +{ + uint32_t d_usize; /* uncompressed size */ + uint32_t d_csize; /* compressed size */ + uint32_t d_crc32; /* the adler32-checksum */ + uint32_t d_off; /* offset of file in zipfile */ + uint16_t d_reclen; /* next dir_hdr structure offset */ + uint16_t d_namlen; /* explicit namelen of d_name */ + uint8_t d_compr; /* the compression type, 0 = store, 8 = inflate */ + char d_name[1]; /* the actual name of the entry, may contain DIRSEPs */ +}; +#define _ZZIP_DIRENT_HAVE_D_NAMLEN +#define _ZZIP_DIRENT_HAVE_D_OFF +#define _ZZIP_DIRENT_HAVE_D_RECLEN + +/* + * you shall not use this struct anywhere else than in zziplib sources. + */ +struct zzip_dir +{ + int fd; + int errcode; /* zzip_error_t */ + long refcount; + struct { + struct zzip_file * fp; /* reduce a lot of alloc/deallocations by */ + char * buf32k; /* caching one entry of these data structures */ + } cache; + struct zzip_dir_hdr * hdr0; /* zfi; */ + struct zzip_dir_hdr * hdr; /* zdp; directory pointer, for dirent stuff */ + struct zzip_file * currentfp; /* last fp used... */ + struct zzip_dirent dirent; + void* realdir; /* e.g. DIR* from posix dirent.h */ + char* realname; + zzip_strings_t* fileext; /* list of fileext to test for */ + zzip_plugin_io_t io; /* vtable for io routines */ +}; + +#define ZZIP_32K 32768 + +/* try to open a zip-basename with default_fileext */ +int __zzip_try_open (zzip_char_t* filename, int filemode, + zzip_strings_t* ext, zzip_plugin_io_t io); + +ZZIP_DIR * +zzip_dir_fdopen(int fd, zzip_error_t * errcode_p); + +ZZIP_DIR* +zzip_dir_fdopen_ext_io(int fd, zzip_error_t * errorcode_p, + zzip_strings_t* ext, const zzip_plugin_io_t io); + +ZZIP_DIR* /*depracated*/ +zzip_dir_alloc_ext_io (zzip_strings_t* ext, const zzip_plugin_io_t io); + +/* get 16/32 bits from little-endian zip-file to host byteorder */ +uint32_t __zzip_get32(unsigned char * s); +uint16_t __zzip_get16(unsigned char * s); + +#ifdef __i386__ +#define ZZIP_GET32(x) (*(uint32_t*)(x)) +#define ZZIP_GET16(x) (*(uint16_t*)(x)) +#else +#define ZZIP_GET32(x) (__zzip_get32(x)) +#define ZZIP_GET16(x) (__zzip_get16(x)) +#endif + +#endif /* _ZZIP_H */ + diff --git a/zzip/stat.c b/zzip/stat.c new file mode 100644 index 0000000..43b4bfc --- /dev/null +++ b/zzip/stat.c @@ -0,0 +1,76 @@ +/* + * Author: + * Guido Draheim + * Tomi Ollila + * + * Copyright (c) 1999,2000,2001,2002 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 + * + * Description: + * although this file is defining a function called zzip_stat it + * will not need a real stat(2) exported by the Operating System. + * It will just try to fill the fields of the ZZIP_STAT structure + * of + */ + +#include /* exported...*/ +#include + +/** + * obtain information about a filename in an opened zip-archive without + * opening that file first. Mostly used to obtain the uncompressed + * size of a file inside a zip-archive. see => zzip_dir_open. + */ +int +zzip_dir_stat(ZZIP_DIR * dir, zzip_char_t* name, ZZIP_STAT * zs, int flags) +{ + struct zzip_dir_hdr * hdr = dir->hdr0; + int (*cmp)(zzip_char_t*, zzip_char_t*); + + cmp = (flags & ZZIP_CASEINSENSITIVE) ? strcasecmp : strcmp; + + if (flags & ZZIP_IGNOREPATH) + { + char* n = strrchr(name, '/'); + if (n) name = n + 1; + } + + if (hdr) + while (1) + { + register char* hdr_name = hdr->d_name; + if (flags & ZZIP_IGNOREPATH) + { + register char* n = strrchr(hdr_name, '/'); + if (n) hdr_name = n + 1; + } + + if (! cmp(hdr_name, name)) + break; + + if (! hdr->d_reclen) + { + dir->errcode = ZZIP_ENOENT; + return -1; + } + + hdr = (struct zzip_dir_hdr *) ((char *)hdr + hdr->d_reclen); + } + + zs->d_compr = hdr->d_compr; + zs->d_csize = hdr->d_csize; + zs->st_size = hdr->d_usize; + zs->d_name = hdr->d_name; + + return 0; +} + +/* + * Local variables: + * c-file-style: "stroustrup" + * End: + */ -- 2.40.0