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