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