/src/zziplib/zzip/write.c

https://bitbucket.org/cabalistic/ogredeps/ · C · 493 lines · 206 code · 38 blank · 249 comment · 34 complexity · b0635bb877e1ed131ea1e9d157a2ef60 MD5 · raw file

  1. /*
  2. * The write-support in zziplib is not a full-flegded interface to the
  3. * internals that zip file-header or zip archive an contain. It's
  4. * primary use goes for savegames or transfer `pack-n-go` archives
  5. * where time-stamps are rather unimportant. Here we can create an
  6. * archive with filenames and their data portions, possibly obfuscated.
  7. *
  8. * DONT USE THIS
  9. *
  10. * The write support is supposed to be added directly into the main
  11. * zziplib but it has not been implemented so far. It does however
  12. * export the relevant call entries which will return EROFS (read-only
  13. * filesystem) in case they are being called. That allows later programs
  14. * to start up with earlier versions of zziplib that can only read ZIPs.
  15. *
  16. * Author:
  17. * Guido Draheim <guidod@gmx.de>
  18. *
  19. * Copyright (c) 2003 Guido Draheim
  20. * All rights reserved,
  21. * use under the restrictions of the
  22. * Lesser GNU General Public License
  23. * or alternatively the restrictions
  24. * of the Mozilla Public License 1.1
  25. */
  26. #define _ZZIP_WRITE_SOURCE
  27. #if defined DDDD || defined DDDDD || defined DDDDDD || defined DDDDDDD
  28. #define _ZZIP_ENABLE_WRITE
  29. #else /* per default, we add support for passthrough to posix write */
  30. #define _ZZIP_POSIX_WRITE
  31. #endif
  32. #include <zzip/write.h> /* #includes <zzip/lib.h> */
  33. #include <zzip/file.h>
  34. #include <string.h>
  35. #include <sys/stat.h>
  36. #include <errno.h>
  37. #include <stdlib.h>
  38. #include <ctype.h>
  39. #ifdef ZZIP_HAVE_DIRECT_H
  40. #include <direct.h>
  41. #endif
  42. #include <zzip/format.h>
  43. #include <zzip/plugin.h>
  44. #include <zzip/__debug.h>
  45. #define ___ {
  46. #define ____ }
  47. #ifndef EROFS
  48. # ifdef ENOSYS
  49. #define EROFS ENOSYS
  50. # else
  51. #define EROFS EPERM
  52. #endif
  53. #endif
  54. /* try real zlib routines for writing ? very experimental, very very ex... */
  55. #ifndef _ZZIP_ENABLE_WRITE
  56. #define _ZZIP_TRY 0
  57. #else
  58. #define _ZZIP_TRY 1
  59. #endif
  60. /* btw, is there any system that did define those different ? get away.. */
  61. # ifndef S_IWGRP
  62. # define S_IWGRP 00020
  63. # endif
  64. # ifndef S_IRWXO
  65. # define S_IRWXO 00007
  66. # endif
  67. # ifdef ZZIP_HAVE_DIRECT_H
  68. # define _mkdir(a,b) mkdir(a)
  69. # else
  70. # define _mkdir mkdir
  71. # endif
  72. /** create a new zip archive for writing
  73. *
  74. * This function will create a new zip archive. The returned parameter
  75. * is a new "zzip dir" handle that should be saved to a variable so it
  76. * can be used a base argument for => zzip_mkdir and => zzip_creat calls.
  77. * The returned handle represents a zip central directory that must be
  78. * saved to disk using => zzip_closedir.
  79. *
  80. * Returns null on error and sets errno. Remember, according to posix
  81. * the => creat(2) call is equivalent to
  82. open (path, O_WRONLY | O_CREAT | O_TRUNC, o_mode)
  83. * so any previous zip-archive will be overwritten unconditionally and
  84. * EEXIST errors from => mkdir(2) are suppressed. (fixme: delete the
  85. * given subtree? like suggested by O_TRUNC? not done so far!)
  86. */
  87. ZZIP_DIR *
  88. zzip_dir_creat(zzip_char_t * name, int o_mode)
  89. {
  90. return zzip_dir_creat_ext_io(name, o_mode, 0, 0);
  91. }
  92. /** => zzip_dir_creat
  93. *
  94. * If the third argument "ext" has another special meaning here, as it
  95. * is used to ensure that a given zip-file is created with the first entry
  96. * of the ext-list appended as an extension unless the file-path already
  97. * ends with a file-extension registered in the list. Therefore {"",0}
  98. * matches all files and creates them as zip-archives under the given
  99. * nonmodified name. (Some magic here? If the path ends in the path
  100. * separator then make a real directory even in the presence of ext-list?)
  101. *
  102. * This function is not yet implemented, check for #def ZZIP_NO_CREAT
  103. * Write-support will extend => zzip_closedir with semantics to finalize the
  104. * zip-archive by writing the zip-trailer and closing the archive file.
  105. */
  106. ZZIP_DIR *
  107. zzip_dir_creat_ext_io(zzip_char_t * name, int o_mode,
  108. zzip_strings_t * ext, zzip_plugin_io_t io)
  109. {
  110. if (! io)
  111. io = zzip_get_default_io();
  112. if (io != zzip_get_default_io())
  113. {
  114. /* the current io-structure does not contain a "write" entry,
  115. * and therefore this parameter is useless. Anyone to expect
  116. * some behavior should be warned, so here we let the function
  117. * fail bluntly - and leaving the recovery to the application
  118. */
  119. errno = EINVAL;
  120. return 0;
  121. }
  122. if (! _ZZIP_TRY)
  123. {
  124. /* not implemented - however, we respect that a null argument to
  125. * zzip_mkdir and zzip_creat works, so we silently still do the mkdir
  126. */
  127. if (! _mkdir(name, o_mode) || errno == EEXIST)
  128. errno = EROFS;
  129. return 0;
  130. } else
  131. {
  132. # define MAX_EXT_LEN 10
  133. ZZIP_DIR *dir = zzip_dir_alloc(ext);
  134. int name_len = strlen(name);
  135. dir->realname = malloc(name_len + MAX_EXT_LEN);
  136. if (! dir->realname)
  137. goto error;
  138. memcpy(dir->realname, name, name_len + 1);
  139. ___ int fd =
  140. __zzip_try_open(dir->realname, O_EXCL | O_TRUNC | O_WRONLY, ext,
  141. io);
  142. if (fd != -1)
  143. { dir->fd = fd; return dir; }
  144. ___ zzip_strings_t *exx = ext;
  145. int exx_len;
  146. for (; *exx; exx++)
  147. {
  148. if ((exx_len = strlen(*exx) + 1) <= name_len &&
  149. ! memcmp(dir->realname + (name_len - exx_len), *exx, exx_len))
  150. break; /* keep unmodified */
  151. exx++;
  152. if (*exx)
  153. continue;
  154. if (! (exx_len = strlen(*exx)) || exx_len >= MAX_EXT_LEN)
  155. break;
  156. memcpy(dir->realname + name_len, exx, exx_len); /* append! */
  157. }
  158. ____;
  159. fd = (io->fd.open)(dir->realname, O_CREAT | O_TRUNC | O_WRONLY, o_mode);
  160. dir->realname[name_len] = '\0'; /* keep ummodified */
  161. if (fd != -1)
  162. { dir->fd = fd; return dir; }
  163. error:
  164. zzip_dir_free(dir);
  165. return 0;
  166. ____;
  167. }
  168. }
  169. /** create a new archive area for writing
  170. *
  171. * This function will create a new archive area. This may either be a
  172. * a new zip archive or a new directory in the filesystem. The returned
  173. * parameter is a new "zzip dir" handle that should be saved to a variable
  174. * so it can be used a base argument for => zzip_file_mkdir and
  175. * => zzip_file_creat calls. The returned handle wraps both possibilities,
  176. * it can be representing a zip central directory that must be
  177. * saved to disk using => zzip_closedir or it is just a handle for the
  178. * name of the real directory that still must be run through
  179. * => zzip_closedir to release the wrapper around the directory name.
  180. *
  181. * The magic is pushed through the o_mode argument. Using a mode that
  182. * has no group-write bit set (S_IWGRP = 0040) then the file is
  183. * created as a zip directory. Note that this is unabridged of any
  184. * umask value in the system where the argument to this function could
  185. * be 0775 but with an umask of 0755 it turns out as 0755 for a real
  186. * directory. Using 0755 directly would not create it as a real directory
  187. * but as a zip archive handle.
  188. *
  189. * This function is not yet implemented, check for #def ZZIP_NO_CREAT
  190. * Write-support will extend => zzip_closedir with semantics to finalize the
  191. * zip-archive by writing the zip-trailer and closing the archive file.
  192. *
  193. * Returns null on error and sets errno. Remember, according to posix
  194. * the => creat(2) call is equivalent to
  195. open (path, O_WRONLY | O_CREAT | O_TRUNC, o_mode)
  196. * so any previous zip-archive will be overwritten unconditionally and
  197. * EEXIST errors from => mkdir(2) are suppressed. (fixme: delete the
  198. * given subtree? like suggested by O_TRUNC? not done so far!)
  199. */
  200. ZZIP_DIR *
  201. zzip_createdir(zzip_char_t * name, int o_mode)
  202. {
  203. if (o_mode & S_IWGRP)
  204. {
  205. if (-1 == _mkdir(name, o_mode) && errno != EEXIST) /* fail */
  206. return 0;
  207. return zzip_opendir(name);
  208. } else
  209. return zzip_dir_creat(name, o_mode);
  210. }
  211. /** => zzip_file_creat also: mkdir(2), creat(2), zzip_dir_creat
  212. *
  213. * This function has an additional primary argument over the posix
  214. * mkdir(2) - if it is null then this function behaves just like
  215. * posix mkdir(2). The zzip_dir argument can be set to the result
  216. * of a => zzip_createdir which allows for some magic that the
  217. * given directory name is created as an entry in the zip archive.
  218. *
  219. * If the given dir name argument is not within the basepath of
  220. * the zip central directory then a real directory is created.
  221. * Any EEXIST errors are not suppressed unlike with => zzip_createdir
  222. *
  223. * Standard usage accepts a global/threaded/modular ZZIP_DIR pointer
  224. * for all zip archive operations like in:
  225. ZZIP_DIR* zip = zzip_createdir (sysconfpath, 0755, zip);
  226. zzip_file_mkdir (zip, filepath[i], 0755);
  227. ZZIP_FILE* file = zzip_file_creat (zip, filename[i], 0644);
  228. zzip_write (file, buf, len);
  229. zzip_close (file); file = 0;
  230. zzip_closedir (zip); zip = 0;
  231. *
  232. * compare with => zzip_mkdir inline macro which allows to
  233. * collapse the examples script to
  234. #define zzip_savefile myproject_saveconfig
  235. #include <zzip/zzip.h>
  236. ZZIP_DIR* zzip_savefile = zzip_createdir (sysconfpath, 0755);
  237. zzip_mkdir (filepath[i], 0755);
  238. ZZIP_FILE* file = zzip_creat(filepath[i], 0644);
  239. zzip_write (file, buf, len);
  240. zzip_close (file); file = 0;
  241. zzip_closedir (zip_savefile);
  242. */
  243. int
  244. zzip_file_mkdir(ZZIP_DIR * dir, zzip_char_t * name, int o_mode)
  245. {
  246. if (! dir)
  247. return _mkdir(name, o_mode);
  248. if (! _ZZIP_TRY)
  249. { /* not implemented */
  250. errno = EROFS;
  251. return -1;
  252. } else
  253. {
  254. errno = EROFS;
  255. return -1;
  256. }
  257. }
  258. /** start next file entry in a zip archive
  259. *
  260. * This function will create a new file within a zzip archive, the
  261. * one given as the primary argument and additionally to the posix
  262. * creat(2) - just like zzip_mkdir has an additional argument over
  263. * the posix mkdir(2) spec. For this function the primary parameter
  264. * can be null as well thereby creating a real file instead of a new
  265. * one inside the zip-archive otherwise given. If the primary parameter is
  266. * not null but wraps a real directory then all new files are also real.
  267. *
  268. * This function is not yet implemented, check for #def ZZIP_NO_CREAT
  269. *
  270. * Returns NULL on an error setting errno, and opening a file _within_
  271. * a zip archive using O_RDONLY (and similar stuff) will surely lead to
  272. * an error.
  273. */
  274. ZZIP_FILE *
  275. zzip_file_creat(ZZIP_DIR * dir, zzip_char_t * name, int o_mode)
  276. {
  277. if (! dir)
  278. return zzip_open(name, o_mode);
  279. if (! _ZZIP_TRY)
  280. { /* not implemented */
  281. errno = EROFS;
  282. return 0;
  283. } else
  284. {
  285. errno = EROFS;
  286. return 0;
  287. }
  288. }
  289. /** write to zzip storage also: write(2), zlib(3)
  290. *
  291. * This function will write data to a file descriptor. If the file
  292. * descriptor represents a real file then it will be forwarded to
  293. * call posix => write(2) directly. If it is a descriptor for a
  294. * file within a zip directory then the data will be "deflated"
  295. * using => zlib(3) and appended to the zip archive file.
  296. */
  297. zzip_ssize_t
  298. zzip_write(ZZIP_FILE * file, const void *ptr, zzip_size_t len)
  299. {
  300. if (zzip_file_real(file))
  301. return write(zzip_realfd(file), ptr, len);
  302. else
  303. return zzip_file_write(file, ptr, len);
  304. }
  305. /** => zzip_write also: zzip_file_creat
  306. *
  307. * This function will write data to a file descriptor inside a zip
  308. * archive. The data will be "deflated" using => zlib(3) compression
  309. * and appended to the end of the zip archive file. Only one file
  310. * descriptor may be open per zzip_dir archive handle (fifo-like).
  311. *
  312. * This function is not yet implemented, check for #def ZZIP_NO_CREAT
  313. * It returns immediately -1 and sets errno=EROFS for indication.
  314. */
  315. zzip_ssize_t
  316. zzip_file_write(ZZIP_FILE * file, const void *ptr, zzip_size_t len)
  317. {
  318. if (! _ZZIP_TRY)
  319. { /* not implemented */
  320. errno = EROFS;
  321. return -1;
  322. } else
  323. {
  324. /* add calls to zlib here... */
  325. errno = EROFS;
  326. return -1;
  327. }
  328. }
  329. /** => zzip_write
  330. * This function is the stdc variant for writing and the arguments
  331. * are forwarded to => zzip_write - the return value is floored to
  332. * null as for STDC spec but there is no zzip_ferror call so far
  333. * for the zziplib (later? is it actually needed?).
  334. *
  335. * This function is not yet implemented, check for #def ZZIP_NO_CREAT
  336. * Write-support extends => zzip_close with semantics to write out a
  337. * file-trailer to the zip-archive leaving a name/offset marker in
  338. * the (still-open) ZZIP_DIR handle.
  339. */
  340. zzip_size_t
  341. zzip_fwrite(const void *ptr, zzip_size_t len, zzip_size_t multiply,
  342. ZZIP_FILE * file)
  343. {
  344. zzip_ssize_t value = zzip_write(file, ptr, len * multiply);
  345. if (value == -1)
  346. value = 0;
  347. return (zzip_size_t) value;
  348. }
  349. #if 0 /* pure documentation */
  350. /** create a zipped file/directory also: zzip_dir_creat, mkdir(2)
  351. *
  352. * This function creates a directory entry in the default zip-archive.
  353. * If you did not specify a "#define zzip_savefile somevar"
  354. * then the default zip-archive is null and all directories are
  355. * created as real directories in the filesystem. This function is
  356. * really a preprocessor macro or preferably an inline function
  357. * around => zzip_file_mkdir, there is no such symbol generated
  358. * into the library. The prototype is modelled after the posix
  359. * => mkdir(2) call.
  360. #ifndef zzip_savefile
  361. #define zzip_savefile 0
  362. #endif
  363. #define zzip_mkdir(name,mode) \ -
  364. zzip_file_mkdir(zzip_savefile,name,mode)
  365. *
  366. */
  367. int inline
  368. zzip_mkdir(zzip_char_t * name, int o_mode)
  369. {
  370. return zzip_file_creat(zzip_savefile, name, mode);
  371. }
  372. #endif
  373. #if 0 /* pure documentation */
  374. /** => zzip_mkdir also: creat(2), zzip_start
  375. *
  376. * This function creates a file in the default zip-archive.
  377. * If you did not specify a "#define zzip_savefile somevar"
  378. * then the default zip-archive is null and all files are created
  379. * as real files. This function is really a preprocessor macro
  380. * or preferably an inline function around => zzip_file_creat,
  381. * there is no such symbol generated into the library. The prototype
  382. * is modelled after the posix => creat(2) call.
  383. #ifndef zzip_savefile
  384. #define zzip_savefile 0
  385. #endif
  386. #define zzip_creat(name,mode) \ -
  387. zzip_file_creat(zzip_savefile,name,mode)
  388. */
  389. ZZIP_FILE *inline
  390. zzip_creat(zzip_char_t * name, int o_mode)
  391. {
  392. return zzip_file_creat(zzip_savefile, name, mode);
  393. }
  394. #endif
  395. #if 0 /* pure documentation */
  396. /** start writing to the magic zzip_savefile also: zzip_creat, zzip_write
  397. *
  398. * open a zip archive for writing via the magic zzip_savefile macro
  399. * variable. The name and mode are given to => zzip_createdir and
  400. * the result is stored into => zzip_savefile - if the => zzip_savefile
  401. * did already have a zzip_dir handle then it is automatically
  402. * finalized with => zzip_sync and the handle closed and the
  403. * zzip_savefile variable reused for the new zip archive just started
  404. * with this call. - This function is really a preprocessor macro
  405. * or preferably an inline function around => zzip_dir_create, there
  406. * is no such symbol generated into the library.
  407. #ifndef zzip_savefile
  408. #define zzip_savefile 0
  409. #endif
  410. #define zzip_start(name,mode,ext) \ -
  411. { if (zzip_savefile) zzip_closedir(zzip_savefile); \ -
  412. zzip_savefile = zzip_createdir(name,mode,ext); }
  413. * This function returns null on error or a zzip_dir handle on
  414. * success. It is perfectly okay to continue with a null in the
  415. * zzip_savefile variable since it makes subsequent calls to
  416. * => zzip_creat and => zzip_mkdir to run as => creat(2) / => mkdir(2)
  417. * on the real filesystem.
  418. */
  419. void inline
  420. zzip_mkfifo(zzip_char_t * name, int o_mode)
  421. {
  422. if (zzip_savefile)
  423. zzip_closedir(zzip_savefile);
  424. zzip_savefile = zzip_createdir(name, o_mode);
  425. }
  426. #endif
  427. #if 0 /* pure documentation */
  428. /** => zzip_mkfifo also: zzip_closedir, sync(2)
  429. *
  430. * finalize a zip archive thereby writing the central directory to
  431. * the end of the file. If it was a real directory then we do just
  432. * nothing - even that the prototype of the call itself is modelled
  433. * to be similar to the posix => sync(2) call. This function is
  434. * really a preprocessor macro or preferably an inline function
  435. * around => zzip_closedir, there is no such symbol generated
  436. * into the library.
  437. #ifndef zzip_savefile
  438. #define zzip_savefile 0
  439. #endif
  440. #define zzip_sync(name,mode) \ -
  441. { zzip_closedir(zzip_savefile); zzip_savefile = 0; }
  442. *
  443. */
  444. void inline
  445. zzip_sync(void)
  446. {
  447. zzip_closedir(zzip_savefile);
  448. zzip_savefile = 0;
  449. }
  450. #endif
  451. /*
  452. * Local variables:
  453. * c-file-style: "stroustrup"
  454. * End:
  455. */