]> granicus.if.org Git - zziplib/blob - zzip/dir.c
indentation
[zziplib] / zzip / dir.c
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  */
51 void
52 zzip_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
72 static int
73 real_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  */
122 ZZIP_DIRENT *
123 zzip_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  */
155 zzip_off_t
156 zzip_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  */
173 void
174 zzip_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 #if defined ZZIP_LARGEFILE_RENAME && defined EOVERFLOW && defined PIC
190 #undef zzip_seekdir             /* zzip_seekdir64 */
191 #undef zzip_telldir             /* zzip_telldir64 */
192
193 long zzip_telldir(ZZIP_DIR * dir);
194 void zzip_seekdir(ZZIP_DIR * dir, long offset);
195
196 /* DLL compatibility layer - so that 32bit code can link with this lib too */
197
198 long
199 zzip_telldir(ZZIP_DIR * dir)
200 {
201     off_t off = zzip_telldir64(dir);
202     long offs = off;
203
204     if (offs != off)
205         { errno = EOVERFLOW; return -1; }
206     return offs;
207 }
208
209 void
210 zzip_seekdir(ZZIP_DIR * dir, long offset)
211 {
212     zzip_seekdir64(dir, offset);
213 }
214 #endif
215
216 /**
217  * This function is the equivalent of => opendir(3) for a realdir or zipfile.
218  * 
219  * This function has some magic - if the given argument-path
220  * is a directory, it will wrap a real => opendir(3) into the ZZIP_DIR
221  * structure. Otherwise it will divert to => zzip_dir_open which 
222  * can also attach a ".zip" extension if needed to find the archive.
223  * 
224  * the error-code is mapped to => errno(3).
225  */
226 ZZIP_DIR *
227 zzip_opendir(zzip_char_t * filename)
228 {
229     return zzip_opendir_ext_io(filename, 0, 0, 0);
230 }
231
232 /** => zzip_opendir
233  * This function uses explicit ext and io instead of the internal 
234  * defaults, setting them to zero is equivalent to => zzip_opendir
235  */
236 ZZIP_DIR *
237 zzip_opendir_ext_io(zzip_char_t * filename, int o_modes,
238                     zzip_strings_t * ext, zzip_plugin_io_t io)
239 {
240     zzip_error_t e;
241     ZZIP_DIR *dir;
242
243 #  ifdef ZZIP_HAVE_SYS_STAT_H
244     struct stat st;
245 #  endif
246
247     if (o_modes & (ZZIP_PREFERZIP | ZZIP_ONLYZIP))
248         goto try_zzip;
249   try_real:
250
251 #  ifdef ZZIP_HAVE_SYS_STAT_H
252     if (stat(filename, &st) >= 0 && S_ISDIR(st.st_mode))
253     {
254         if (USE_DIRENT)
255         {
256             _zzip_DIR *realdir = _zzip_opendir(filename);
257
258             if (realdir)
259             {
260                 if (! (dir = (ZZIP_DIR *) calloc(1, sizeof(*dir))))
261                 {
262                     _zzip_closedir(realdir);
263                     return 0;
264                 } else
265                 {
266                     dir->realdir = realdir;
267                     dir->realname = strdup(filename);
268                     return dir;
269                 }
270             }
271         }
272         return 0;
273     }
274 #  endif /* HAVE_SYS_STAT_H */
275
276   try_zzip:
277     dir = zzip_dir_open_ext_io(filename, &e, ext, io);
278     if (! dir && (o_modes & ZZIP_PREFERZIP))
279         goto try_real;
280     if (e)
281         errno = zzip_errno(e);
282     return dir;
283 }
284
285 /**
286  * This function is the equivalent of => closedir(3) for a realdir or zipfile.
287  * 
288  * This function is magic - if the given arg-ZZIP_DIR
289  * is a real directory, it will call the real => closedir(3) and then
290  * free the wrapping ZZIP_DIR structure. Otherwise it will divert 
291  * to => zzip_dir_close which will free the ZZIP_DIR structure.
292  */
293 int
294 zzip_closedir(ZZIP_DIR * dir)
295 {
296     if (! dir)
297         { errno = EBADF; return -1; }
298
299     if (USE_DIRENT && dir->realdir)
300     {
301         _zzip_closedir(dir->realdir);
302         free(dir->realname);
303         free(dir);
304         return 0;
305     } else
306     {
307         zzip_dir_close(dir);
308         return 0;
309     }
310 }
311
312 /* 
313  * Local variables:
314  * c-file-style: "stroustrup"
315  * End:
316  */