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.
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.
17 * Guido Draheim <guidod@gmx.de>
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
27 #define _ZZIP_WRITE_SOURCE
29 #if defined DDDD || defined DDDDD || defined DDDDDD || defined DDDDDDD
30 #define _ZZIP_ENABLE_WRITE
31 #else /* per default, we add support for passthrough to posix write */
32 #define _ZZIP_POSIX_WRITE
35 #include <zzip/write.h> /* #includes <zzip/lib.h> */
36 #include <zzip/file.h>
44 #ifdef ZZIP_HAVE_DIRECT_H
48 #include <zzip/format.h>
49 #include <zzip/plugin.h>
50 #include <zzip/__debug.h>
63 /* try real zlib routines for writing ? very experimental, very very ex... */
64 #ifndef _ZZIP_ENABLE_WRITE
70 /* btw, is there any system that did define those different ? get away.. */
72 # define S_IWGRP 00020
75 # define S_IRWXO 00007
78 # ifdef ZZIP_HAVE_DIRECT_H
79 # define _mkdir(a,b) mkdir(a)
84 /** create a new zip archive for writing
86 * This function will create a new zip archive. The returned parameter
87 * is a new "zzip dir" handle that should be saved to a variable so it
88 * can be used a base argument for => zzip_mkdir and => zzip_creat calls.
89 * The returned handle represents a zip central directory that must be
90 * saved to disk using => zzip_closedir.
92 * Returns null on error and sets errno. Remember, according to posix
93 * the => creat(2) call is equivalent to
94 open (path, O_WRONLY | O_CREAT | O_TRUNC, o_mode)
95 * so any previous zip-archive will be overwritten unconditionally and
96 * EEXIST errors from => mkdir(2) are suppressed. (fixme: delete the
97 * given subtree? like suggested by O_TRUNC? not done so far!)
100 zzip_dir_creat(zzip_char_t* name, int o_mode)
102 return zzip_dir_creat_ext_io (name, o_mode, 0, 0);
105 /** => zzip_dir_creat
107 * If the third argument "ext" has another special meaning here, as it
108 * is used to ensure that a given zip-file is created with the first entry
109 * of the ext-list appended as an extension unless the file-path already
110 * ends with a file-extension registered in the list. Therefore {"",0}
111 * matches all files and creates them as zip-archives under the given
112 * nonmodified name. (Some magic here? If the path ends in the path
113 * separator then make a real directory even in the presence of ext-list?)
115 * This function is not yet implemented, check for #def ZZIP_NO_CREAT
116 * Write-support will extend => zzip_closedir with semantics to finalize the
117 * zip-archive by writing the zip-trailer and closing the archive file.
120 zzip_dir_creat_ext_io(zzip_char_t* name, int o_mode,
121 zzip_strings_t* ext, zzip_plugin_io_t io)
123 if (! io) io = zzip_get_default_io ();
125 if (io != zzip_get_default_io())
126 { /* the current io-structure does not contain a "write" entry,
127 * and therefore this parameter is useless. Anyone to expect
128 * some behavior should be warned, so here we let the function
129 * fail bluntly - and leaving the recovery to the application
137 { /* not implemented - however, we respect that a null argument to
138 * zzip_mkdir and zzip_creat works, so we silently still do the mkdir
140 if (! _mkdir (name, o_mode) || errno == EEXIST)
144 # define MAX_EXT_LEN 10
145 ZZIP_DIR* dir = zzip_dir_alloc (ext);
146 int name_len = strlen(name);
147 dir->realname = malloc (name_len+MAX_EXT_LEN);
148 if (! dir->realname) goto error;
150 memcpy (dir->realname, name, name_len+1);
151 ___ int fd = __zzip_try_open (
152 dir->realname, O_EXCL|O_TRUNC|O_WRONLY, ext, io);
153 if (fd != -1) { dir->fd = fd; return dir; }
155 ___ zzip_strings_t* exx = ext; int exx_len;
158 if ((exx_len = strlen (*exx)+1) <= name_len &&
159 !memcmp (dir->realname+(name_len-exx_len), *exx, exx_len))
160 break; /* keep unmodified */
161 exx++; if (*exx) continue;
163 if (! (exx_len = strlen (*exx)) || exx_len >= MAX_EXT_LEN) break;
164 memcpy (dir->realname+name_len, exx, exx_len); /* append! */
166 fd = io->fd.open (dir->realname, O_CREAT|O_TRUNC|O_WRONLY, o_mode);
167 dir->realname[name_len] = '\0'; /* keep ummodified */
168 if (fd != -1) { dir->fd = fd; return dir; }
170 zzip_dir_free (dir); return 0;
175 /** create a new archive area for writing
177 * This function will create a new archive area. This may either be a
178 * a new zip archive or a new directory in the filesystem. The returned
179 * parameter is a new "zzip dir" handle that should be saved to a variable
180 * so it can be used a base argument for => zzip_file_mkdir and
181 * => zzip_file_creat calls. The returned handle wraps both possibilities,
182 * it can be representing a zip central directory that must be
183 * saved to disk using => zzip_closedir or it is just a handle for the
184 * name of the real directory that still must be run through
185 * => zzip_closedir to release the wrapper around the directory name.
187 * The magic is pushed through the o_mode argument. Using a mode that
188 * has no group-write bit set (S_IWGRP = 0040) then the file is
189 * created as a zip directory. Note that this is unabridged of any
190 * umask value in the system where the argument to this function could
191 * be 0775 but with an umask of 0755 it turns out as 0755 for a real
192 * directory. Using 0755 directly would not create it as a real directory
193 * but as a zip archive handle.
195 * This function is not yet implemented, check for #def ZZIP_NO_CREAT
196 * Write-support will extend => zzip_closedir with semantics to finalize the
197 * zip-archive by writing the zip-trailer and closing the archive file.
199 * Returns null on error and sets errno. Remember, according to posix
200 * the => creat(2) call is equivalent to
201 open (path, O_WRONLY | O_CREAT | O_TRUNC, o_mode)
202 * so any previous zip-archive will be overwritten unconditionally and
203 * EEXIST errors from => mkdir(2) are suppressed. (fixme: delete the
204 * given subtree? like suggested by O_TRUNC? not done so far!)
207 zzip_createdir(zzip_char_t* name, int o_mode)
209 if (o_mode & S_IWGRP)
211 if (-1 == _mkdir(name, o_mode) && errno != EEXIST) /* fail */
213 return zzip_opendir (name);
215 return zzip_dir_creat (name, o_mode);
218 /** => zzip_file_creat also: mkdir(2), creat(2), zzip_dir_creat
220 * This function has an additional primary argument over the posix
221 * mkdir(2) - if it is null then this function behaves just like
222 * posix mkdir(2). The zzip_dir argument can be set to the result
223 * of a => zzip_createdir which allows for some magic that the
224 * given directory name is created as an entry in the zip archive.
226 * If the given dir name argument is not within the basepath of
227 * the zip central directory then a real directory is created.
228 * Any EEXIST errors are not suppressed unlike with => zzip_createdir
230 * Standard usage accepts a global/threaded/modular ZZIP_DIR pointer
231 * for all zip archive operations like in:
232 ZZIP_DIR* zip = zzip_createdir (sysconfpath, 0755, zip);
233 zzip_file_mkdir (zip, filepath[i], 0755);
234 ZZIP_FILE* file = zzip_file_creat (zip, filename[i], 0644);
235 zzip_write (file, buf, len);
236 zzip_close (file); file = 0;
237 zzip_closedir (zip); zip = 0;
239 * compare with => zzip_mkdir inline macro which allows to
240 * collapse the examples script to
241 #define zzip_savefile myproject_saveconfig
242 #include <zzip/zzip.h>
243 ZZIP_DIR* zzip_savefile = zzip_createdir (sysconfpath, 0755);
244 zzip_mkdir (filepath[i], 0755);
245 ZZIP_FILE* file = zzip_creat(filepath[i], 0644);
246 zzip_write (file, buf, len);
247 zzip_close (file); file = 0;
248 zzip_closedir (zip_savefile);
251 zzip_file_mkdir(ZZIP_DIR* dir, zzip_char_t* name, int o_mode)
254 return _mkdir(name, o_mode);
257 {/* not implemented */
266 /** start next file entry in a zip archive
268 * This function will create a new file within a zzip archive, the
269 * one given as the primary argument and additionally to the posix
270 * creat(2) - just like zzip_mkdir has an additional argument over
271 * the posix mkdir(2) spec. For this function the primary parameter
272 * can be null as well thereby creating a real file instead of a new
273 * one inside the zip-archive otherwise given. If the primary parameter is
274 * not null but wraps a real directory then all new files are also real.
276 * This function is not yet implemented, check for #def ZZIP_NO_CREAT
278 * Returns NULL on an error setting errno, and opening a file _within_
279 * a zip archive using O_RDONLY (and similar stuff) will surely lead to
283 zzip_file_creat(ZZIP_DIR* dir, zzip_char_t* name, int o_mode)
286 return zzip_open (name, o_mode);
289 {/* not implemented */
298 /** write to zzip storage also: write(2), zlib(3)
300 * This function will write data to a file descriptor. If the file
301 * descriptor represents a real file then it will be forwarded to
302 * call posix => write(2) directly. If it is a descriptor for a
303 * file within a zip directory then the data will be "deflated"
304 * using => zlib(3) and appended to the zip archive file.
307 zzip_write(ZZIP_FILE* file, const void* ptr, zzip_size_t len)
309 if (zzip_file_real(file))
310 return write (zzip_realfd (file), ptr, len);
312 return zzip_file_write (file, ptr, len);
315 /** => zzip_write also: zzip_file_creat
317 * This function will write data to a file descriptor inside a zip
318 * archive. The data will be "deflated" using => zlib(3) compression
319 * and appended to the end of the zip archive file. Only one file
320 * descriptor may be open per zzip_dir archive handle (fifo-like).
322 * This function is not yet implemented, check for #def ZZIP_NO_CREAT
323 * It returns immediately -1 and sets errno=EROFS for indication.
326 zzip_file_write(ZZIP_FILE* file, const void* ptr, zzip_size_t len)
329 {/* not implemented */
333 /* add calls to zlib here... */
340 * This function is the stdc variant for writing and the arguments
341 * are forwarded to => zzip_write - the return value is floored to
342 * null as for STDC spec but there is no zzip_ferror call so far
343 * for the zziplib (later? is it actually needed?).
345 * This function is not yet implemented, check for #def ZZIP_NO_CREAT
346 * Write-support extends => zzip_close with semantics to write out a
347 * file-trailer to the zip-archive leaving a name/offset marker in
348 * the (still-open) ZZIP_DIR handle.
351 zzip_fwrite(const void* ptr, zzip_size_t len, zzip_size_t multiply,
354 zzip_ssize_t value = zzip_write (file, ptr, len * multiply);
357 return (zzip_size_t) value;
360 #if 0 /* pure documentation */
361 /** create a zipped file/directory also: zzip_dir_creat, mkdir(2)
363 * This function creates a directory entry in the default zip-archive.
364 * If you did not specify a "#define zzip_savefile somevar"
365 * then the default zip-archive is null and all directories are
366 * created as real directories in the filesystem. This function is
367 * really a preprocessor macro or preferably an inline function
368 * around => zzip_file_mkdir, there is no such symbol generated
369 * into the library. The prototype is modelled after the posix
371 #ifndef zzip_savefile
372 #define zzip_savefile 0
374 #define zzip_mkdir(name,mode) \ -
375 zzip_file_mkdir(zzip_savefile,name,mode)
379 zzip_mkdir(zzip_char_t* name, int o_mode)
381 return zzip_file_creat(zzip_savefile, name, mode);
385 #if 0 /* pure documentation */
386 /** => zzip_mkdir also: creat(2), zzip_start
388 * This function creates a file in the default zip-archive.
389 * If you did not specify a "#define zzip_savefile somevar"
390 * then the default zip-archive is null and all files are created
391 * as real files. This function is really a preprocessor macro
392 * or preferably an inline function around => zzip_file_creat,
393 * there is no such symbol generated into the library. The prototype
394 * is modelled after the posix => creat(2) call.
395 #ifndef zzip_savefile
396 #define zzip_savefile 0
398 #define zzip_creat(name,mode) \ -
399 zzip_file_creat(zzip_savefile,name,mode)
402 zzip_creat(zzip_char_t* name, int o_mode)
404 return zzip_file_creat(zzip_savefile, name, mode);
409 #if 0 /* pure documentation */
410 /** start writing to the magic zzip_savefile also: zzip_creat, zzip_write
412 * open a zip archive for writing via the magic zzip_savefile macro
413 * variable. The name and mode are given to => zzip_createdir and
414 * the result is stored into => zzip_savefile - if the => zzip_savefile
415 * did already have a zzip_dir handle then it is automatically
416 * finalized with => zzip_sync and the handle closed and the
417 * zzip_savefile variable reused for the new zip archive just started
418 * with this call. - This function is really a preprocessor macro
419 * or preferably an inline function around => zzip_dir_create, there
420 * is no such symbol generated into the library.
421 #ifndef zzip_savefile
422 #define zzip_savefile 0
424 #define zzip_start(name,mode,ext) \ -
425 { if (zzip_savefile) zzip_closedir(zzip_savefile); \ -
426 zzip_savefile = zzip_createdir(name,mode,ext); }
427 * This function returns null on error or a zzip_dir handle on
428 * success. It is perfectly okay to continue with a null in the
429 * zzip_savefile variable since it makes subsequent calls to
430 * => zzip_creat and => zzip_mkdir to run as => creat(2) / => mkdir(2)
431 * on the real filesystem.
434 zzip_mkfifo(zzip_char_t* name, int o_mode)
436 if (zzip_savefile) zzip_closedir (zzip_savefile);
437 zzip_savefile = zzip_createdir(name, o_mode);
441 #if 0 /* pure documentation */
442 /** => zzip_mkfifo also: zzip_closedir, sync(2)
444 * finalize a zip archive thereby writing the central directory to
445 * the end of the file. If it was a real directory then we do just
446 * nothing - even that the prototype of the call itself is modelled
447 * to be similar to the posix => sync(2) call. This function is
448 * really a preprocessor macro or preferably an inline function
449 * around => zzip_closedir, there is no such symbol generated
451 #ifndef zzip_savefile
452 #define zzip_savefile 0
454 #define zzip_sync(name,mode) \ -
455 { zzip_closedir(zzip_savefile); zzip_savefile = 0; }
461 zzip_closedir (zzip_savefile); zzip_savefile = 0;
467 * c-file-style: "stroustrup"