ut_compress_zlib_raw.c

Go to the documentation of this file.
00001 /*
00002  !concept {:name => "Simple file compression",
00003    :desc => "Straightforward file compression based on (raw) zlib."}
00004 */
00005 
00006 /*
00007   To decompress, use
00008     ./zpipe -d < compressed-file > plain-file
00009 
00010   To allow gunzip to be used, we might want to use its file format.
00011     http://en.wikipedia.org/wiki/Gzip#File_format
00012     http://tools.ietf.org/html/rfc1952
00013  */
00014 
00015 #include "ut_compress.h"
00016 
00017 #include "ac_app_context.h"
00018 #include "application_config.h"
00019 #include "er_errors.h"
00020 
00021 #include <zlib.h>
00022 
00023 #include <stdio.h>
00024 #include <string.h>
00025 #include <assert.h>
00026 
00027 #if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(__CYGWIN__)
00028 #  include <fcntl.h>
00029 #  include <io.h>
00030 #  define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY)
00031 #else
00032 #  define SET_BINARY_MODE(file)
00033 #endif
00034 
00035 // inBuf and outBuf must be at least this large.
00036 #define CHUNK (8 * 1024)
00037 
00038 /* Compress from file source to file dest until EOF on source.
00039    def() returns Z_OK on success, Z_MEM_ERROR if memory could not be
00040    allocated for processing, Z_STREAM_ERROR if an invalid compression
00041    level is supplied, Z_VERSION_ERROR if the version of zlib.h and the
00042    version of the library linked do not match, or Z_ERRNO if there is
00043    an error reading or writing the files. */
00044 static int def(FILE *source, FILE *dest, 
00045          int level,
00046          unsigned char* inBuf,
00047          unsigned char* outBuf)
00048 {
00049     int ret, flush;
00050     unsigned have;
00051     z_stream strm;
00052 
00053     /* allocate deflate state */
00054     strm.zalloc = Z_NULL;
00055     strm.zfree = Z_NULL;
00056     strm.opaque = Z_NULL;
00057     ret = deflateInit(&strm, level);
00058     if (ret != Z_OK)
00059         return ret;
00060 
00061     /* compress until end of file */
00062     do {
00063         strm.avail_in = fread(inBuf, 1, CHUNK, source);
00064         if (ferror(source)) {
00065             (void)deflateEnd(&strm);
00066             return Z_ERRNO;
00067         }
00068         flush = feof(source) ? Z_FINISH : Z_NO_FLUSH;
00069         strm.next_in = inBuf;
00070 
00071         /* run deflate() on input until output buffer not full, finish
00072            compression if all of source has been read in */
00073         do {
00074             strm.avail_out = CHUNK;
00075             strm.next_out = outBuf;
00076             ret = deflate(&strm, flush);    /* no bad return value */
00077             assert(ret != Z_STREAM_ERROR);  /* state not clobbered */
00078             have = CHUNK - strm.avail_out;
00079             if (fwrite(outBuf, 1, have, dest) != have || ferror(dest)) {
00080                 (void)deflateEnd(&strm);
00081                 return Z_ERRNO;
00082             }
00083         } while (strm.avail_out == 0);
00084         assert(strm.avail_in == 0);     /* all input will be used */
00085 
00086         /* done when last data in file processed */
00087     } while (flush != Z_FINISH);
00088     assert(ret == Z_STREAM_END);        /* stream will be complete */
00089 
00090     /* clean up and return */
00091     (void)deflateEnd(&strm);
00092     return Z_OK;
00093 }
00094 
00095 /* report a zlib or i/o error */
00096 static GError* zerr(int ret)
00097 {
00098     switch (ret) {
00099     case Z_ERRNO:
00100       return gx_error_new(domain_posix, errno, 
00101         "zlib: %s (%d)", strerror(errno), errno);
00102     case Z_STREAM_ERROR:
00103       return gx_error_new(domain_zlib, ret, 
00104         "zlib: invalid compression level");
00105     case Z_DATA_ERROR:
00106       return gx_error_new(domain_zlib, ret, 
00107         "zlib: invalid or incomplete deflate data");
00108     case Z_MEM_ERROR:
00109       return gx_error_new(domain_zlib, ret, "zlib: out of memory");
00110     case Z_VERSION_ERROR:
00111       return gx_error_new(domain_zlib, ret, "zlib version mismatch");
00112     default:
00113       return gx_error_new(domain_zlib, ret, "unexpected zlib error %d", ret);
00114     }
00115 }
00116 
00117 static gboolean compress_ft(const char* fs, const char* ft, GError** error)
00118 {
00119   unsigned char* inBuf = NULL;
00120   unsigned char* outBuf = NULL;
00121   FILE* inFd = NULL;
00122   FILE* outFd = NULL;
00123   gboolean ret = FALSE;
00124 
00125   inBuf = g_try_malloc(CHUNK);
00126   if (!inBuf) {
00127     if (error) *error = gx_error_no_memory;
00128     goto done;
00129   }
00130   outBuf = g_try_malloc(CHUNK);
00131   if (!outBuf) {
00132     if (error) *error = gx_error_no_memory;
00133     goto done;
00134   }
00135   inFd = fopen(fs, "r");
00136   if (!inFd) {
00137     if (error)
00138       *error = gx_error_new(domain_posix, errno, 
00139           "could not open file '%s' for reading: %s (%d)", 
00140           fs, strerror(errno), errno);
00141     goto done;
00142   }
00143   outFd = fopen(ft, "w+");
00144   if (!outFd) {
00145     if (error)
00146       *error = gx_error_new(domain_posix, errno, 
00147           "could not open file '%s' for writing: %s (%d)", 
00148           ft, strerror(errno), errno);
00149     goto done;
00150   }
00151 
00152   int zret = def(inFd, outFd, Z_DEFAULT_COMPRESSION, inBuf, outBuf);
00153   if (zret != Z_OK) {
00154     if (error) *error = zerr(zret);
00155     goto done;
00156   }
00157 
00158   ret = TRUE;
00159 
00160  done:
00161   g_free(inBuf);
00162   g_free(outBuf);
00163   fclose(inFd);
00164   fclose(outFd);
00165   return ret;
00166 }
00167 
00168 gboolean compress_file(const char* fn, GError** error)
00169 {
00170   char* ft = tempnam(LOG_UPLOADS_DIR, "zlog_"); // caller must free result
00171   if (!ft) {
00172     if (error)
00173       *error = gx_error_new(domain_posix, errno,
00174           "tempnam failed: %s (%d)",
00175           strerror(errno), errno);
00176     return FALSE;
00177   }
00178 
00179   if (!compress_ft(fn, ft, error)) {
00180     g_free(ft);
00181     return FALSE;
00182   }
00183 
00184   if (g_unlink(fn)) {
00185     if (error)
00186       *error = gx_error_new(G_FILE_ERROR, g_file_error_from_errno(errno), 
00187           "error deleting file '%s': %s (%d)", fn, 
00188           strerror(errno), errno);
00189     g_free(ft);
00190     return FALSE;
00191   }
00192 
00193   if (rename(ft, fn)) {
00194     if (error)
00195       *error = gx_error_new(domain_posix, errno, 
00196                             "failed to rename '%s' as '%s': %s (%d)", 
00197                             ft, fn, strerror(errno), errno);
00198     g_free(ft);
00199     return FALSE;
00200   }
00201 
00202   g_free(ft);
00203   
00204   return TRUE;
00205 }
00206 
00207 /**
00208 
00209 Copyright 2010 Helsinki Institute for Information Technology (HIIT)
00210 and the authors. All rights reserved.
00211 
00212 Authors: Tero Hasu <tero.hasu@hut.fi>
00213 
00214 Permission is hereby granted, free of charge, to any person
00215 obtaining a copy of this software and associated documentation files
00216 (the "Software"), to deal in the Software without restriction,
00217 including without limitation the rights to use, copy, modify, merge,
00218 publish, distribute, sublicense, and/or sell copies of the Software,
00219 and to permit persons to whom the Software is furnished to do so,
00220 subject to the following conditions:
00221 
00222 The above copyright notice and this permission notice shall be
00223 included in all copies or substantial portions of the Software.
00224 
00225 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
00226 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00227 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
00228 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
00229 BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
00230 ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
00231 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
00232 SOFTWARE.
00233 
00234  **/
00235 
00236 /* Some of the code is from zpipe.c.
00237 
00238    zpipe.c: example of proper use of zlib's inflate() and deflate()
00239    Not copyrighted -- provided to the public domain
00240    Version 1.4  11 December 2005  Mark Adler 
00241    retrieved from http://www.zlib.net/zpipe.c
00242 */
00243 
00244 /* Version history:
00245    1.0  30 Oct 2004  First version
00246    1.1   8 Nov 2004  Add void casting for unused return values
00247                      Use switch statement for inflate() return values
00248    1.2   9 Nov 2004  Add assertions to document zlib guarantees
00249    1.3   6 Apr 2005  Remove incorrect assertion in inf()
00250    1.4  11 Dec 2005  Add hack to avoid MSDOS end-of-line conversions
00251                      Avoid some compiler warnings for input and output buffers
00252  */

ContextLogger2—ContextLogger2 Logger Daemon Internals—Generated on Mon May 2 13:49:57 2011 by Doxygen 1.6.1