Initial revision
[chise/xemacs-chise.git.1] / nt / minitar.c
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
15 #include <stdio.h>
16 #include <errno.h>
17
18 #include <zlib.h>
19
20 Usage(char *name)
21 {
22   fprintf(stderr,"Usage: %s file.tar.gz [base-dir]\n",name);
23   fprintf(stderr,"\tExtracts the contents compressed tar file to base-dir\n");
24   exit(-1);
25 }
26
27
28 #define BLOCKSIZE 512
29 #define MAXNAMELEN 1024
30
31 int octal(char *str)
32 {
33   int ret = -1;
34   sscanf(str,"%o",&ret);
35   return ret;
36 }
37
38 /* this is like mkdir -p, except if there is no trailing slash,
39    the final component is assumed to be a file, rather than a
40    path component, so it is not created as a directory */
41
42 int makepath(char *path)
43 {
44   char tmp[MAXNAMELEN];
45   char *cp;
46
47   for (cp=path; cp; cp = (char*)strchr(cp+1,'/')){
48     if (!*cp)
49       break;
50     if (*cp != '/')
51       continue;
52     strncpy(tmp, path, cp-path);
53     tmp[cp-path] = '\0';
54     if (strlen(tmp) == 0)
55       continue;
56     if (mkdir(tmp,0777)){
57       if (errno == EEXIST)
58         continue;
59       else
60         return -1;
61     }
62   }
63   return 0;
64 }
65
66   
67                      
68
69 main(int argc, char **argv)
70 {
71   char fullname[MAXNAMELEN];
72   char *basedir = ".";
73   char *tarfile;
74   char *cp;
75   int size;
76   char osize[13];
77   char name[101];
78   char magic[7];
79   char type;
80   
81   gzFile *infile = (gzFile*)0;
82   FILE *outfile = (FILE*)0;
83
84   char block[BLOCKSIZE];
85   int nbytes, nread, nwritten;
86
87   int in_block = 0;
88   int directory = 0;
89
90   if (argc < 2 || argc > 3)
91     Usage(argv[0]);
92
93   tarfile = argv[1];
94   if (argc==3)
95     basedir = argv[2];
96
97   if (! (infile = gzopen(tarfile,"rb"))){
98     fprintf(stderr,"Cannot open %s\n", tarfile);
99     exit(-2);
100   }
101   
102   while (1){
103   
104
105     nread = gzread(infile,block,512);
106
107     if (!in_block && nread == 0)
108       break;
109
110     if (nread != BLOCKSIZE){
111       fprintf(stderr,"Error: incomplete block read. Exiting.\n");
112       exit(-2);
113     }
114
115     if (!in_block){
116       if (block[0]=='\0')  /* We're done */
117         break;
118
119       strncpy(magic,block+257,6);
120       magic[6] = '\0';
121       if (strcmp(magic,"ustar ")){
122         fprintf(stderr,
123                 "Error: incorrect magic number in tar header. Exiting\n");
124       }
125
126       strncpy(name,block,100);
127       name[100] = '\0';
128       sprintf(fullname,"%s/%s",basedir,name);
129       printf("%s\n",fullname);
130       type = block[156];
131       
132       switch(type){
133       case '0':
134       case '\0':
135         directory = 0;
136         break;
137       case '5':
138         directory = 1;
139         break;
140       default:
141         fprintf(stderr,"Error: unknown type flag %c. Exiting.\n",type);
142         break;
143       }
144       
145       if (directory){
146         in_block = 0;
147         
148         /* makepath will ignore the final path component, so make sure 
149            dirnames have a trailing slash */
150
151         if (fullname[strlen(fullname)-1] != '/')
152           strcat(fullname,"/");
153         if (makepath(fullname)){
154           fprintf(stderr, "Error: cannot create directory %s. Exiting.\n",
155                   fullname);
156           exit(-2);
157         }
158         continue;
159       } else { /*file */
160         in_block = 1;
161         if (outfile){
162           if (fclose(outfile)){
163             fprintf(stderr,"Error: cannot close file %s. Exiting.\n",
164                     fullname);
165             exit(-2);
166           }
167           outfile = (FILE*)0;
168         }
169
170         if ( !(outfile = fopen(fullname,"wb"))){
171           /*try creating the directory, maybe it's not there */
172           if (makepath(fullname)){
173             fprintf(stderr,"Error: cannot create file %s. Exiting.\n",
174                     fullname);
175             exit(-2);
176           }
177           /* now try again to open the file */
178           if (!(outfile = fopen(fullname,"wb"))){
179             fprintf(stderr,"Error: cannot create file %s. Exiting.\n",
180                     fullname);
181             exit(-2);
182           }
183         }
184
185         strncpy(osize,block+124,12);
186         osize[12] = '\0';
187         size = octal(osize);
188         if (size<0){
189           fprintf(stderr,"Error: invalid size in tar header. Exiting.\n");
190           exit(-2);
191         }
192       }
193     } else { /* write or continue writing file contents */
194       nbytes = size>512? 512:size;
195       
196       nwritten = fwrite(block, 1, nbytes, outfile);
197       if (nwritten != nbytes){
198         fprintf(stderr, "Error: only wrote %d bytes to file %s. Exiting.\n",
199                 nwritten, fullname);
200       }
201       size -= nbytes;
202       if (size==0)
203         in_block = 0;
204     }
205   }
206   exit (0);
207 }       
208
209
210
211