Mercurial > hg > xemacs-beta
comparison nt/minitar.c @ 327:03446687b7cc r21-0-61
Import from CVS: tag r21-0-61
author | cvs |
---|---|
date | Mon, 13 Aug 2007 10:48:16 +0200 |
parents | |
children | 8e84bee8ddd0 74fd4e045ea6 9d177e8d4150 |
comparison
equal
deleted
inserted
replaced
326:e2671bc7f66a | 327:03446687b7cc |
---|---|
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 |