PageRenderTime 20ms CodeModel.GetById 7ms app.highlight 8ms RepoModel.GetById 1ms app.codeStats 0ms

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