PageRenderTime 33ms CodeModel.GetById 12ms app.highlight 16ms RepoModel.GetById 1ms app.codeStats 0ms

/src/zziplib/zzip/dir.c

https://bitbucket.org/cabalistic/ogredeps/
C | 332 lines | 222 code | 41 blank | 69 comment | 44 complexity | 1fe3711912d19e843ff9b3d6891657be MD5 | raw file
  1
  2/*
  3 * Author: 
  4 *	Guido Draheim <guidod@gmx.de>
  5 *
  6 *	Copyright (c) 1999,2000,2001,2002,2003 Guido Draheim
  7 * 	    All rights reserved,
  8 *	    use under the restrictions of the
  9 *	    Lesser GNU General Public License
 10 *          or alternatively the restrictions 
 11 *          of the Mozilla Public License 1.1
 12 */
 13
 14#include <zzip/lib.h>           /* exported... */
 15#include <zzip/file.h>
 16#include <stddef.h>             /*offsetof */
 17#include <stdlib.h>
 18#include <string.h>
 19#include <errno.h>
 20
 21#ifdef ZZIP_HAVE_SYS_STAT_H
 22#include <sys/stat.h>
 23#else
 24#include <stdio.h>
 25#endif
 26
 27#include <zzip/__dirent.h>
 28
 29#ifndef offsetof
 30#pragma warning had to DEFINE offsetof as it was not in stddef.h
 31#define offsetof(T,M) ((unsigned)(& ((T*)0)->M))
 32#endif
 33
 34#ifdef ZZIP_HAVE_SYS_STAT_H
 35
 36/* MSVC does have IFbitmask but not the corresponding IStests */
 37# if ! defined S_ISDIR && defined S_IFDIR
 38# define S_ISDIR(_X_) ((_X_) & S_IFDIR)
 39# endif
 40# if ! defined S_ISREG && defined S_IFREG
 41# define S_ISREG(_X_) ((_X_) & S_IFREG)
 42# endif
 43#endif
 44
 45/** 
 46 * This function is the equivalent of a => rewinddir(2) for a realdir or
 47 * the zipfile in place of a directory. The ZZIP_DIR handle returned from
 48 * => zzip_opendir has a flag saying realdir or zipfile. As for a zipfile,
 49 * the filenames will include the filesubpath, so take care.
 50 */
 51void
 52zzip_rewinddir(ZZIP_DIR * dir)
 53{
 54    if (! dir)
 55        return;
 56
 57    if (USE_DIRENT && dir->realdir)
 58    {
 59        _zzip_rewinddir(dir->realdir);
 60        return;
 61    }
 62
 63    if (dir->hdr0)
 64        dir->hdr = dir->hdr0;
 65    else
 66        dir->hdr = 0;
 67}
 68
 69#if ! USE_DIRENT
 70#define real_readdir(_X_) 1
 71#else
 72static int
 73real_readdir(ZZIP_DIR * dir)
 74{
 75    struct stat st = { 0 };
 76    char filename[PATH_MAX];
 77    struct dirent *dirent = _zzip_readdir(dir->realdir);
 78
 79    if (! dirent)
 80        return 0;
 81
 82    dir->dirent.d_name = dirent->d_name;
 83    strcpy(filename, dir->realname);
 84    strcat(filename, "/");
 85    strcat(filename, dirent->d_name);
 86
 87    if (stat(filename, &st) == -1)
 88        return -1;
 89
 90    dir->dirent.d_csize = dir->dirent.st_size = st.st_size;
 91
 92    if (st.st_mode)
 93    {
 94        if (! S_ISREG(st.st_mode))
 95        {
 96            dir->dirent.d_compr = st.st_mode;
 97            dir->dirent.d_compr |= 0x80000000;
 98            /* makes it effectively negative, 
 99             * but can still be fed to S_ISXXX(x) */
100        } else
101        {
102            dir->dirent.d_compr = 0;    /* stored */
103        }
104    } else
105    {
106        dir->dirent.d_compr = 0;        /* stored */
107    }
108
109    return 1;
110}
111#endif
112
113/**
114 * This function is the equivalent of a => readdir(2) for a realdir 
115 * or a zipfile referenced by the ZZIP_DIR returned from => zzip_opendir.
116 *
117 * The ZZIP_DIR handle (as returned by => zzip_opendir) contains a few more 
118 * entries than being copied into the ZZIP_DIRENT. The only valid fields in
119 * a ZZIP_DIRENT are d_name (the file name), d_compr (compression), d_csize
120 * (compressed size), st_size (uncompressed size).
121 */
122ZZIP_DIRENT *
123zzip_readdir(ZZIP_DIR * dir)
124{
125    if (! dir)
126        { errno=EBADF; return 0; }
127
128    if (USE_DIRENT && dir->realdir)
129    {
130        if (! real_readdir(dir))
131            return 0;
132    } else
133    {
134        if (! dir->hdr)
135            return 0;
136
137        dir->dirent.d_name = dir->hdr->d_name;
138        dir->dirent.d_compr = dir->hdr->d_compr;
139
140        dir->dirent.d_csize = dir->hdr->d_csize;
141        dir->dirent.st_size = dir->hdr->d_usize;
142
143        if (! dir->hdr->d_reclen)
144            dir->hdr = 0;
145        else
146            dir->hdr = (struct zzip_dir_hdr *)
147                ((char *) dir->hdr + dir->hdr->d_reclen);
148    }
149    return &dir->dirent;
150}
151
152/** => zzip_rewinddir
153 * This function is the equivalent of => telldir(2) for a realdir or zipfile.
154 */
155zzip_off_t
156zzip_telldir(ZZIP_DIR * dir)
157{
158    if (! dir)
159        { errno=EBADF; return -1; }
160
161    if (USE_DIRENT && dir->realdir)
162    {
163        return _zzip_telldir(dir->realdir);
164    } else
165    {
166        return ((zzip_off_t) ((char *) dir->hdr - (char *) dir->hdr0));
167    }
168}
169
170/** => zzip_rewinddir
171 * This function is the equivalent of => seekdir(2) for a realdir or zipfile.
172 */
173void
174zzip_seekdir(ZZIP_DIR * dir, zzip_off_t offset)
175{
176    if (! dir)
177        return;
178
179    if (USE_DIRENT && dir->realdir)
180    {
181        _zzip_seekdir(dir->realdir, offset);
182    } else
183    {
184        dir->hdr = (struct zzip_dir_hdr *)
185            (dir->hdr0 ? (char *) dir->hdr0 + (size_t) offset : 0);
186    }
187}
188
189#ifndef EOVERFLOW
190#define EOVERFLOW EFBIG
191#endif
192
193/** => zzip_rewinddir
194 * This function is provided for users who can not use any largefile-mode.
195 */
196long
197zzip_telldir32(ZZIP_DIR * dir)
198{
199    if (sizeof(zzip_off_t) == sizeof(long))
200    {
201        return zzip_telldir(dir);
202    } else
203    {
204        off_t off = zzip_telldir(dir);
205        if (off >= 0) {
206            register long off32 = off;
207            if (off32 == off) return off32;
208            errno = EOVERFLOW;
209        }
210        return -1;
211    }
212}
213
214/** => zzip_rewinddir
215 * This function is provided for users who can not use any largefile-mode.
216 */
217void
218zzip_seekdir32(ZZIP_DIR * dir, long offset)
219{
220    zzip_seekdir(dir, offset);
221}
222
223#if defined ZZIP_LARGEFILE_RENAME && defined EOVERFLOW && defined PIC
224#undef zzip_seekdir             /* zzip_seekdir64 */
225#undef zzip_telldir             /* zzip_telldir64 */
226
227/* DLL compatibility layer - so that 32bit code can link with a 64on32 too */
228long zzip_telldir(ZZIP_DIR * dir) { return zzip_telldir32(dir); }
229void zzip_seekdir(ZZIP_DIR * dir, long offset) { zzip_seekdir32(dir, offset); }
230#endif
231
232/**
233 * This function is the equivalent of => opendir(3) for a realdir or zipfile.
234 * 
235 * This function has some magic - if the given argument-path
236 * is a directory, it will wrap a real => opendir(3) into the ZZIP_DIR
237 * structure. Otherwise it will divert to => zzip_dir_open which 
238 * can also attach a ".zip" extension if needed to find the archive.
239 * 
240 * the error-code is mapped to => errno(3).
241 */
242ZZIP_DIR *
243zzip_opendir(zzip_char_t * filename)
244{
245    return zzip_opendir_ext_io(filename, 0, 0, 0);
246}
247
248/** => zzip_opendir
249 * This function uses explicit ext and io instead of the internal 
250 * defaults, setting them to zero is equivalent to => zzip_opendir
251 */
252ZZIP_DIR *
253zzip_opendir_ext_io(zzip_char_t * filename, int o_modes,
254                    zzip_strings_t * ext, zzip_plugin_io_t io)
255{
256    zzip_error_t e;
257    ZZIP_DIR *dir;
258
259#  ifdef ZZIP_HAVE_SYS_STAT_H
260    struct stat st;
261#  endif
262
263    if (o_modes & (ZZIP_PREFERZIP | ZZIP_ONLYZIP))
264        goto try_zzip;
265  try_real:
266
267#  ifdef ZZIP_HAVE_SYS_STAT_H
268    if (stat(filename, &st) >= 0 && S_ISDIR(st.st_mode))
269    {
270        if (USE_DIRENT)
271        {
272            _zzip_DIR *realdir = _zzip_opendir(filename);
273
274            if (realdir)
275            {
276                if (! (dir = (ZZIP_DIR *) calloc(1, sizeof(*dir))))
277                {
278                    _zzip_closedir(realdir);
279                    return 0;
280                } else
281                {
282                    dir->realdir = realdir;
283                    dir->realname = strdup(filename);
284                    return dir;
285                }
286            }
287        }
288        return 0;
289    }
290#  endif /* HAVE_SYS_STAT_H */
291
292  try_zzip:
293    dir = zzip_dir_open_ext_io(filename, &e, ext, io);
294    if (! dir && (o_modes & ZZIP_PREFERZIP))
295        goto try_real;
296    if (e)
297        errno = zzip_errno(e);
298    return dir;
299}
300
301/**
302 * This function is the equivalent of => closedir(3) for a realdir or zipfile.
303 * 
304 * This function is magic - if the given arg-ZZIP_DIR
305 * is a real directory, it will call the real => closedir(3) and then
306 * free the wrapping ZZIP_DIR structure. Otherwise it will divert 
307 * to => zzip_dir_close which will free the ZZIP_DIR structure.
308 */
309int
310zzip_closedir(ZZIP_DIR * dir)
311{
312    if (! dir)
313        { errno = EBADF; return -1; }
314
315    if (USE_DIRENT && dir->realdir)
316    {
317        _zzip_closedir(dir->realdir);
318        free(dir->realname);
319        free(dir);
320        return 0;
321    } else
322    {
323        zzip_dir_close(dir);
324        return 0;
325    }
326}
327
328/* 
329 * Local variables:
330 * c-file-style: "stroustrup"
331 * End:
332 */