]> cygwin.com Git - cygwin-apps/setup.git/blob - tar.cc
* net.cc (do_net): Default to direct download.
[cygwin-apps/setup.git] / tar.cc
1 /*
2 * Copyright (c) 2000, 2001, Red Hat, Inc.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * A copy of the GNU General Public License can be found at
10 * http://www.gnu.org/
11 *
12 * Written by DJ Delorie <dj@cygnus.com>
13 *
14 */
15
16 /* Built-in tar functionality. See tar.h for usage. */
17
18 static char *cvsid = "\n%%% $Id$\n";
19
20 #include "win32.h"
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <sys/types.h>
24 #include <sys/fcntl.h>
25
26 #include "zlib/zlib.h"
27 #include "tar.h"
28 #include "mkdir.h"
29 #include "log.h"
30
31 #include "port.h"
32 #undef _WIN32
33 #include "bzlib.h"
34
35 #define FACTOR (0x19db1ded53ea710LL)
36 #define NSPERSEC 10000000LL
37 #define SYMLINK_COOKIE "!<symlink>"
38
39 extern DWORD get_file_size (char *);
40
41 typedef struct {
42 char name[100]; /* 0 */
43 char mode[8]; /* 100 */
44 char uid[8]; /* 108 */
45 char gid[8]; /* 116 */
46 char size[12]; /* 124 */
47 char mtime[12]; /* 136 */
48 char chksum[8]; /* 148 */
49 char typeflag; /* 156 */
50 char linkname[100]; /* 157 */
51 char magic[6]; /* 257 */
52 char version[2]; /* 263 */
53 char uname[32]; /* 265 */
54 char gname[32]; /* 297 */
55 char devmajor[8]; /* 329 */
56 char devminor[8]; /* 337 */
57 char prefix[155]; /* 345 */
58 char junk[12]; /* 500 */
59 } tar_header_type;
60
61 typedef struct tar_map_result_type_s {
62 struct tar_map_result_type_s *next;
63 char *stored_name;
64 char *mapped_name;
65 } tar_map_result_type;
66
67 static tar_map_result_type *tar_map_result = 0;
68
69 static int err;
70
71 static char file_name[_MAX_PATH+512];
72 static char have_longname = 0;
73 static int file_length;
74
75 static tar_header_type tar_header;
76 static char buf[512];
77
78 static int _tar_file_size = 0;
79 int _tar_verbose = 0;
80 FILE * _tar_vfile = 0;
81 #define vp if (_tar_verbose) fprintf
82 #define vp2 if (_tar_verbose>1) fprintf
83
84 class gzbz
85 {
86 protected:
87 union
88 {
89 gzFile g;
90 BZFILE *b;
91 };
92 int fd;
93 public:
94 virtual int read (void *buf, int len) {};
95 virtual int close () {};
96 virtual off_t tell () {};
97 operator int () {return (int) g;}
98 };
99
100 class gz: public gzbz
101 {
102 public:
103 gz (const char *pathname)
104 {
105 g = gzopen (pathname, "rb");
106 }
107 int read (void *buf, int len)
108 {
109 return gzread (g, buf, len);
110 }
111 int close ()
112 {
113 return gzclose (g);
114 }
115 off_t tell () {return gzctell (g);}
116 ~gz () {close ();}
117 };
118
119 class bz: public gzbz
120 {
121 public:
122 bz (const char *pathname)
123 {
124 fd = open (pathname, O_RDONLY | O_BINARY);
125 if (fd)
126 b = BZ2_bzdopen (fd, "rb");
127 else
128 b = NULL;
129 }
130 int read (void *buf, int len)
131 {
132 return BZ2_bzread (b, buf, len);
133 }
134 int close ()
135 {
136 BZ2_bzclose (b);
137 return 0;
138 }
139 off_t tell () {return ::tell (fd);}
140 ~bz () {close ();}
141 };
142
143 gzbz *z = NULL;
144
145 static char *
146 xstrdup (char *c)
147 {
148 char *r = (char *) malloc (strlen (c) + 1);
149 if (!r)
150 exit_setup (1);
151 strcpy (r, c);
152 return r;
153 }
154
155 int
156 tar_open (char *pathname)
157 {
158 if (_tar_vfile == 0)
159 _tar_vfile = stderr;
160
161 vp2 (_tar_vfile, "tar: open `%s'\n", pathname);
162 DWORD size;
163 if ((size = get_file_size (pathname)) == 0)
164 return 1;
165 _tar_file_size = size;
166
167 if (strstr (pathname, ".bz2"))
168 z = new bz (pathname);
169 else
170 z = new gz (pathname);
171 if (sizeof (tar_header) != 512)
172 {
173 /* drastic, but important */
174 fprintf (stderr, "compilation error: tar header struct not 512"
175 " bytes (it's %d)\n", sizeof (tar_header));
176 exit_setup (1);
177 }
178 err = 0;
179 return *z ? 0 : 1;
180 }
181
182 int
183 tar_ftell ()
184 {
185 return z->tell ();
186 }
187
188 static void
189 skip_file ()
190 {
191 while (file_length > 0)
192 {
193 z->read (buf, 512);
194 file_length -= 512;
195 }
196 }
197
198 char *
199 tar_next_file ()
200 {
201 int r, n;
202 char *c;
203 r = z->read (&tar_header, 512);
204
205 /* See if we're at end of file */
206 if (r != 512)
207 return 0;
208
209 /* See if the header is all zeros (i.e. last block) */
210 n = 0;
211 for (r = 512/sizeof (int); r; r--)
212 n |= ((int *)&tar_header)[r-1];
213 if (n == 0)
214 return 0;
215
216 if (!have_longname && tar_header.typeflag != 'L')
217 {
218 memcpy (file_name, tar_header.name, 100);
219 file_name[100] = 0;
220 }
221
222 sscanf (tar_header.size, "%o", &file_length);
223
224 vp2 (_tar_vfile, "%c %9d %s\n", tar_header.typeflag, file_length, file_name);
225
226 switch (tar_header.typeflag)
227 {
228 case 'L': /* GNU tar long name extension */
229 if (file_length > _MAX_PATH)
230 {
231 skip_file ();
232 fprintf (stderr, "error: long file name exceeds %d characters\n",
233 _MAX_PATH);
234 err++;
235 z->read (&tar_header, 512);
236 sscanf (tar_header.size, "%o", &file_length);
237 skip_file ();
238 return tar_next_file ();
239 }
240 c = file_name;
241 while (file_length > 0)
242 {
243 int need = file_length > 512 ? 512 : file_length;
244 if (z->read (buf, 512) < 512)
245 return 0;
246 memcpy (c, buf, need);
247 c += need;
248 file_length -= need;
249 }
250 *c = 0;
251 have_longname = 1;
252 return tar_next_file ();
253
254 case '3': /* char */
255 case '4': /* block */
256 case '6': /* fifo */
257 fprintf (stderr, "warning: not extracting special file %s\n",
258 file_name);
259 err++;
260 return tar_next_file ();
261
262 case '0': /* regular file */
263 case 0: /* regular file also */
264 case '2': /* symbolic link */
265 case '5': /* directory */
266 case '7': /* contiguous file */
267 return file_name;
268
269 case '1': /* hard link, we just copy */
270 return file_name;
271
272 default:
273 fprintf (stderr, "error: unknown (or unsupported) file type `%c'\n",
274 tar_header.typeflag);
275 err++;
276 skip_file ();
277 return tar_next_file ();
278 }
279 }
280
281 static void
282 fix_time_stamp (char *path)
283 {
284 int mtime;
285 long long ftimev;
286 FILETIME ftime;
287 HANDLE h;
288
289 sscanf (tar_header.mtime, "%o", &mtime);
290 ftimev = mtime * NSPERSEC + FACTOR;
291 ftime.dwHighDateTime = ftimev >> 32;
292 ftime.dwLowDateTime = ftimev;
293 h = CreateFileA (path, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
294 0, OPEN_EXISTING,
295 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS, 0);
296 if (h)
297 {
298 SetFileTime (h, 0, 0, &ftime);
299 CloseHandle (h);
300 }
301 }
302
303 static FILE *
304 common_fopen (char *path)
305 {
306 FILE *out;
307 out = fopen (path, "wb");
308 if (!out)
309 {
310 /* maybe we need to create a directory */
311 if (mkdir_p (0, path))
312 {
313 skip_file ();
314 return 0;
315 }
316 out = fopen (path, "wb");
317 }
318 if (!out)
319 {
320 fprintf (stderr, "unable to write to file %s\n", path);
321 perror ("The error was");
322 skip_file ();
323 return 0;
324 }
325 return out;
326 }
327
328 static void
329 prepare_for_file (char *path)
330 {
331 DWORD w;
332 mkdir_p (0, path);
333
334 w = GetFileAttributes (path);
335 if (w != 0xffffffff && w & FILE_ATTRIBUTE_DIRECTORY)
336 {
337 char *tmp = (char *) malloc (strlen (path) + 10);
338 int i = 0;
339 do {
340 i++;
341 sprintf (tmp, "%s.old-%d", path, i);
342 } while (GetFileAttributes (tmp) != 0xffffffff);
343 fprintf (stderr, "warning: moving directory \"%s\" out of the way.\n", path);
344 MoveFile (path, tmp);
345 free (tmp);
346 }
347
348 DeleteFileA (path);
349 }
350
351 int
352 tar_read_file (char *path)
353 {
354 FILE *out, *copy;
355 HANDLE h;
356 DWORD w, startticks;
357 int got;
358 tar_map_result_type *tmr;
359
360 switch (tar_header.typeflag)
361 {
362 case '0': /* regular files */
363 case 0:
364 case '7':
365 vp (_tar_vfile, "F %s\n", path);
366 prepare_for_file (path);
367 out = common_fopen (path);
368 if (!out)
369 return 1;
370
371 while (file_length > 0)
372 {
373 int put;
374 int want = file_length > 512 ? 512 : file_length;
375 got = z->read (buf, 512);
376 if (got < 512)
377 {
378 fprintf (stderr, "tar: unexpected end of file reading %s\n", path);
379 fclose (out);
380 remove (path);
381 return 1;
382 }
383 put = fwrite (buf, 1, want, out);
384 if (put < want)
385 {
386 fprintf (stderr, "tar: out of disk space writing %s\n", path);
387 fclose (out);
388 remove (path);
389 skip_file ();
390 return 1;
391 }
392 file_length -= want;
393 }
394 fclose (out);
395
396 fix_time_stamp (path);
397
398 /* we need this to do hard links below */
399 tmr = (tar_map_result_type *) malloc (sizeof (tar_map_result_type));
400 tmr->next = tar_map_result;
401 tmr->stored_name = xstrdup (file_name);
402 tmr->mapped_name = xstrdup (path);
403 tar_map_result = tmr;
404
405 return 0;
406
407 case '1': /* hard links; we just copy */
408 for (tmr = tar_map_result; tmr; tmr=tmr->next)
409 if (strcmp (tmr->stored_name, tar_header.linkname) == 0)
410 break;
411 if (!tmr)
412 {
413 fprintf (stderr, "tar: can't find %s to link %s to\n",
414 tar_header.linkname, path);
415 return 1;
416 }
417 vp (_tar_vfile, "H %s <- %s\n", path, tmr->mapped_name);
418 prepare_for_file (path);
419 copy = fopen (tmr->mapped_name, "rb");
420 if (!copy)
421 {
422 fprintf (stderr, "tar: unable to read %s\n", tmr->mapped_name);
423 return 1;
424 }
425 out = common_fopen (path);
426 if (!out)
427 return 1;
428
429 while ((got = fread (buf, 1, 512, copy)) > 0)
430 {
431 int put = fwrite (buf, 1, got, out);
432 if (put < got)
433 {
434 fprintf (stderr, "tar: out of disk space writing %s\n", path);
435 fclose (out);
436 fclose (copy);
437 remove (path);
438 return 1;
439 }
440 }
441 fclose (out);
442 fclose (copy);
443
444 fix_time_stamp (path);
445 return 0;
446
447 case '5': /* directories */
448 vp (_tar_vfile, "D %s\n", path);
449 while (path[0] && path[strlen (path)-1] == '/')
450 path[strlen (path) - 1] = 0;
451 return mkdir_p (1, path);
452
453
454 case '2': /* symbolic links */
455 vp (_tar_vfile, "L %s -> %s\n", path, tar_header.linkname);
456 prepare_for_file (path);
457 h = CreateFileA (path, GENERIC_WRITE, 0, 0, CREATE_NEW,
458 FILE_ATTRIBUTE_NORMAL, 0);
459 if (h == INVALID_HANDLE_VALUE)
460 {
461 fprintf (stderr, "error: unable to create symlink \"%s\" -> \"%s\"\n",
462 path, tar_header.linkname);
463 return 1;
464 }
465 strcpy (buf, SYMLINK_COOKIE);
466 strcat (buf, tar_header.linkname);
467 if (WriteFile (h, buf, strlen (buf) + 1, &w, NULL))
468 {
469 CloseHandle (h);
470 SetFileAttributesA (path, FILE_ATTRIBUTE_SYSTEM);
471 return 0;
472 }
473 CloseHandle (h);
474 fprintf (stderr, "error: unable to write symlink \"%s\"\n", path);
475 DeleteFileA (path);
476 return 1;
477 }
478 }
479
480 int
481 tar_close ()
482 {
483 #if 0
484 while (tar_map_result)
485 {
486 tar_map_result_type *t = tar_map_result->next;
487 free (tar_map_result->stored_name);
488 free (tar_map_result->mapped_name);
489 free (tar_map_result);
490 tar_map_result = t;
491 }
492 #endif
493 tar_map_result = 0;
494
495 if (z->close ())
496 err++;
497 return err; /* includes errors for skipped files, etc */
498 }
499
500 typedef struct {
501 char *from;
502 int from_len;
503 char *to;
504 int to_len;
505 } map_type;
506
507 static map_type *map;
508 static int nmaps;
509
510 int
511 tar_auto (char *pathname, char **maplist)
512 {
513 char *c;
514 int err = 0;
515 int i, j;
516 map_type mtemp;
517 char newname[_MAX_PATH+512];
518 static char twiddles[] = "|\b/\b-\b\\\b";
519 int t = 0;
520
521 for (nmaps=0; maplist[nmaps*2]; nmaps++) ;
522 map = (map_type *) malloc ((nmaps+1) * sizeof (map_type));
523 for (nmaps=0; maplist[nmaps*2]; nmaps++)
524 {
525 map[nmaps].from = maplist[nmaps*2];
526 map[nmaps].from_len = strlen (maplist[nmaps*2]);
527 map[nmaps].to = maplist[nmaps*2+1];
528 map[nmaps].to_len = strlen (maplist[nmaps*2+1]);
529 }
530 /* bubble sort - expect the maps to be short */
531 for (i=0; i<nmaps-1; i++)
532 for (j=i+1; j<nmaps; j++)
533 if (map[i].from_len < map[j].from_len)
534 {
535 mtemp = map[i];
536 map[i] = map[j];
537 map[j] = mtemp;
538 }
539
540 if (tar_open (pathname))
541 return 1;
542 while (c = tar_next_file ())
543 {
544 int l = strlen (c);
545 for (i=0; i<nmaps; i++)
546 if (l >= map[i].from_len
547 && strncmp (c, map[i].from, map[i].from_len) == 0)
548 {
549 strcpy (newname, map[i].to);
550 strcpy (newname+map[i].to_len, c + map[i].from_len);
551 c = newname;
552 break;
553 }
554
555 t = (t+2) % 8;
556 fwrite (twiddles+t, 1, 2, stderr);
557
558 if (tar_read_file (c))
559 err++;
560 }
561 if (tar_close ())
562 err++;
563
564 fwrite (" \b", 1, 2, stderr);
565
566 vp2 (_tar_vfile, "tar_auto returns %d\n", err);
567 return err;
568 }
This page took 0.059331 seconds and 5 git commands to generate.