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;
+    }
+  }
+}	
+
+
+
+