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