ZZIP_FILE* zzip_open_shared_io (ZZIP_FILE* stream, zzip_char_t* filename, int o_flags, int o_modes, zzip_strings_t* ext, zzip_plugin_io_t io) { if (stream && stream->dir) { if (! ext) ext = stream->dir->fileext; if (! io) io = stream->dir->io; } if (! io) io = zzip_get_default_io (); if (o_modes & (ZZIP_PREFERZIP|ZZIP_ONLYZIP)) goto try_zzip; try_real: /* prefer an existing real file */ { zzip_plugin_io_t os = (o_modes & ZZIP_ALLOWREAL) ? zzip_get_default_io () : io; int fd = os->fd.open(filename, o_flags); /* io->fd.open */ if (fd != -1) { #if !defined(WINDOWSPC) || defined(__MINGW32__) struct stat st; // JMW #endif ZZIP_FILE* fp = calloc (1, sizeof(ZZIP_FILE)); if (! fp) { os->fd.close(fd); return 0; } /* io->fd.close */ fp->dir = NULL; fp->fd = fd; fp->io = os; #if !defined(WINDOWSPC) || defined(__MINGW32__) if (stat(filename,&st) >=0) fp->usize = st.st_size; #else fp->usize = os->fd.filesize(fd); #endif return fp; } if (o_modes & ZZIP_PREFERZIP) { return 0; } } try_zzip: /* if the user had it in place of a normal xopen, then * we better defend this lib against illegal usage */ if (o_flags & (O_CREAT|O_WRONLY)) { errno = EINVAL; return 0; } if (o_flags & (O_RDWR)) { o_flags ^= O_RDWR; o_flags |= O_RDONLY; } /* this is just for backward compatibility -and strictly needed to * prepare ourselves for more options and more options later on... */ /*# if (o_modes & ZZIP_CASELESS) { o_flags |= ZZIP_CASEINSENSITIVE; } */ /*# if (o_modes & ZZIP_NOPATHS) { o_flags |= ZZIP_IGNOREPATH; } */ /* see if we can open a file that is a zip file */ { char basename[PATH_MAX]; char* p; int filename_len = strlen (filename); if (filename_len >= PATH_MAX) { #ifdef ENAMETOOLONG errno = ENAMETOOLONG; #endif return 0; } memcpy (basename, filename, filename_len+1); /* see if we can share the same zip directory */ if (stream && stream->dir && stream->dir->realname) { zzip_size_t len = strlen (stream->dir->realname); if (! memcmp (filename, stream->dir->realname, len) && ((filename[len] == '/') || (filename[len] == '\\')) && filename[len+1]) { ZZIP_FILE* fp = zzip_file_open (stream->dir, filename+len+1, o_modes); if (! fp) { errno = zzip_errno (stream->dir->errcode); } return fp; } } /* per each slash in filename, check if it there is a zzip around */ while ((p = strrchr (basename, '/')) || (p = strrchr (basename, '\\'))) { zzip_error_t e = 0; ZZIP_DIR* dir; ZZIP_FILE* fp; int fd; *p = '\0'; /* cut at path separator == possible zipfile basename */ fd = __zzip_try_open (basename, o_flags|O_RDONLY|O_BINARY, ext, io); if (fd == -1) { continue; } /* found: */ /* found zip-file, now try to parse it */ dir = zzip_dir_fdopen_ext_io(fd, &e, ext, io); if (e) { errno = zzip_errno(e); io->fd.close(fd); return 0; } /* (p - basename) is the lenghtof zzip_dir part of the filename */ fp = zzip_file_open(dir, filename + (p - basename) +1, o_modes); if (! fp) { errno = zzip_errno(dir->errcode); } else { if (! dir->realname) dir->realname = strdup (basename); } zzip_dir_close(dir); /* note: since (fp) is attached that (dir) will survive */ /* but (dir) is implicitly closed on next zzip_close(fp) */ return fp; } /*again*/ if (o_modes & ZZIP_PREFERZIP) goto try_real; errno = ENOENT; return 0; } }
/** => zzip_dir_creat * * If the third argument "ext" has another special meaning here, as it * is used to ensure that a given zip-file is created with the first entry * of the ext-list appended as an extension unless the file-path already * ends with a file-extension registered in the list. Therefore {"",0} * matches all files and creates them as zip-archives under the given * nonmodified name. (Some magic here? If the path ends in the path * separator then make a real directory even in the presence of ext-list?) * * This function is not yet implemented, check for #def ZZIP_NO_CREAT * Write-support will extend => zzip_closedir with semantics to finalize the * zip-archive by writing the zip-trailer and closing the archive file. */ ZZIP_DIR * zzip_dir_creat_ext_io(zzip_char_t * name, int o_mode, zzip_strings_t * ext, zzip_plugin_io_t io) { if (! io) io = zzip_get_default_io(); if (io != zzip_get_default_io()) { /* the current io-structure does not contain a "write" entry, * and therefore this parameter is useless. Anyone to expect * some behavior should be warned, so here we let the function * fail bluntly - and leaving the recovery to the application */ errno = EINVAL; return 0; } if (! _ZZIP_TRY) { /* not implemented - however, we respect that a null argument to * zzip_mkdir and zzip_creat works, so we silently still do the mkdir */ if (! _mkdir(name, o_mode) || errno == EEXIST) errno = EROFS; return 0; } else { # define MAX_EXT_LEN 10 ZZIP_DIR *dir = zzip_dir_alloc(ext); int name_len = strlen(name); dir->realname = malloc(name_len + MAX_EXT_LEN); if (! dir->realname) goto error; memcpy(dir->realname, name, name_len + 1); ___ int fd = __zzip_try_open(dir->realname, O_EXCL | O_TRUNC | O_WRONLY, ext, io); if (fd != -1) { dir->fd = fd; return dir; } ___ zzip_strings_t *exx = ext; int exx_len; for (; *exx; exx++) { if ((exx_len = strlen(*exx) + 1) <= name_len && ! memcmp(dir->realname + (name_len - exx_len), *exx, exx_len)) break; /* keep unmodified */ exx++; if (*exx) continue; if (! (exx_len = strlen(*exx)) || exx_len >= MAX_EXT_LEN) break; memcpy(dir->realname + name_len, exx, exx_len); /* append! */ } ____; fd = (io->fd.open)(dir->realname, O_CREAT | O_TRUNC | O_WRONLY, o_mode); dir->realname[name_len] = '\0'; /* keep ummodified */ if (fd != -1) { dir->fd = fd; return dir; } error: zzip_dir_free(dir); return 0; ____; } }