/** * @file zlib.c Zlib module * * $Id: zlib.c,v 1.35 2003/01/04 19:14:15 chipx86 Exp $ * * @Copyright (C) 2001-2003 The GNUpdate Project. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include #include #include #include "utils.h" typedef struct { char *path; FILE *fp; gzFile gzfp; } CxZData; #if 0 static char gzMagic[2] = { 0x1F, 0x8B }; #endif static size_t __readFunc(void *ptr, size_t size, size_t nmemb, CxFP *fp) { size_t result; gzFile gzfp = (gzFile)fp->moduleData; result = gzread(gzfp, ptr, size * nmemb); if (result == -1) { int errnum; const char *errstr; errstr = gzerror(gzfp, &errnum); cxSetError(fp, errnum, errstr); return 0; } return (result / size); } static size_t __writeFunc(const void *ptr, size_t size, size_t nmemb, CxFP *fp) { size_t result; gzFile gzfp = (gzFile)fp->moduleData; result = gzwrite(gzfp, (const voidp)ptr, size * nmemb); if (result == -1) { int errnum; const char *errstr; errstr = gzerror(gzfp, &errnum); cxSetError(fp, errnum, errstr); return 0; } return (result / size); } static void __seekFunc(CxFP *fp, long offset, int whence) { gzseek((gzFile)fp->moduleData, (z_off_t)offset, whence); } static void __closeFunc(CxFP *fp) { fp->moduleData = NULL; } static char * __extractFp(CxFP *fp) { size_t s; char buffer[4096]; FILE *outFp; char *filename; filename = cxMakeTempFilename(); outFp = fopen(filename, "w"); if (outFp == NULL) { free(filename); return NULL; } while ((s = cxRead(buffer, sizeof(char), 4096, fp)) > 0) fwrite(buffer, sizeof(char), s, outFp); fclose(outFp); return filename; } static char * __writeCompressed(CxFile *file) { size_t s; char buffer[4096]; CxFP *inFp; gzFile outFp; char *filename; /* Open the file. */ inFp = cxOpenFile(cxGetFilePhysicalPath(file), CX_MODE_READ_ONLY | CX_MODE_RAW); if (inFp == NULL) return NULL; filename = cxMakeTempFilename(); outFp = gzopen(filename, "wb"); if (outFp == NULL) { free(filename); return NULL; } while ((s = cxRead(buffer, 1, 4096, inFp)) > 0) gzwrite(outFp, buffer, s); gzclose(outFp); cxClose(inFp); return filename; } static CxStatus readArchive(CxArchive *archive, CxFP *afp) { FILE *fp; gzFile gzfp; CxFile *file; char *temp; char *path; CxZData *zData; /* Necessary hack. */ path = __extractFp(afp); if (path == NULL) return CX_ERROR; /* Open the file. */ fp = fopen(path, "rb"); if (fp == NULL) { unlink(path); free(path); return CX_FILE_NOT_FOUND; } gzfp = gzdopen(fileno(fp), "rb"); if (gzfp == NULL || gzeof(gzfp)) { /* * libcomprex ensures that the file exists. * This is some other error. */ if (gzfp != NULL) gzclose(gzfp); fclose(fp); unlink(path); free(path); return CX_ERROR; } if (((_gz_stream *)gzfp)->transparent == 1) { /* It's not a .gz! Clean up so other modules can try... */ gzclose(gzfp); fclose(fp); unlink(path); free(path); return CX_INVALID_FORMAT; } /* Set the total size of this archive's contents. */ archive->archiveSize = __getTotalFileSize(fp); /* Add the contained file. */ file = cxNewFile(); temp = __makeOutputFilename(cxGetArchiveFileName(archive)); cxSetFileName(file, temp); free(temp); cxSetFileSize(file, archive->archiveSize); cxDirAddFile(cxGetArchiveRoot(archive), file); /* This is always a single-file archive. */ cxSetArchiveType(archive, CX_ARCHIVE_SINGLE); /* Store the path in moduleData */ MEM_CHECK(zData = (CxZData *)malloc(sizeof(CxZData))); zData->path = path; zData->gzfp = gzfp; zData->fp = fp; archive->moduleData = zData; return CX_SUCCESS; } static CxStatus saveArchive(CxArchive *archive, CxFP *fp) { CxFile *file; FILE *inFp; char *tempfile; char buffer[4096]; size_t s; if ((file = cxGetFirstFile(cxGetArchiveRoot(archive))) == NULL) return CX_ERROR; if ((tempfile = __writeCompressed(file)) == NULL) return CX_ERROR; /* Read the file back in. */ inFp = fopen(tempfile, "rb"); while ((s = fread(buffer, 1, 4096, inFp)) > 0) cxWrite(buffer, 1, s, fp); fclose(inFp); free(tempfile); #if 0 /* Create the input buffer. */ inlen = cxGetFileSize(file); MEM_CHECK(inbuf = (Bytef *)malloc(inlen * sizeof(Bytef))); /* Read in the file. */ cxRead(inbuf, 1, inlen, inFp); /* Close up. We don't need this anymore. */ cxClose(inFp); /* Compress the data. */ MEM_CHECK(outbuf = (Bytef *)malloc((inlen * 1.01) + 12)); r = compress(outbuf, &outlen, inbuf, inlen); free(inbuf); /* Write the gzip header. */ now = time(NULL); snprintf(header, 10, "%c%c%c%c%lu%c%c", gzMagic[0], gzMagic[1], Z_DEFLATED, 0, mktime(localtime(&now)), 0, OS_CODE); cxWrite(header, 1, 10, fp); /* Write the compressed data. */ cxWrite(outbuf, 1, outlen, fp); free(outbuf); #endif return CX_SUCCESS; } static void closeArchive(CxArchive *archive) { if (archive->moduleData != NULL) { CxZData *data = (CxZData *)archive->moduleData; gzclose(data->gzfp); fclose(data->fp); unlink(data->path); free(data->path); free(data); archive->moduleData = NULL; } } static CxFP * openFile(CxFile *file, CxAccessMode mode) { CxArchive *archive = NULL; CxFP *fp; if (!CX_IS_MODE_READ_ONLY(mode)) return NULL; /* Open the file. */ archive = cxGetFileArchive(file); fp = cxNewFp(); fp->moduleData = ((CxZData *)archive->moduleData)->gzfp; cxSetReadFunc(fp, __readFunc); cxSetWriteFunc(fp, __writeFunc); cxSetSeekFunc(fp, __seekFunc); cxSetCloseFunc(fp, __closeFunc); gzseek((gzFile)fp->moduleData, 0, SEEK_SET); return fp; } static void destroyFile(CxFile *file) { } static char supportsExtension(const char *ext) { if (!strcasecmp(ext, "gz") || !strcasecmp(ext, "Z") || !strcasecmp(ext, "taz") || !strcasecmp(ext, "tgz")) { return 1; } return 0; } static CxArchiveOps ops = { readArchive, /* openArchive */ saveArchive, /* saveArchive */ closeArchive, /* closeArchive */ openFile, /* openFile */ destroyFile, /* destroyFile */ supportsExtension /* supportsExtension */ }; static void __moduleInit(CxModuleType type) { } CX_INIT_ARCHIVE_MODULE(zlib, __moduleInit, ops)