You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
177 lines
4.7 KiB
177 lines
4.7 KiB
/* OS-specific IO functions for xcftools
|
|
*
|
|
* Copyright (C) 2006 Henning Makholm
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of version 2 of the GNU General Public License as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
#include "xcftools.h"
|
|
#include <string.h>
|
|
#include <sys/types.h>
|
|
#include <sys/wait.h>
|
|
#include <sys/stat.h>
|
|
#include <unistd.h>
|
|
#include <stdlib.h>
|
|
#include <errno.h>
|
|
#if HAVE_MMAP
|
|
#include <sys/mman.h>
|
|
#endif
|
|
|
|
static FILE *xcfstream = 0 ;
|
|
|
|
void
|
|
free_or_close_xcf(void)
|
|
{
|
|
if( xcf_file ) {
|
|
if( xcfstream ) {
|
|
munmap(xcf_file,xcf_length) ;
|
|
fclose(xcfstream);
|
|
xcf_file = 0 ;
|
|
xcfstream = 0 ;
|
|
} else {
|
|
free(xcf_file) ;
|
|
xcf_file = 0 ;
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
read_or_mmap_xcf(const char *filename,const char *unzipper)
|
|
{
|
|
struct stat statbuf ;
|
|
|
|
free_or_close_xcf() ;
|
|
|
|
if( strcmp(filename,"-") != 0 ) {
|
|
if( access(filename,R_OK) != 0 )
|
|
FatalGeneric(21,"!%s",filename);
|
|
}
|
|
|
|
if( !unzipper ) {
|
|
const char *pc ;
|
|
pc = filename + strlen(filename) ;
|
|
if( pc-filename > 2 && strcmp(pc-2,"gz") == 0 )
|
|
unzipper = "zcat" ;
|
|
else if ( pc-filename > 3 && strcmp(pc-3,"bz2") == 0 )
|
|
unzipper = "bzcat" ;
|
|
else
|
|
unzipper = "" ;
|
|
} else if( strcmp(unzipper,"cat") == 0 )
|
|
unzipper = "" ;
|
|
|
|
if( *unzipper ) {
|
|
int pid, status, outfd ;
|
|
#if HAVE_MMAP
|
|
xcfstream = tmpfile() ;
|
|
if( !xcfstream )
|
|
FatalUnexpected(_("!Cannot create temporary unzipped file"));
|
|
outfd = fileno(xcfstream) ;
|
|
#else
|
|
int fh[2] ;
|
|
if( pipe(fh) < 0 )
|
|
FatalUnexpected("!Cannot create pipe for %s",unzipper);
|
|
xcfstream = fdopen(fh[1],"rb") ;
|
|
if( !xcfstream )
|
|
FatalUnexpected("!Cannot fdopen() unzipper pipe");
|
|
outfd = fh[0] ;
|
|
#endif
|
|
if( (pid = fork()) == 0 ) {
|
|
/* We're the child */
|
|
if( dup2(outfd,1) < 0 ) {
|
|
perror("Cannot dup2 in unzip process");
|
|
exit(127) ;
|
|
}
|
|
fclose(xcfstream) ;
|
|
execlp(unzipper,unzipper,filename,NULL) ;
|
|
fprintf(stderr,_("Cannot execute "));
|
|
perror(unzipper);
|
|
exit(126) ;
|
|
}
|
|
#if HAVE_MMAP
|
|
while( wait(&status) != pid )
|
|
;
|
|
if( WIFEXITED(status) ) {
|
|
status = WEXITSTATUS(status) ;
|
|
if( status > 0 ) {
|
|
fclose(xcfstream) ;
|
|
xcfstream = 0 ;
|
|
FatalGeneric(status,NULL);
|
|
}
|
|
} else {
|
|
fclose(xcfstream) ;
|
|
xcfstream = 0 ;
|
|
FatalGeneric(126,_("%s terminated abnormally"),unzipper);
|
|
}
|
|
#else
|
|
close(fh[0]) ;
|
|
#endif
|
|
} else if( strcmp(filename,"-") == 0 ) {
|
|
xcfstream = fdopen(dup(0),"rb") ;
|
|
if( !xcfstream )
|
|
FatalUnexpected("!Cannot dup stdin for input") ;
|
|
} else {
|
|
xcfstream = fopen(filename,"rb") ;
|
|
if( !xcfstream )
|
|
FatalGeneric(21,_("!Cannot open %s"),filename);
|
|
}
|
|
/* OK, now we have an open stream ... */
|
|
if( fstat(fileno(xcfstream),&statbuf) == 0 &&
|
|
(statbuf.st_mode & S_IFMT) == S_IFREG ) {
|
|
xcf_length = statbuf.st_size ;
|
|
#if HAVE_MMAP
|
|
xcf_file = mmap(0,xcf_length,PROT_READ,MAP_SHARED,fileno(xcfstream),0);
|
|
if( xcf_file != (void*)-1 )
|
|
return ;
|
|
if( errno != ENODEV ) {
|
|
int saved = errno ;
|
|
fclose(xcfstream) ;
|
|
xcf_file = 0 ;
|
|
errno = saved ;
|
|
FatalUnexpected("!Could not mmap input");
|
|
}
|
|
#endif
|
|
xcf_file = malloc(xcf_length);
|
|
if( xcf_file == 0 )
|
|
FatalUnexpected(_("Out of memory for xcf data"));
|
|
if( fread(xcf_file,1,xcf_length,xcfstream) != xcf_length ) {
|
|
if( feof(xcfstream) )
|
|
FatalUnexpected(_("XCF file shrunk while reading it"));
|
|
else
|
|
FatalUnexpected(_("!Could not read xcf data"));
|
|
}
|
|
fclose(xcfstream) ;
|
|
xcfstream = 0 ;
|
|
} else {
|
|
size_t blocksize = 0x80000 ; /* 512 KB */
|
|
xcf_length = 0 ;
|
|
xcf_file = 0 ;
|
|
while(1) {
|
|
xcf_file = realloc(xcf_file,blocksize) ;
|
|
if( xcf_file == 0 )
|
|
FatalUnexpected(_("Out of memory for xcf data"));
|
|
size_t actual = fread(xcf_file+xcf_length,1,blocksize-xcf_length,
|
|
xcfstream) ;
|
|
xcf_length += actual ;
|
|
if( feof(xcfstream) )
|
|
break ;
|
|
if( xcf_length < blocksize ) {
|
|
FatalUnexpected(_("!Could not read xcf data")) ;
|
|
}
|
|
blocksize += (blocksize >> 1) & ~(size_t)0x3FFF ; /* 16 KB granularity */
|
|
}
|
|
fclose(xcfstream) ;
|
|
xcfstream = 0 ;
|
|
}
|
|
}
|