This commit was manufactured by cvs2svn to create branch 'chise-r21-4-18'.
[chise/xemacs-chise.git-] / nt / minitar.c
diff --git a/nt/minitar.c b/nt/minitar.c
new file mode 100644 (file)
index 0000000..d5e3d40
--- /dev/null
@@ -0,0 +1,246 @@
+
+/* 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 <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <io.h>
+#ifdef WIN32_NATIVE
+# include <direct.h>   /* For mkdir */
+#endif
+
+#include <zlib.h>
+
+static void
+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
+
+static 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 */
+
+static int
+makepath (char *path)
+{
+  char tmp[MAXNAMELEN];
+  char *cp;
+
+  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;
+#ifdef WIN32_NATIVE
+      if (mkdir (tmp))
+#else
+       if (mkdir (tmp, 0777))
+#endif
+         {
+           if (errno == EEXIST)
+             continue;
+           else
+             return -1;
+         }
+    }
+  return 0;
+}
+
+
+
+int
+main (int argc, char **argv)
+{
+  char fullname[MAXNAMELEN];
+  char *basedir = ".";
+  char *tarfile;
+  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");
+             exit (-2);
+           }
+
+         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);
+             exit (-2);
+             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);
+               }
+             if (size==0)      /* file of size 0 is done */
+               in_block = 0;
+           }
+       }
+      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);
+             exit (-2);
+           }
+         size -= nbytes;
+         if (size==0)
+           in_block = 0;
+       }
+    }
+  return 0;
+}
+
+
+