| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424 |
- /*
- * compress.c -- part of compress.mod
- * uses the compression library libz to compress and uncompress the
- * userfiles during the sharing process
- *
- * Written by Fabian Knittel <fknittel@gmx.de>. Based on zlib examples
- * by Jean-loup Gailly and Miguel Albrecht.
- *
- */
- /*
- * Copyright (C) 2000, 2001, 2002 Eggheads Development Team
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
- #define MODULE_NAME "compress"
- #define MAKING_COMPRESS
- #include <string.h>
- #include <errno.h>
- #include "src/mod/module.h"
- #include "share.mod/share.h"
- #ifdef HAVE_MMAP
- # include <sys/types.h>
- # include <sys/mman.h>
- # include <sys/stat.h>
- #endif /* HAVE_MMAP */
- #include "compress.h"
- #define BUFLEN 512
- static Function *global = NULL,
- *share_funcs = NULL;
- static unsigned int compressed_files; /* Number of files compressed. */
- static unsigned int uncompressed_files; /* Number of files uncompressed. */
- static unsigned int share_compressed = 1; /* Compress userfiles when sharing? */
- static unsigned int compress_level = 9; /* Default compression used. */
- static int uncompress_to_file(char *f_src, char *f_target);
- static int compress_to_file(char *f_src, char *f_target, int mode_num);
- static int compress_file(char *filename, int mode_num);
- static int uncompress_file(char *filename);
- static int is_compressedfile(char *filename);
- #include "tclcompress.c"
- /*
- * Misc functions.
- */
- static int is_compressedfile(char *filename)
- {
- char buf1[50], buf2[50];
- FILE *fin;
- register int len1, len2, i;
- egg_memset(buf1, 0, 50);
- egg_memset(buf2, 0, 50);
- if (!is_file(filename))
- return COMPF_FAILED;
- /* Read data with zlib routines.
- */
- fin = gzopen(filename, "rb");
- if (!fin)
- return COMPF_FAILED;
- len1 = gzread(fin, buf1, sizeof(buf1));
- if (len1 < 0)
- return COMPF_FAILED;
- if (gzclose(fin) != Z_OK)
- return COMPF_FAILED;
- /* Read raw data.
- */
- fin = fopen(filename, "rb");
- if (!fin)
- return COMPF_FAILED;
- len2 = fread(buf2, 1, sizeof(buf2), fin);
- if (ferror(fin))
- return COMPF_FAILED;
- fclose(fin);
- /* Compare what we found.
- */
- if (len1 != len2)
- return COMPF_COMPRESSED;
- for (i = 0; i < sizeof(buf1); i++)
- if (buf1[i] != buf2[i])
- return COMPF_COMPRESSED;
- return COMPF_UNCOMPRESSED;
- }
- /*
- * General compression / uncompression functions
- */
- /* Uncompresses a file `f_src' and saves it as `f_target'.
- */
- static int uncompress_to_file(char *f_src, char *f_target)
- {
- char buf[BUFLEN];
- int len;
- FILE *fin, *fout;
- if (!is_file(f_src)) {
- putlog(LOG_MISC, "*", "Failed to uncompress file `%s': not a file.",
- f_src);
- return COMPF_ERROR;
- }
- fin = gzopen(f_src, "rb");
- if (!fin) {
- putlog(LOG_MISC, "*", "Failed to uncompress file `%s': gzopen failed.",
- f_src);
- return COMPF_ERROR;
- }
- fout = fopen(f_target, "wb");
- if (!fout) {
- putlog(LOG_MISC, "*", "Failed to uncompress file `%s': open failed: %s.",
- f_src, strerror(errno));
- return COMPF_ERROR;
- }
- while (1) {
- len = gzread(fin, buf, sizeof(buf));
- if (len < 0) {
- putlog(LOG_MISC, "*", "Failed to uncompress file `%s': gzread failed.",
- f_src);
- return COMPF_ERROR;
- }
- if (!len)
- break;
- if ((int) fwrite(buf, 1, (unsigned int) len, fout) != len) {
- putlog(LOG_MISC, "*", "Failed to uncompress file `%s': fwrite failed: %s.",
- f_src, strerror(errno));
- return COMPF_ERROR;
- }
- }
- if (fclose(fout)) {
- putlog(LOG_MISC, "*", "Failed to uncompress file `%s': fclose failed: %s.",
- f_src, strerror(errno));
- return COMPF_ERROR;
- }
- if (gzclose(fin) != Z_OK) {
- putlog(LOG_MISC, "*", "Failed to uncompress file `%s': gzclose failed.",
- f_src);
- return COMPF_ERROR;
- }
- uncompressed_files++;
- return COMPF_SUCCESS;
- }
- /* Enforce limits.
- */
- inline static void adjust_mode_num(int *mode)
- {
- if (*mode > 9)
- *mode = 9;
- else if (*mode < 0)
- *mode = 0;
- }
- #ifdef HAVE_MMAP
- /* Attempt to compress in one go, by mmap'ing the file to memory.
- */
- static int compress_to_file_mmap(FILE *fout, FILE *fin)
- {
- int len, ifd = fileno(fin);
- char *buf;
- struct stat st;
- /* Find out size of file */
- if (fstat(ifd, &st) < 0)
- return COMPF_ERROR;
- if (st.st_size <= 0)
- return COMPF_ERROR;
- /* mmap file contents to memory */
- buf = mmap(0, st.st_size, PROT_READ, MAP_SHARED, ifd, 0);
- if (buf < 0)
- return COMPF_ERROR;
- /* Compress the whole file in one go */
- len = gzwrite(fout, buf, st.st_size);
- if (len != (int) st.st_size)
- return COMPF_ERROR;
- munmap(buf, st.st_size);
- fclose(fin);
- if (gzclose(fout) != Z_OK)
- return COMPF_ERROR;
- return COMPF_SUCCESS;
- }
- #endif /* HAVE_MMAP */
- /* Compresses a file `f_src' and saves it as `f_target'.
- */
- static int compress_to_file(char *f_src, char *f_target, int mode_num)
- {
- char buf[BUFLEN], mode[5];
- FILE *fin, *fout;
- int len;
- adjust_mode_num(&mode_num);
- egg_snprintf(mode, sizeof mode, "wb%d", mode_num);
- if (!is_file(f_src)) {
- putlog(LOG_MISC, "*", "Failed to compress file `%s': not a file.",
- f_src);
- return COMPF_ERROR;
- }
- fin = fopen(f_src, "rb");
- if (!fin) {
- putlog(LOG_MISC, "*", "Failed to compress file `%s': open failed: %s.",
- f_src, strerror(errno));
- return COMPF_ERROR;
- }
- fout = gzopen(f_target, mode);
- if (!fout) {
- putlog(LOG_MISC, "*", "Failed to compress file `%s': gzopen failed.",
- f_src);
- return COMPF_ERROR;
- }
- #ifdef HAVE_MMAP
- if (compress_to_file_mmap(fout, fin) == COMPF_SUCCESS) {
- compressed_files++;
- return COMPF_SUCCESS;
- } else {
- /* To be on the safe side, close the file before attempting
- * to write again.
- */
- gzclose(fout);
- fout = gzopen(f_target, mode);
- }
- #endif /* HAVE_MMAP */
- while (1) {
- len = fread(buf, 1, sizeof(buf), fin);
- if (ferror(fin)) {
- putlog(LOG_MISC, "*", "Failed to compress file `%s': fread failed: %s",
- f_src, strerror(errno));
- return COMPF_ERROR;
- }
- if (!len)
- break;
- if (gzwrite(fout, buf, (unsigned int) len) != len) {
- putlog(LOG_MISC, "*", "Failed to compress file `%s': gzwrite failed.",
- f_src);
- return COMPF_ERROR;
- }
- }
- fclose(fin);
- if (gzclose(fout) != Z_OK) {
- putlog(LOG_MISC, "*", "Failed to compress file `%s': gzclose failed.",
- f_src);
- return COMPF_ERROR;
- }
- compressed_files++;
- return COMPF_SUCCESS;
- }
- /* Compresses a file `filename' and saves it as `filename'.
- */
- static int compress_file(char *filename, int mode_num)
- {
- char *temp_fn, randstr[5];
- int ret;
- /* Create temporary filename. */
- temp_fn = nmalloc(strlen(filename) + 5);
- make_rand_str(randstr, 4);
- strcpy(temp_fn, filename);
- strcat(temp_fn, randstr);
- /* Compress file. */
- ret = compress_to_file(filename, temp_fn, mode_num);
- /* Overwrite old file with compressed version. Only do so
- * if the compression routine succeeded.
- */
- if (ret == COMPF_SUCCESS)
- movefile(temp_fn, filename);
- nfree(temp_fn);
- return ret;
- }
- /* Uncompresses a file `filename' and saves it as `filename'.
- */
- static int uncompress_file(char *filename)
- {
- char *temp_fn, randstr[5];
- int ret;
- /* Create temporary filename. */
- temp_fn = nmalloc(strlen(filename) + 5);
- make_rand_str(randstr, 4);
- strcpy(temp_fn, filename);
- strcat(temp_fn, randstr);
- /* Uncompress file. */
- ret = uncompress_to_file(filename, temp_fn);
- /* Overwrite old file with uncompressed version. Only do so
- * if the uncompression routine succeeded.
- */
- if (ret == COMPF_SUCCESS)
- movefile(temp_fn, filename);
- nfree(temp_fn);
- return ret;
- }
- /*
- * Userfile feature releated functions
- */
- static int uff_comp(int idx, char *filename)
- {
- debug1("Compressing user file for %s.", dcc[idx].nick);
- return compress_file(filename, compress_level);
- }
- static int uff_uncomp(int idx, char *filename)
- {
- debug1("Uncompressing user file from %s.", dcc[idx].nick);
- return uncompress_file(filename);
- }
- static int uff_ask_compress(int idx)
- {
- if (share_compressed)
- return 1;
- else
- return 0;
- }
- static uff_table_t compress_uff_table[] = {
- {"compress", UFF_COMPRESS, uff_ask_compress, 100, uff_comp, uff_uncomp},
- {NULL, 0, NULL, 0, NULL, NULL}
- };
- /*
- * Compress module related code
- */
- static tcl_ints my_tcl_ints[] = {
- {"share-compressed", &share_compressed},
- {"compress-level", &compress_level},
- {NULL, NULL}
- };
- static int compress_expmem(void)
- {
- return 0;
- }
- static int compress_report(int idx, int details)
- {
- if (details)
- dprintf(idx, " Compressed %u file(s), uncompressed %u file(s).\n",
- compressed_files, uncompressed_files);
- return 0;
- }
- EXPORT_SCOPE char *compress_start();
- static Function compress_table[] =
- {
- /* 0 - 3 */
- (Function) compress_start,
- (Function) NULL,
- (Function) compress_expmem,
- (Function) compress_report,
- /* 4 - 7 */
- (Function) compress_to_file,
- (Function) compress_file,
- (Function) uncompress_to_file,
- (Function) uncompress_file,
- /* 8 - 11 */
- (Function) is_compressedfile,
- };
- char *compress_start(Function *global_funcs)
- {
- global = global_funcs;
- compressed_files = 0;
- uncompressed_files = 0;
- share_compressed = 0;
- compress_level = 9;
- module_register(MODULE_NAME, compress_table, 1, 1);
- share_funcs = module_depend(MODULE_NAME, "share", 2, 3);
- if (!share_funcs) {
- module_undepend(MODULE_NAME);
- return "This module requires share module 2.3 or later.";
- }
- uff_addtable(compress_uff_table);
- add_tcl_ints(my_tcl_ints);
- add_tcl_commands(my_tcl_cmds);
- return NULL;
- }
|