2 * Copyright (c) 2000, 2001, Red Hat, Inc.
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.
9 * A copy of the GNU General Public License can be found at
12 * Written by DJ Delorie <dj@cygnus.com>
16 /* Built-in tar functionality. See tar.h for usage. */
18 static char *cvsid
= "\n%%% $Id$\n";
23 #include <sys/types.h>
24 #include <sys/fcntl.h>
26 #include "zlib/zlib.h"
35 #define FACTOR (0x19db1ded53ea710LL)
36 #define NSPERSEC 10000000LL
37 #define SYMLINK_COOKIE "!<symlink>"
39 extern DWORD
get_file_size (char *);
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 */
61 typedef struct tar_map_result_type_s
{
62 struct tar_map_result_type_s
*next
;
65 } tar_map_result_type
;
67 static tar_map_result_type
*tar_map_result
= 0;
71 static char file_name
[_MAX_PATH
+512];
72 static char have_longname
= 0;
73 static int file_length
;
75 static tar_header_type tar_header
;
78 static int _tar_file_size
= 0;
80 FILE * _tar_vfile
= 0;
81 #define vp if (_tar_verbose) fprintf
82 #define vp2 if (_tar_verbose>1) fprintf
94 virtual int read (void *buf
, int len
) {};
95 virtual int close () {};
96 virtual off_t
tell () {};
97 operator int () {return (int) g
;}
100 class gz
: public gzbz
103 gz (const char *pathname
)
105 g
= gzopen (pathname
, "rb");
107 int read (void *buf
, int len
)
109 return gzread (g
, buf
, len
);
115 off_t
tell () {return gzctell (g
);}
119 class bz
: public gzbz
122 bz (const char *pathname
)
124 fd
= open (pathname
, O_RDONLY
| O_BINARY
);
126 b
= BZ2_bzdopen (fd
, "rb");
130 int read (void *buf
, int len
)
132 return BZ2_bzread (b
, buf
, len
);
139 off_t
tell () {return ::tell (fd
);}
148 char *r
= (char *) malloc (strlen (c
) + 1);
156 tar_open (char *pathname
)
161 vp2 (_tar_vfile
, "tar: open `%s'\n", pathname
);
163 if ((size
= get_file_size (pathname
)) == 0)
165 _tar_file_size
= size
;
167 if (strstr (pathname
, ".bz2"))
168 z
= new bz (pathname
);
170 z
= new gz (pathname
);
171 if (sizeof (tar_header
) != 512)
173 /* drastic, but important */
174 fprintf (stderr
, "compilation error: tar header struct not 512"
175 " bytes (it's %d)\n", sizeof (tar_header
));
191 while (file_length
> 0)
203 r
= z
->read (&tar_header
, 512);
205 /* See if we're at end of file */
209 /* See if the header is all zeros (i.e. last block) */
211 for (r
= 512/sizeof (int); r
; r
--)
212 n
|= ((int *)&tar_header
)[r
-1];
216 if (!have_longname
&& tar_header
.typeflag
!= 'L')
218 memcpy (file_name
, tar_header
.name
, 100);
222 sscanf (tar_header
.size
, "%o", &file_length
);
224 vp2 (_tar_vfile
, "%c %9d %s\n", tar_header
.typeflag
, file_length
, file_name
);
226 switch (tar_header
.typeflag
)
228 case 'L': /* GNU tar long name extension */
229 if (file_length
> _MAX_PATH
)
232 fprintf (stderr
, "error: long file name exceeds %d characters\n",
235 z
->read (&tar_header
, 512);
236 sscanf (tar_header
.size
, "%o", &file_length
);
238 return tar_next_file ();
241 while (file_length
> 0)
243 int need
= file_length
> 512 ? 512 : file_length
;
244 if (z
->read (buf
, 512) < 512)
246 memcpy (c
, buf
, need
);
252 return tar_next_file ();
255 case '4': /* block */
257 fprintf (stderr
, "warning: not extracting special file %s\n",
260 return tar_next_file ();
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 */
269 case '1': /* hard link, we just copy */
273 fprintf (stderr
, "error: unknown (or unsupported) file type `%c'\n",
274 tar_header
.typeflag
);
277 return tar_next_file ();
282 fix_time_stamp (char *path
)
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
,
295 FILE_ATTRIBUTE_NORMAL
| FILE_FLAG_BACKUP_SEMANTICS
, 0);
298 SetFileTime (h
, 0, 0, &ftime
);
304 common_fopen (char *path
)
307 out
= fopen (path
, "wb");
310 /* maybe we need to create a directory */
311 if (mkdir_p (0, path
))
316 out
= fopen (path
, "wb");
320 fprintf (stderr
, "unable to write to file %s\n", path
);
321 perror ("The error was");
329 prepare_for_file (char *path
)
334 w
= GetFileAttributes (path
);
335 if (w
!= 0xffffffff && w
& FILE_ATTRIBUTE_DIRECTORY
)
337 char *tmp
= (char *) malloc (strlen (path
) + 10);
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
);
352 tar_read_file (char *path
)
358 tar_map_result_type
*tmr
;
360 switch (tar_header
.typeflag
)
362 case '0': /* regular files */
365 vp (_tar_vfile
, "F %s\n", path
);
366 prepare_for_file (path
);
367 out
= common_fopen (path
);
371 while (file_length
> 0)
374 int want
= file_length
> 512 ? 512 : file_length
;
375 got
= z
->read (buf
, 512);
378 fprintf (stderr
, "tar: unexpected end of file reading %s\n", path
);
383 put
= fwrite (buf
, 1, want
, out
);
386 fprintf (stderr
, "tar: out of disk space writing %s\n", path
);
396 fix_time_stamp (path
);
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
;
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)
413 fprintf (stderr
, "tar: can't find %s to link %s to\n",
414 tar_header
.linkname
, path
);
417 vp (_tar_vfile
, "H %s <- %s\n", path
, tmr
->mapped_name
);
418 prepare_for_file (path
);
419 copy
= fopen (tmr
->mapped_name
, "rb");
422 fprintf (stderr
, "tar: unable to read %s\n", tmr
->mapped_name
);
425 out
= common_fopen (path
);
429 while ((got
= fread (buf
, 1, 512, copy
)) > 0)
431 int put
= fwrite (buf
, 1, got
, out
);
434 fprintf (stderr
, "tar: out of disk space writing %s\n", path
);
444 fix_time_stamp (path
);
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
);
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
)
461 fprintf (stderr
, "error: unable to create symlink \"%s\" -> \"%s\"\n",
462 path
, tar_header
.linkname
);
465 strcpy (buf
, SYMLINK_COOKIE
);
466 strcat (buf
, tar_header
.linkname
);
467 if (WriteFile (h
, buf
, strlen (buf
) + 1, &w
, NULL
))
470 SetFileAttributesA (path
, FILE_ATTRIBUTE_SYSTEM
);
474 fprintf (stderr
, "error: unable to write symlink \"%s\"\n", path
);
484 while (tar_map_result
)
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
);
497 return err
; /* includes errors for skipped files, etc */
507 static map_type
*map
;
511 tar_auto (char *pathname
, char **maplist
)
517 char newname
[_MAX_PATH
+512];
518 static char twiddles
[] = "|\b/\b-\b\\\b";
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
++)
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]);
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
)
540 if (tar_open (pathname
))
542 while (c
= tar_next_file ())
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)
549 strcpy (newname
, map
[i
].to
);
550 strcpy (newname
+map
[i
].to_len
, c
+ map
[i
].from_len
);
556 fwrite (twiddles
+t
, 1, 2, stderr
);
558 if (tar_read_file (c
))
564 fwrite (" \b", 1, 2, stderr
);
566 vp2 (_tar_vfile
, "tar_auto returns %d\n", err
);