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