X-Git-Url: http://git.ipfire.org/?a=blobdiff_plain;f=decomp.c;h=28be9076a2e06b8d442d276779e9625d0334ec65;hb=cedca1116b4193e322d94a8cf5373c8168d5ac5c;hp=133ee7c712e0a42426ab4634c809990d8ca40779;hpb=61d965f3719e7e4f22c14de73c37e4a8ceb2c24e;p=thirdparty%2Fsarg.git diff --git a/decomp.c b/decomp.c index 133ee7c..28be907 100644 --- a/decomp.c +++ b/decomp.c @@ -1,6 +1,6 @@ /* * SARG Squid Analysis Report Generator http://sarg.sourceforge.net - * 1998, 2012 + * 1998, 2015 * * SARG donations: * please look at http://sarg.sourceforge.net/donations.php @@ -26,48 +26,331 @@ #include "include/conf.h" #include "include/defs.h" +#ifdef HAVE_ZLIB_H +#include "zlib.h" +#endif +#ifdef HAVE_BZLIB_H +#include "bzlib.h" +#endif -FILE *decomp(const char *arq, bool *pipe) +#ifdef HAVE_ZLIB_H +/*! + * Read from gzip file. + * + * \param Data The file object. + * \param Buffer The boffer to store the data read. + * \param Size How many bytes to read. + * + * \return The number of bytes read. + */ +static int Gzip_Read(void *Data,void *Buffer,int Size) { - char cmd[1024]; - int arqlen; + return(gzread((gzFile)Data,Buffer,Size)); +} - if(access(arq, R_OK) != 0) { - debuga(_("File not found: %s\n"),arq); - exit(EXIT_FAILURE); +/*! + * Check if end of file is reached. + * + * \param Data The file object. + * + * \return \c True if end of file is reached. + */ +static int Gzip_Eof(void *Data) +{ + return(gzeof((gzFile)Data)); +} + +/*! + * Return to the beginnig of the file. + * + * \param Data The file object. + */ +static void Gzip_Rewind(void *Data) +{ + gzrewind((gzFile)Data); +} + +/*! + * Close the file. + * + * \param Data File to close. + * + * \return 0 on success or -1 on error. + */ +static int Gzip_Close(void *Data) +{ + int RetCode=-1; + int Status; + + Status=gzclose((gzFile)Data); + switch (Status) + { + case Z_OK: + RetCode=0; + break; + case Z_STREAM_ERROR: + FileObject_SetLastCloseError(_("Invalid gzip file")); + break; + case Z_ERRNO: + FileObject_SetLastCloseError(_("File operation error")); + break; + case Z_MEM_ERROR: + FileObject_SetLastCloseError(_("Not enough memory")); + break; + case Z_BUF_ERROR: + FileObject_SetLastCloseError(_("Truncated gzip stream")); + break; + default: + FileObject_SetLastCloseError(_("Unknown error returned by zlib")); + break; + } + return(RetCode); +} + +/*! + * Open a file object to read from a gzip file. + * + * \return The object to pass to other function in this module. + */ +static FileObject *Gzip_Open(int fd) +{ + FileObject *File; + + FileObject_SetLastOpenError(NULL); + File=calloc(1,sizeof(*File)); + if (!File) + { + FileObject_SetLastOpenError(_("Not enough memory")); + return(NULL); + } + File->Data=gzdopen(fd,"rb"); + if (!File->Data) + { + free(File); + FileObject_SetLastOpenError(_("Error opening gzip file")); + return(NULL); } + File->Read=Gzip_Read; + File->Eof=Gzip_Eof; + File->Rewind=Gzip_Rewind; + File->Close=Gzip_Close; + return(File); +} +#endif + +#ifdef HAVE_BZLIB_H + +struct BzlibInternalFile +{ + //! Bzlib object. + BZFILE *BzFile; + //! \c True if end of file is reached. + bool Eof; + //! Copy of the original file handle. + int fd; +} + +/*! + * Read from bzip file. + * + * \param Data The file object. + * \param Buffer The boffer to store the data read. + * \param Size How many bytes to read. + * + * \return The number of bytes read. + */ +static int Bzip_Read(void *Data,void *Buffer,int Size) +{ + struct BzlibInternalFile *BData=(struct BzlibInternalFile *)Data; + int nread; + + nread=BZ2_bzread(BData->BzFile,Buffer,Size); + if (nread==0) BData->Eof=true; + return(nread); +} + +/*! + * Check if end of file is reached. + * + * \param Data The file object. + * + * \return \c True if end of file is reached. + */ +static int Bzip_Eof(void *Data) +{ + struct BzlibInternalFile *BData=(struct BzlibInternalFile *)Data; + return(BData->Eof); +} + +/*! + * Return to the beginnig of the file. + * + * \param Data The file object. + */ +static void Bzip_Rewind(void *Data) +{ + struct BzlibInternalFile *BData=(struct BzlibInternalFile *)Data; + int fd; - arqlen=strlen(arq); - if(arqlen>3 && strcmp(arq+arqlen-3,".gz") == 0) { - debuga(_("Decompressing log file \"%s\" with zcat\n"),arq); - if (snprintf(cmd,sizeof(cmd),"zcat \"%s\"",arq)>=sizeof(cmd)) { - debuga(_("decompression command too long for log file %s\n"),arq); - exit(EXIT_FAILURE); - } - *pipe=true; - return(popen(cmd,"r")); + BZ2_bzclose(BData->BzFile); + fd=dup(BData->fd); + if (fd==-1) + { + debuga(__FILE__,__LINE__,_("Cannot rewind bzip file\n")); + exit(EXIT_FAILURE); } + BData->BzFile=BZ2_bzdopen(fd,"rb"); + if (!BData->BzFile) + { + debuga(__FILE__,__LINE__,_("Cannot rewind bzip file\n")); + exit(EXIT_FAILURE); + } +} - if(arqlen>4 && strcmp(arq+arqlen-4,".bz2") == 0) { - debuga(_("Decompressing log file \"%s\" with bzcat\n"),arq); - if (snprintf(cmd,sizeof(cmd),"bzcat \"%s\"",arq)>=sizeof(cmd)) { - debuga(_("decompression command too long for log file %s\n"),arq); - exit(EXIT_FAILURE); - } - *pipe=true; - return(popen(cmd,"r")); +/*! + * Close the file. + * + * \param Data File to close. + * + * \return 0 on success or -1 on error. + */ +static int Bzip_Close(void *Data) +{ + struct BzlibInternalFile *BData=(struct BzlibInternalFile *)Data; + + BZ2_bzclose(BData->BzFile); + close(BData->fd); + free(BData); + return(0); +} + +/*! + * Open a file object to read from a bzip file. + * + * \return The object to pass to other function in this module. + */ +static FileObject *Bzip_Open(int fd) +{ + FileObject *File; + struct BzlibInternalFile *BData; + + FileObject_SetLastOpenError(NULL); + File=calloc(1,sizeof(*File)); + if (!File) + { + FileObject_SetLastOpenError(_("Not enough memory")); + return(NULL); + } + BData=calloc(1,sizeof(*BData)); + if (!BData) + { + free(File); + FileObject_SetLastOpenError(_("Not enough memory")); + return(NULL); + } + BData->fd=dup(fd); + if (BData->fd==-1) + { + free(BData); + free(File); + FileObject_SetLastOpenError(_("Error duplicating file descriptor")); + return(NULL); + } + File=Data=BData; + BData->BzFile=BZ2_bzdopen(fd,"rb"); + if (!BData->BzFile) + { + close(BData->fd); + free(BData); + free(File); + FileObject_SetLastOpenError(_("Error opening bzip file")); + return(NULL); } + File->Read=Bzip_Read; + File->Eof=Bzip_Eof; + File->Rewind=Bzip_Rewind; + File->Close=Bzip_Close; + return(File); +} +#endif + + +/*! +Open the log file. If it is compressed, uncompress it through a pipe. + +Log files compressed with gzip, bzip2 or compress are uncompressed with zcat or bzcat. + +If the log file does not exist, the process terminates with an error message. + +\param arq The log file to process. +\param pipe A variable set to \c true if the log file is opened through a pipe or set to \c false if the file is open directly. - if(arqlen>2 && strcmp(arq+arqlen-2,".Z") == 0) { - debuga(_("Decompressing log file \"%s\" with zcat\n"),arq); - if (snprintf(cmd,sizeof(cmd),"zcat \"%s\"",arq)>=sizeof(cmd)) { - debuga(_("decompression command too long for log file %s\n"),arq); - exit(EXIT_FAILURE); - } - *pipe=true; - return(popen(cmd,"r")); +\date 2009-09-24 - F Marchal\n This function used to uncompress .Z files in +place using uncompress but that required a write access to the log directory, +could conflict with logrotate and could leave the log file uncompressed if sarg +crashed. According to the documentation, zcat is capable of uncompressing .Z +files so it is now used. + +\date 2010-05-10 - F Marchal\n +The function doesn't use a temporary file any more and read the compressed file through a pipe. +*/ +FileObject *decomp(const char *arq) +{ + int fd; + FileObject *fi; + unsigned char buf[3]; + ssize_t nread; + + // guess file type + fd=open(arq,O_RDONLY | O_LARGEFILE); + if (fd==-1) { + debuga(__FILE__,__LINE__,_("Cannot open file \"%s\": %s\n"),arq,strerror(errno)); + exit(EXIT_FAILURE); + } + nread=read(fd,buf,sizeof(buf)); + if (nread==-1) { + debuga(__FILE__,__LINE__,_("Error while reading \"%s\" to guess its type: %s\n"),arq,strerror(errno)); + exit(EXIT_FAILURE); + } + if (nread<3) { + debuga(__FILE__,__LINE__,_("File \"%s\" is too small to guess its type\n"),arq); + exit(EXIT_FAILURE); + } + if (lseek(fd,0,SEEK_SET)==-1) { + debuga(__FILE__,__LINE__,_("Cannot return to the beginning of file \"%s\": %s"),arq,strerror(errno)); + exit(EXIT_FAILURE); } - *pipe=false; - return(MY_FOPEN(arq,"r")); + if (buf[0]==0x1F && buf[1]==0x8B && buf[2]==0x08)//gzip file + { +#ifdef HAVE_ZLIB_H + fi=Gzip_Open(fd); +#else + debuga(__FILE__,__LINE__,_("Sarg was not compiled with gzip support to read file \"%s\"\n"),arq); + exit(EXIT_FAILURE); +#endif + } + else if (buf[0]==0x42 && buf[1]==0x5A && buf[2]==0x68)//bzip2 file + { +#ifdef HAVE_BZLIB_H + fi=Bzip_Open(fd); +#else + debuga(__FILE__,__LINE__,_("Sarg was not compiled with bzip support to read file \"%s\"\n"),arq); + exit(EXIT_FAILURE); +#endif + } + else if (buf[0]==0x1F && (buf[1]==0x9D || buf[1]==0xA0))//LZW and LZH compressed file + { + debuga(__FILE__,__LINE__,_("Support for LZW and LZH compressed files was removed in sarg 2.4.\n" + "You can still read such a file with a command like this:\n" + " zcat \"%s\" | sarg - [your usual options here]\n" + "If you think it is important for sarg to read those files, open a bug ticket at .\n"), + arq); + exit(EXIT_FAILURE); + } + else //normal file + { + fi=FileObject_FdOpen(fd); + } + return(fi); }