/* unpack.c -- David Bremner, 1991; * Changes to this file Copyright 1991, 1994 Liam R. Quin. * All Rights Reserved. * This code is NOT in the public domain. * See the file COPYRIGHT for full details. * * $Id: unpack.c,v 1.14 2001/05/30 20:42:16 liam Exp $ * * Uncompress or dearchive a file and return a an open file descriptor to a * copy of the file in /tmp * * If a filename contains a ':' it is assumed to be of the form * archive-path:component * * Compression is determined via magic number * * Original by David Bremner (bremner@cs.sfu.ca). * Id: LQT_UnpackAndOpen.c,v 1.1 1991/06/05 18:39:47 bremner Exp * */ #include "error.h" #include #include #include "globals.h" #ifdef HAVE_STRING_H # include #else # include #endif #ifdef HAVE_STDLIB_H # include #endif #ifdef HAVE_FCNTL_H # ifdef HAVE_SYSV_FCNTL_H # include # endif # include #endif #ifdef HAVE_UNISTD_H # include #endif #include "emalloc.h" #include "fileinfo.h" #include "liblqtext.h" #include "lqtrace.h" #define COMPRESS_MAGIC "\037\235\220" #define COMPRESS_LEN (sizeof(COMPRESS_MAGIC) - 1) #define UNCOMPRESS_COMMAND "compress -d < '%s' > '%s'" #define UNGZIP_COMMAND "gzip -d -c < '%s' > '%s'" #define BUNZIP_COMMAND "bzip2 -d -c < '%s' > '%s'" #define GZIP_MAGIC "\037\213" #define GZIP_MAGIC_LEN (sizeof(GZIP_MAGIC) - 1) #define AR_COMMAND "ar p '%s' '%s' > '%s'" /* Archives are accessed as archivename(component), where the ( and ) * characters are START_CHAR and END_CHAR respectively. Define END_CHAR to * be \0 to disable it. * TODO: combine with LQT_GetFilterType and make dynamically configured. */ #define START_CHAR '(' #define END_CHAR ')' PRIVATE int DoCommand( #ifdef HAVE_PROTO t_LQTEXT_Database *db, char *Command, char *InputFile #endif ); PRIVATE int UnpackArchive( #ifdef HAVE_PROTO t_LQTEXT_Database *, char *, char * #endif ); extern char *mktemp( #ifdef HAVE_PROTO char *pattern #endif ); /* * LQT_UnpackAndOpen * Database/Documents * * Tries to open the named file, using compress or gunzip as * necessary. Can append a .Z or .gz to the file name. * Currently, LQT_UnpackAndOpen makes a copy of a file if necessary; * a future version may create a pipe, and the interface will change. * * *
  • an open file descriptor on success; *
  • -1 if the file couldn't be opened. * * * LQT_FindFile * LQT_MakeInput * */ API int LQT_UnpackAndOpen(db, FileName) t_LQTEXT_Database *db; char *FileName; { int fd; char magic_buffer[4]; char *Component; if ((fd = open(FileName, O_RDONLY, 0)) < 0) { char *CompressedName = emalloc( "LQT_UnpackAndOpen filename", strlen(FileName) + 5 /* for .bz2 + \0 */ ); /* gzip? */ (void) sprintf(CompressedName, "%s.gz", FileName); if ((fd = open(CompressedName, O_RDONLY, 0)) >= 0) { (void) close(fd); return DoCommand(db, UNGZIP_COMMAND, CompressedName); } /* compressed */ (void) sprintf(CompressedName, "%s.Z", FileName); if ((fd = open(CompressedName, O_RDONLY, 0)) >= 0) { (void) close(fd); return DoCommand(db, UNCOMPRESS_COMMAND, CompressedName); } /* or with bzip2? */ (void) sprintf(CompressedName, "%s.bz2", FileName); if ((fd = open(CompressedName, O_RDONLY, 0)) >= 0) { (void) close(fd); return DoCommand(db, BUNZIP_COMMAND, CompressedName); } /* Check to see if it could be a name of the form * archivename(component); * Archive Component */ if ((Component = strchr(FileName, START_CHAR)) != (char *) 0) { char *ArchiveName = emalloc( "LQT_UnpackAndOpen archive name", Component - FileName + 1 ); char *ArchiveLocation = 0; /* search filepath */ char *p; int Newfd; if (!ArchiveName) return -1; if (END_CHAR && FileName[strlen(FileName) - 1] != END_CHAR) { (void) efree(ArchiveName); return -1; } (void) strncpy(ArchiveName, FileName, Component - FileName); ArchiveName[Component - FileName] = '\0'; ArchiveLocation = LQT_FindFile(db, ArchiveName); if (!ArchiveLocation) { (void) efree(ArchiveName); return -1; } ++Component; /* skip over FIRST_CHAR */ if (END_CHAR) { char *q; p = emalloc( "LQT_UnpackAndOpen ar component", strlen(Component) + 1 ); (void) strcpy(p, Component); q = strrchr(p, END_CHAR); if (q && q[1] == '\0') { *q = '\0'; } } else { p = emalloc("LQT_UnpackAndOpen component", strlen(Component) + 1); (void) strncpy(p, Component, strlen(Component)); } Component = p; #ifdef ASCIITRACE LQT_Trace(LQTRACE_FINDFILE, "archive %s; Component %s", ArchiveLocation, Component ); #endif (void) close(fd); Newfd = UnpackArchive(db, ArchiveLocation, Component); (void) efree(ArchiveName); (void) efree(Component); return Newfd; } return -1; } if (read(fd, magic_buffer, COMPRESS_LEN) == COMPRESS_LEN) { if (strncmp(magic_buffer, COMPRESS_MAGIC, COMPRESS_LEN) == 0) { (void) close(fd); return DoCommand(db, UNCOMPRESS_COMMAND, FileName); } else if (strncmp(magic_buffer, GZIP_MAGIC, GZIP_MAGIC_LEN) == 0) { (void) close(fd); return DoCommand(db, UNGZIP_COMMAND, FileName); } } /* If we fall thorough to here, it is just a regular file */ /* reset file pointer */ if (lseek(fd,0L,SEEK_SET) < 0 ) { (void) close(fd); return -1; } else { return fd; } /*NOTREACHED*/ } PRIVATE int UnpackArchive(db, ArchiveLocation, Component) t_LQTEXT_Database *db; char *ArchiveLocation; /* a full pathname */ char *Component; { int fd; char *Tmp = emalloc( "ArchiveLocation", strlen(ArchiveLocation) + strlen(AR_COMMAND) ); (void) sprintf(Tmp, AR_COMMAND, ArchiveLocation, "%s", "%s"); fd = DoCommand(db, Tmp, Component); (void) efree(Tmp); return fd; } PRIVATE int DoCommand(db, Command, InputFile) t_LQTEXT_Database *db; char *Command; char *InputFile; { char *template; char *Buffer; int fd; char *tmpdir = getenv("TMPDIR"); if (!tmpdir) { tmpdir = "/tmp"; } #define PATTERN "/lqtextZZXXXXXX" template = emalloc("DoComamnd template", strlen(tmpdir) + sizeof(PATTERN)); (void) strcpy(template, tmpdir); (void) strcat(template, PATTERN); (void) mktemp(template); Buffer = emalloc( "DoCommand buffer", strlen(Command) + strlen(InputFile) + strlen(template) ); (void) sprintf(Buffer, Command, InputFile, template); #ifdef ASCIITRACE LQT_Trace(LQTRACE_FINDFILE, "findfile/Unpack command: %s", Buffer ); #endif /* System() will create the file, so we have not to * call Error(E_FATAL...) until we have ensured that * we have removed the temporary file. * An interrupt would also leave the file lying around. * However, we need to keep the file around for long enough to * unpack it, so there's not much we can do. */ system(Buffer); (void) efree(Buffer); fd = LQT_UnpackAndOpen(db, template); (void) unlink(template); efree(template); return fd; }