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