327
+ − 1
+ − 2 /* Minitar: extract .tar.gz files on Win32 platforms.
+ − 3 Uses zlib for decompression.
+ − 4
+ − 5 This is very simple-minded, it ignores checksums, and any type of file
+ − 6 that is not a plain file or a directory. Nonetheless it is useful.
+ − 7
+ − 8 Author: Charles G. Waldman (cgw@pgt.com), Aug 4 1998
+ − 9
+ − 10 This file is placed in the public domain; you can
+ − 11 do whatever you like with it. There is NO WARRANTY.
+ − 12 If it breaks, you get to keep both pieces */
+ − 13
+ − 14
2951
+ − 15 #ifdef HAVE_CONFIG_H
+ − 16 # include <config.h>
+ − 17 #endif
+ − 18
327
+ − 19 #include <stdio.h>
812
+ − 20 #include <stdlib.h>
438
+ − 21 #include <errno.h>
464
+ − 22 #include <string.h>
+ − 23 #include <io.h>
812
+ − 24 #ifdef WIN32_NATIVE
+ − 25 # include <direct.h> /* For mkdir */
+ − 26 #endif
327
+ − 27
+ − 28 #include <zlib.h>
+ − 29
1782
+ − 30 static void
495
+ − 31 Usage (char *name)
327
+ − 32 {
495
+ − 33 fprintf (stderr, "Usage: %s file.tar.gz [base-dir]\n", name);
+ − 34 fprintf (stderr, "\tExtracts the contents compressed tar file to base-dir\n");
+ − 35 exit (-1);
327
+ − 36 }
+ − 37
+ − 38
+ − 39 #define BLOCKSIZE 512
+ − 40 #define MAXNAMELEN 1024
+ − 41
464
+ − 42 static int
495
+ − 43 octal (char *str)
327
+ − 44 {
+ − 45 int ret = -1;
495
+ − 46 sscanf (str, "%o", &ret);
327
+ − 47 return ret;
+ − 48 }
+ − 49
+ − 50 /* this is like mkdir -p, except if there is no trailing slash,
+ − 51 the final component is assumed to be a file, rather than a
+ − 52 path component, so it is not created as a directory */
+ − 53
464
+ − 54 static int
495
+ − 55 makepath (char *path)
327
+ − 56 {
+ − 57 char tmp[MAXNAMELEN];
+ − 58 char *cp;
+ − 59
495
+ − 60 for (cp=path; cp; cp = (char*)strchr (cp+1, '/'))
+ − 61 {
+ − 62 if (!*cp)
+ − 63 break;
+ − 64 if (*cp != '/')
+ − 65 continue;
+ − 66 strncpy (tmp, path, cp-path);
+ − 67 tmp[cp-path] = '\0';
+ − 68 if (strlen (tmp) == 0)
+ − 69 continue;
464
+ − 70 #ifdef WIN32_NATIVE
495
+ − 71 if (mkdir (tmp))
464
+ − 72 #else
495
+ − 73 if (mkdir (tmp, 0777))
464
+ − 74 #endif
495
+ − 75 {
+ − 76 if (errno == EEXIST)
+ − 77 continue;
+ − 78 else
+ − 79 return -1;
+ − 80 }
327
+ − 81 }
+ − 82 return 0;
+ − 83 }
+ − 84
495
+ − 85
327
+ − 86
464
+ − 87 int
495
+ − 88 main (int argc, char **argv)
327
+ − 89 {
+ − 90 char fullname[MAXNAMELEN];
+ − 91 char *basedir = ".";
+ − 92 char *tarfile;
+ − 93 int size;
+ − 94 char osize[13];
+ − 95 char name[101];
+ − 96 char magic[7];
+ − 97 char type;
+ − 98
+ − 99 gzFile *infile = (gzFile*)0;
+ − 100 FILE *outfile = (FILE*)0;
+ − 101
+ − 102 char block[BLOCKSIZE];
+ − 103 int nbytes, nread, nwritten;
+ − 104
+ − 105 int in_block = 0;
+ − 106 int directory = 0;
+ − 107
+ − 108 if (argc < 2 || argc > 3)
495
+ − 109 Usage (argv[0]);
327
+ − 110
+ − 111 tarfile = argv[1];
+ − 112 if (argc==3)
+ − 113 basedir = argv[2];
+ − 114
495
+ − 115 if (! (infile = gzopen (tarfile, "rb")))
+ − 116 {
+ − 117 fprintf (stderr, "Cannot open %s\n", tarfile);
+ − 118 exit (-2);
+ − 119 }
327
+ − 120
495
+ − 121 while (1)
+ − 122 {
+ − 123 nread = gzread (infile, block, 512);
327
+ − 124
495
+ − 125 if (!in_block && nread == 0)
327
+ − 126 break;
+ − 127
495
+ − 128 if (nread != BLOCKSIZE)
+ − 129 {
+ − 130 fprintf (stderr, "Error: incomplete block read. Exiting.\n");
+ − 131 exit (-2);
327
+ − 132 }
+ − 133
495
+ − 134 if (!in_block)
+ − 135 {
+ − 136 if (block[0]=='\0') /* We're done */
+ − 137 break;
+ − 138
+ − 139 strncpy (magic, block+257, 6);
+ − 140 magic[6] = '\0';
+ − 141 if (strcmp (magic, "ustar "))
+ − 142 {
+ − 143 fprintf (stderr,
+ − 144 "Error: incorrect magic number in tar header. Exiting\n");
1529
+ − 145 exit (-2);
495
+ − 146 }
+ − 147
+ − 148 strncpy (name, block, 100);
+ − 149 name[100] = '\0';
+ − 150 sprintf (fullname, "%s/%s", basedir, name);
+ − 151 printf ("%s\n", fullname);
+ − 152 type = block[156];
+ − 153
+ − 154 switch (type)
+ − 155 {
+ − 156 case '0':
+ − 157 case '\0':
+ − 158 directory = 0;
+ − 159 break;
+ − 160 case '5':
+ − 161 directory = 1;
+ − 162 break;
+ − 163 default:
+ − 164 fprintf (stderr, "Error: unknown type flag %c. Exiting.\n", type);
1529
+ − 165 exit (-2);
495
+ − 166 break;
+ − 167 }
+ − 168
+ − 169 if (directory)
+ − 170 {
+ − 171 in_block = 0;
+ − 172
+ − 173 /* makepath will ignore the final path component, so make sure
+ − 174 dirnames have a trailing slash */
327
+ − 175
495
+ − 176 if (fullname[strlen (fullname)-1] != '/')
+ − 177 strcat (fullname, "/");
+ − 178 if (makepath (fullname))
+ − 179 {
+ − 180 fprintf (stderr, "Error: cannot create directory %s. Exiting.\n",
+ − 181 fullname);
+ − 182 exit (-2);
+ − 183 }
+ − 184 continue;
+ − 185 }
+ − 186 else
+ − 187 { /*file */
+ − 188 in_block = 1;
+ − 189 if (outfile)
+ − 190 {
+ − 191 if (fclose (outfile))
+ − 192 {
+ − 193 fprintf (stderr, "Error: cannot close file %s. Exiting.\n",
+ − 194 fullname);
+ − 195 exit (-2);
+ − 196 }
+ − 197 outfile = (FILE*)0;
+ − 198 }
+ − 199
+ − 200 if (!(outfile = fopen (fullname, "wb")))
+ − 201 {
+ − 202 /*try creating the directory, maybe it's not there */
+ − 203 if (makepath (fullname))
+ − 204 {
+ − 205 fprintf (stderr, "Error: cannot create file %s. Exiting.\n",
+ − 206 fullname);
+ − 207 exit (-2);
+ − 208 }
+ − 209 /* now try again to open the file */
+ − 210 if (!(outfile = fopen (fullname, "wb")))
+ − 211 {
+ − 212 fprintf (stderr, "Error: cannot create file %s. Exiting.\n",
+ − 213 fullname);
+ − 214 exit (-2);
+ − 215 }
+ − 216 }
+ − 217
+ − 218 strncpy (osize, block+124, 12);
+ − 219 osize[12] = '\0';
+ − 220 size = octal (osize);
+ − 221 if (size<0)
+ − 222 {
+ − 223 fprintf (stderr, "Error: invalid size in tar header. Exiting.\n");
+ − 224 exit (-2);
+ − 225 }
1529
+ − 226 if (size==0) /* file of size 0 is done */
+ − 227 in_block = 0;
495
+ − 228 }
1782
+ − 229 }
+ − 230 else
+ − 231 { /* write or continue writing file contents */
495
+ − 232 nbytes = size>512? 512:size;
327
+ − 233
495
+ − 234 nwritten = fwrite (block, 1, nbytes, outfile);
+ − 235 if (nwritten != nbytes)
+ − 236 {
+ − 237 fprintf (stderr, "Error: only wrote %d bytes to file %s. Exiting.\n",
+ − 238 nwritten, fullname);
1529
+ − 239 exit (-2);
495
+ − 240 }
+ − 241 size -= nbytes;
+ − 242 if (size==0)
+ − 243 in_block = 0;
+ − 244 }
327
+ − 245 }
495
+ − 246 return 0;
+ − 247 }
327
+ − 248
+ − 249
+ − 250