/*
* SARG Squid Analysis Report Generator http://sarg.sourceforge.net
- * 1998, 2013
+ * 1998, 2015
*
* SARG donations:
* please look at http://sarg.sourceforge.net/donations.php
#include "include/conf.h"
#include "include/defs.h"
+#ifdef HAVE_ZLIB_H
+#include "zlib.h"
+#endif
+#ifdef HAVE_BZLIB_H
+#include "bzlib.h"
+#endif
+
+#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)
+{
+ return(gzread((gzFile)Data,Buffer,Size));
+}
+
+/*!
+ * 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;
+ //! Original file in case a rewind is necessary.
+ FILE *File;
+};
+
+/*!
+ * 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;
+ int bzerr=BZ_OK;
+
+ if (BData->Eof) return(0);
+ nread=BZ2_bzRead(&bzerr,BData->BzFile,Buffer,Size);
+ if (bzerr==BZ_STREAM_END)
+ BData->Eof=true;
+ else if (bzerr!=BZ_OK)
+ return(0);
+ 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 bzerr=BZ_OK;
+
+ BZ2_bzReadClose(&bzerr,BData->BzFile);
+ rewind(BData->File);
+ BData->BzFile=BZ2_bzReadOpen(&bzerr,BData->File,0,0,NULL,0);
+ if (!BData->BzFile)
+ {
+ debuga(__FILE__,__LINE__,_("Cannot rewind bzip file\n"));
+ exit(EXIT_FAILURE);
+ }
+ BData->Eof=false;
+}
+
+/*!
+ * 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;
+ int bzerr=BZ_OK;
+
+ BZ2_bzReadClose(&bzerr,BData->BzFile);
+ fclose(BData->File);
+ 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;
+ int bzerr=BZ_OK;
+
+ 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->File=fdopen(fd,"rb");
+ if (BData->File==NULL)
+ {
+ free(BData);
+ free(File);
+ FileObject_SetLastOpenError(_("Error duplicating file descriptor"));
+ return(NULL);
+ }
+ File->Data=BData;
+ BData->BzFile=BZ2_bzReadOpen(&bzerr,BData->File,0,0,NULL,0);
+ if (!BData->BzFile)
+ {
+ fclose(BData->File);
+ 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.
\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.
*/
-FILE *decomp(const char *arq, bool *pipe)
+FileObject *decomp(const char *arq)
{
- FILE *fi;
- char cmd[1024];
- int arqlen;
-
- 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;
- fi=popen(cmd,"r");
- }
- else 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;
- fi=popen(cmd,"r");
- }
- else 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;
- fi=popen(cmd,"r");
- }
- else {
- *pipe=false;
- fi=MY_FOPEN(arq,"r");
+ 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);
+ }
+
+ 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 <http://sourceforge.net/p/sarg/bugs/>.\n"),
+ arq);
+ exit(EXIT_FAILURE);
+ }
+ else //normal file
+ {
+ fi=FileObject_FdOpen(fd);
}
return(fi);
}