Mercurial > hg > xemacs-beta
diff nt/minitar.c @ 327:03446687b7cc r21-0-61
Import from CVS: tag r21-0-61
author | cvs |
---|---|
date | Mon, 13 Aug 2007 10:48:16 +0200 |
parents | |
children | 8e84bee8ddd0 74fd4e045ea6 9d177e8d4150 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nt/minitar.c Mon Aug 13 10:48:16 2007 +0200 @@ -0,0 +1,211 @@ + +/* Minitar: extract .tar.gz files on Win32 platforms. + Uses zlib for decompression. + + This is very simple-minded, it ignores checksums, and any type of file + that is not a plain file or a directory. Nonetheless it is useful. + + Author: Charles G. Waldman (cgw@pgt.com), Aug 4 1998 + + This file is placed in the public domain; you can + do whatever you like with it. There is NO WARRANTY. + If it breaks, you get to keep both pieces */ + + +#include <stdio.h> +#include <Errno.h> + +#include <zlib.h> + +Usage(char *name) +{ + fprintf(stderr,"Usage: %s file.tar.gz [base-dir]\n",name); + fprintf(stderr,"\tExtracts the contents compressed tar file to base-dir\n"); + exit(-1); +} + + +#define BLOCKSIZE 512 +#define MAXNAMELEN 1024 + +int octal(char *str) +{ + int ret = -1; + sscanf(str,"%o",&ret); + return ret; +} + +/* this is like mkdir -p, except if there is no trailing slash, + the final component is assumed to be a file, rather than a + path component, so it is not created as a directory */ + +int makepath(char *path) +{ + char tmp[MAXNAMELEN]; + char *cp; + extern int errno; + + for (cp=path; cp; cp = (char*)strchr(cp+1,'/')){ + if (!*cp) + break; + if (*cp != '/') + continue; + strncpy(tmp, path, cp-path); + tmp[cp-path] = '\0'; + if (strlen(tmp) == 0) + continue; + if (mkdir(tmp,0777)){ + if (errno == EEXIST) + continue; + else + return -1; + } + } + return 0; +} + + + + +main(int argc, char **argv) +{ + char fullname[MAXNAMELEN]; + char *basedir = "."; + char *tarfile; + char *cp; + int size; + char osize[13]; + char name[101]; + char magic[7]; + char type; + + gzFile *infile = (gzFile*)0; + FILE *outfile = (FILE*)0; + + char block[BLOCKSIZE]; + int nbytes, nread, nwritten; + + int in_block = 0; + int directory = 0; + + if (argc < 2 || argc > 3) + Usage(argv[0]); + + tarfile = argv[1]; + if (argc==3) + basedir = argv[2]; + + if (! (infile = gzopen(tarfile,"rb"))){ + fprintf(stderr,"Cannot open %s\n", tarfile); + exit(-2); + } + + while (1){ + + + nread = gzread(infile,block,512); + + if (!in_block && nread == 0) + break; + + if (nread != BLOCKSIZE){ + fprintf(stderr,"Error: incomplete block read. Exiting.\n"); + exit(-2); + } + + if (!in_block){ + if (block[0]=='\0') /* We're done */ + break; + + strncpy(magic,block+257,6); + magic[6] = '\0'; + if (strcmp(magic,"ustar ")){ + fprintf(stderr, + "Error: incorrect magic number in tar header. Exiting\n"); + } + + strncpy(name,block,100); + name[100] = '\0'; + sprintf(fullname,"%s/%s",basedir,name); + printf("%s\n",fullname); + type = block[156]; + + switch(type){ + case '0': + case '\0': + directory = 0; + break; + case '5': + directory = 1; + break; + default: + fprintf(stderr,"Error: unknown type flag %c. Exiting.\n",type); + break; + } + + if (directory){ + in_block = 0; + + /* makepath will ignore the final path component, so make sure + dirnames have a trailing slash */ + + if (fullname[strlen(fullname)-1] != '/') + strcat(fullname,"/"); + if (makepath(fullname)){ + fprintf(stderr, "Error: cannot create directory %s. Exiting.\n", + fullname); + exit(-2); + } + continue; + } else { /*file */ + in_block = 1; + if (outfile){ + if (fclose(outfile)){ + fprintf(stderr,"Error: cannot close file %s. Exiting.\n", + fullname); + exit(-2); + } + outfile = (FILE*)0; + } + + if ( !(outfile = fopen(fullname,"wb"))){ + /*try creating the directory, maybe it's not there */ + if (makepath(fullname)){ + fprintf(stderr,"Error: cannot create file %s. Exiting.\n", + fullname); + exit(-2); + } + /* now try again to open the file */ + if (!(outfile = fopen(fullname,"wb"))){ + fprintf(stderr,"Error: cannot create file %s. Exiting.\n", + fullname); + exit(-2); + } + } + + strncpy(osize,block+124,12); + osize[12] = '\0'; + size = octal(osize); + if (size<0){ + fprintf(stderr,"Error: invalid size in tar header. Exiting.\n"); + exit(-2); + } + } + } else { /* write or continue writing file contents */ + nbytes = size>512? 512:size; + + nwritten = fwrite(block, 1, nbytes, outfile); + if (nwritten != nbytes){ + fprintf(stderr, "Error: only wrote %d bytes to file %s. Exiting.\n", + nwritten, fullname); + } + size -= nbytes; + if (size==0) + in_block = 0; + } + } +} + + + +