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