new beta-0.90.0
[luatex.git] / source / libs / zziplib / zziplib-src / zzip / dir.c
blob2df1bbc0fda20f21f4d488d279a247601d9ee76e
2 /*
3 * Author:
4 * Guido Draheim <guidod@gmx.de>
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
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>
21 #ifdef ZZIP_HAVE_SYS_STAT_H
22 #include <sys/stat.h>
23 #else
24 #include <stdio.h>
25 #endif
27 #include <zzip/__dirent.h>
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
34 #ifdef ZZIP_HAVE_SYS_STAT_H
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
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.
51 void
52 zzip_rewinddir(ZZIP_DIR * dir)
54 if (! dir)
55 return;
57 if (USE_DIRENT && dir->realdir)
59 _zzip_rewinddir(dir->realdir);
60 return;
63 if (dir->hdr0)
64 dir->hdr = dir->hdr0;
65 else
66 dir->hdr = 0;
69 #if ! USE_DIRENT
70 #define real_readdir(_X_) 1
71 #else
72 static int
73 real_readdir(ZZIP_DIR * dir)
75 struct stat st = { 0 };
76 char filename[PATH_MAX];
77 struct dirent *dirent = _zzip_readdir(dir->realdir);
79 if (! dirent)
80 return 0;
82 dir->dirent.d_name = dirent->d_name;
83 strcpy(filename, dir->realname);
84 strcat(filename, "/");
85 strcat(filename, dirent->d_name);
87 if (stat(filename, &st) == -1)
88 return -1;
90 dir->dirent.d_csize = dir->dirent.st_size = st.st_size;
92 if (st.st_mode)
94 if (! S_ISREG(st.st_mode))
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
102 dir->dirent.d_compr = 0; /* stored */
104 } else
106 dir->dirent.d_compr = 0; /* stored */
109 return 1;
111 #endif
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.
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).
122 ZZIP_DIRENT *
123 zzip_readdir(ZZIP_DIR * dir)
125 if (! dir)
126 { errno=EBADF; return 0; }
128 if (USE_DIRENT && dir->realdir)
130 if (! real_readdir(dir))
131 return 0;
132 } else
134 if (! dir->hdr)
135 return 0;
137 dir->dirent.d_name = dir->hdr->d_name;
138 dir->dirent.d_compr = dir->hdr->d_compr;
140 dir->dirent.d_csize = dir->hdr->d_csize;
141 dir->dirent.st_size = dir->hdr->d_usize;
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);
149 return &dir->dirent;
152 /** => zzip_rewinddir
153 * This function is the equivalent of => telldir(2) for a realdir or zipfile.
155 zzip_off_t
156 zzip_telldir(ZZIP_DIR * dir)
158 if (! dir)
159 { errno=EBADF; return -1; }
161 if (USE_DIRENT && dir->realdir)
163 return _zzip_telldir(dir->realdir);
164 } else
166 return ((zzip_off_t) ((char *) dir->hdr - (char *) dir->hdr0));
170 /** => zzip_rewinddir
171 * This function is the equivalent of => seekdir(2) for a realdir or zipfile.
173 void
174 zzip_seekdir(ZZIP_DIR * dir, zzip_off_t offset)
176 if (! dir)
177 return;
179 if (USE_DIRENT && dir->realdir)
181 _zzip_seekdir(dir->realdir, offset);
182 } else
184 dir->hdr = (struct zzip_dir_hdr *)
185 (dir->hdr0 ? (char *) dir->hdr0 + (size_t) offset : 0);
189 #ifndef EOVERFLOW
190 #define EOVERFLOW EFBIG
191 #endif
193 /** => zzip_rewinddir
194 * This function is provided for users who can not use any largefile-mode.
196 long
197 zzip_telldir32(ZZIP_DIR * dir)
199 if (sizeof(zzip_off_t) == sizeof(long))
201 return zzip_telldir(dir);
202 } else
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;
210 return -1;
214 /** => zzip_rewinddir
215 * This function is provided for users who can not use any largefile-mode.
217 void
218 zzip_seekdir32(ZZIP_DIR * dir, long offset)
220 zzip_seekdir(dir, offset);
223 #if defined ZZIP_LARGEFILE_RENAME && defined EOVERFLOW && defined PIC
224 #undef zzip_seekdir /* zzip_seekdir64 */
225 #undef zzip_telldir /* zzip_telldir64 */
227 /* DLL compatibility layer - so that 32bit code can link with a 64on32 too */
228 long zzip_telldir(ZZIP_DIR * dir) { return zzip_telldir32(dir); }
229 void zzip_seekdir(ZZIP_DIR * dir, long offset) { zzip_seekdir32(dir, offset); }
230 #endif
233 * This function is the equivalent of => opendir(3) for a realdir or zipfile.
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.
240 * the error-code is mapped to => errno(3).
242 ZZIP_DIR *
243 zzip_opendir(zzip_char_t * filename)
245 return zzip_opendir_ext_io(filename, 0, 0, 0);
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
252 ZZIP_DIR *
253 zzip_opendir_ext_io(zzip_char_t * filename, int o_modes,
254 zzip_strings_t * ext, zzip_plugin_io_t io)
256 zzip_error_t e;
257 ZZIP_DIR *dir;
259 # ifdef ZZIP_HAVE_SYS_STAT_H
260 struct stat st;
261 # endif
263 if (o_modes & (ZZIP_PREFERZIP | ZZIP_ONLYZIP))
264 goto try_zzip;
265 try_real:
267 # ifdef ZZIP_HAVE_SYS_STAT_H
268 if (stat(filename, &st) >= 0 && S_ISDIR(st.st_mode))
270 if (USE_DIRENT)
272 _zzip_DIR *realdir = _zzip_opendir(filename);
274 if (realdir)
276 if (! (dir = (ZZIP_DIR *) calloc(1, sizeof(*dir))))
278 _zzip_closedir(realdir);
279 return 0;
280 } else
282 dir->realdir = realdir;
283 dir->realname = strdup(filename);
284 return dir;
288 return 0;
290 # endif /* HAVE_SYS_STAT_H */
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;
302 * This function is the equivalent of => closedir(3) for a realdir or zipfile.
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.
310 zzip_closedir(ZZIP_DIR * dir)
312 if (! dir)
313 { errno = EBADF; return -1; }
315 if (USE_DIRENT && dir->realdir)
317 _zzip_closedir(dir->realdir);
318 free(dir->realname);
319 free(dir);
320 return 0;
321 } else
323 zzip_dir_close(dir);
324 return 0;
329 * Local variables:
330 * c-file-style: "stroustrup"
331 * End: