2 * Copyright (c) 2000, 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. */
21 #include <sys/types.h>
24 #include "zlib/zlib.h"
30 #define FACTOR (0x19db1ded53ea710LL)
31 #define NSPERSEC 10000000LL
32 #define SYMLINK_COOKIE "!<symlink>"
35 char name
[100]; /* 0 */
36 char mode
[8]; /* 100 */
37 char uid
[8]; /* 108 */
38 char gid
[8]; /* 116 */
39 char size
[12]; /* 124 */
40 char mtime
[12]; /* 136 */
41 char chksum
[8]; /* 148 */
42 char typeflag
; /* 156 */
43 char linkname
[100]; /* 157 */
44 char magic
[6]; /* 257 */
45 char version
[2]; /* 263 */
46 char uname
[32]; /* 265 */
47 char gname
[32]; /* 297 */
48 char devmajor
[8]; /* 329 */
49 char devminor
[8]; /* 337 */
50 char prefix
[155]; /* 345 */
51 char junk
[12]; /* 500 */
54 typedef struct tar_map_result_type_s
{
55 struct tar_map_result_type_s
*next
;
58 } tar_map_result_type
;
60 static tar_map_result_type
*tar_map_result
= 0;
64 static char file_name
[_MAX_PATH
+512];
65 static char have_longname
= 0;
66 static int file_length
;
68 static tar_header_type tar_header
;
71 static int _tar_file_size
= 0;
73 FILE * _tar_vfile
= 0;
74 #define vp if (_tar_verbose) fprintf
75 #define vp2 if (_tar_verbose>1) fprintf
82 char *r
= (char *) malloc (strlen (c
) + 1);
90 tar_open (char *pathname
)
96 vp2 (_tar_vfile
, "tar: open `%s'\n", pathname
);
97 if (stat (pathname
, &s
) < 0)
99 _tar_file_size
= s
.st_size
;
101 g
= gzopen (pathname
, "rb");
102 if (sizeof (tar_header
) != 512)
104 /* drastic, but important */
105 fprintf (stderr
, "compilation error: tar header struct not 512"
106 " bytes (it's %d)\n", sizeof (tar_header
));
122 while (file_length
> 0)
124 gzread (g
, buf
, 512);
134 r
= gzread (g
, &tar_header
, 512);
136 /* See if we're at end of file */
140 /* See if the header is all zeros (i.e. last block) */
142 for (r
= 512/sizeof (int); r
; r
--)
143 n
|= ((int *)&tar_header
)[r
-1];
147 if (!have_longname
&& tar_header
.typeflag
!= 'L')
149 memcpy (file_name
, tar_header
.name
, 100);
153 sscanf (tar_header
.size
, "%o", &file_length
);
155 vp2 (_tar_vfile
, "%c %9d %s\n", tar_header
.typeflag
, file_length
, file_name
);
157 switch (tar_header
.typeflag
)
159 case 'L': /* GNU tar long name extension */
160 if (file_length
> _MAX_PATH
)
163 fprintf (stderr
, "error: long file name exceeds %d characters\n",
166 gzread (g
, &tar_header
, 512);
167 sscanf (tar_header
.size
, "%o", &file_length
);
169 return tar_next_file ();
172 while (file_length
> 0)
174 int need
= file_length
> 512 ? 512 : file_length
;
175 if (gzread (g
, buf
, 512) < 512)
177 memcpy (c
, buf
, need
);
183 return tar_next_file ();
186 case '4': /* block */
188 fprintf (stderr
, "warning: not extracting special file %s\n",
191 return tar_next_file ();
193 case '0': /* regular file */
194 case 0: /* regular file also */
195 case '2': /* symbolic link */
196 case '5': /* directory */
197 case '7': /* contiguous file */
200 case '1': /* hard link, we just copy */
204 fprintf (stderr
, "error: unknown (or unsupported) file type `%c'\n",
205 tar_header
.typeflag
);
208 return tar_next_file ();
213 fix_time_stamp (char *path
)
220 sscanf (tar_header
.mtime
, "%o", &mtime
);
221 ftimev
= mtime
* NSPERSEC
+ FACTOR
;
222 ftime
.dwHighDateTime
= ftimev
>> 32;
223 ftime
.dwLowDateTime
= ftimev
;
224 h
= CreateFileA (path
, GENERIC_WRITE
, FILE_SHARE_READ
| FILE_SHARE_WRITE
,
226 FILE_ATTRIBUTE_NORMAL
| FILE_FLAG_BACKUP_SEMANTICS
, 0);
229 SetFileTime (h
, 0, 0, &ftime
);
235 common_fopen (char *path
)
238 out
= fopen (path
, "wb");
241 /* maybe we need to create a directory */
242 if (mkdir_p (0, path
))
247 out
= fopen (path
, "wb");
251 fprintf (stderr
, "unable to write to file %s\n", path
);
252 perror ("The error was");
260 prepare_for_file (char *path
)
265 w
= GetFileAttributes (path
);
266 if (w
!= 0xffffffff && w
& FILE_ATTRIBUTE_DIRECTORY
)
268 char *tmp
= (char *) malloc (strlen (path
) + 10);
272 sprintf (tmp
, "%s.old-%d", path
, i
);
273 } while (GetFileAttributes (tmp
) != 0xffffffff);
274 fprintf (stderr
, "warning: moving directory \"%s\" out of the way.\n", path
);
275 MoveFile (path
, tmp
);
283 tar_read_file (char *path
)
289 tar_map_result_type
*tmr
;
291 switch (tar_header
.typeflag
)
293 case '0': /* regular files */
296 vp (_tar_vfile
, "F %s\n", path
);
297 prepare_for_file (path
);
298 out
= common_fopen (path
);
302 while (file_length
> 0)
305 int want
= file_length
> 512 ? 512 : file_length
;
306 got
= gzread (g
, buf
, 512);
309 fprintf (stderr
, "tar: unexpected end of file reading %s\n", path
);
314 put
= fwrite (buf
, 1, want
, out
);
317 fprintf (stderr
, "tar: out of disk space writing %s\n", path
);
327 fix_time_stamp (path
);
329 /* we need this to do hard links below */
330 tmr
= (tar_map_result_type
*) malloc (sizeof (tar_map_result_type
));
331 tmr
->next
= tar_map_result
;
332 tmr
->stored_name
= xstrdup (file_name
);
333 tmr
->mapped_name
= xstrdup (path
);
334 tar_map_result
= tmr
;
338 case '1': /* hard links; we just copy */
339 for (tmr
= tar_map_result
; tmr
; tmr
=tmr
->next
)
340 if (strcmp (tmr
->stored_name
, tar_header
.linkname
) == 0)
344 fprintf (stderr
, "tar: can't find %s to link %s to\n",
345 tar_header
.linkname
, path
);
348 vp (_tar_vfile
, "H %s <- %s\n", path
, tmr
->mapped_name
);
349 prepare_for_file (path
);
350 copy
= fopen (tmr
->mapped_name
, "rb");
353 fprintf (stderr
, "tar: unable to read %s\n", tmr
->mapped_name
);
356 out
= common_fopen (path
);
360 while ((got
= fread (buf
, 1, 512, copy
)) > 0)
362 int put
= fwrite (buf
, 1, got
, out
);
365 fprintf (stderr
, "tar: out of disk space writing %s\n", path
);
375 fix_time_stamp (path
);
378 case '5': /* directories */
379 vp (_tar_vfile
, "D %s\n", path
);
380 while (path
[0] && path
[strlen (path
)-1] == '/')
381 path
[strlen (path
) - 1] = 0;
382 return mkdir_p (1, path
);
385 case '2': /* symbolic links */
386 vp (_tar_vfile
, "L %s -> %s\n", path
, tar_header
.linkname
);
387 prepare_for_file (path
);
388 h
= CreateFileA (path
, GENERIC_WRITE
, 0, 0, CREATE_NEW
,
389 FILE_ATTRIBUTE_NORMAL
, 0);
390 if (h
== INVALID_HANDLE_VALUE
)
392 fprintf (stderr
, "error: unable to create symlink \"%s\" -> \"%s\"\n",
393 path
, tar_header
.linkname
);
396 strcpy (buf
, SYMLINK_COOKIE
);
397 strcat (buf
, tar_header
.linkname
);
398 if (WriteFile (h
, buf
, strlen (buf
) + 1, &w
, NULL
))
401 SetFileAttributesA (path
, FILE_ATTRIBUTE_SYSTEM
);
405 fprintf (stderr
, "error: unable to write symlink \"%s\"\n", path
);
415 while (tar_map_result
)
417 tar_map_result_type
*t
= tar_map_result
->next
;
418 free (tar_map_result
->stored_name
);
419 free (tar_map_result
->mapped_name
);
420 free (tar_map_result
);
428 return err
; /* includes errors for skipped files, etc */
438 static map_type
*map
;
442 tar_auto (char *pathname
, char **maplist
)
448 char newname
[_MAX_PATH
+512];
449 static char twiddles
[] = "|\b/\b-\b\\\b";
452 for (nmaps
=0; maplist
[nmaps
*2]; nmaps
++) ;
453 map
= (map_type
*) malloc ((nmaps
+1) * sizeof (map_type
));
454 for (nmaps
=0; maplist
[nmaps
*2]; nmaps
++)
456 map
[nmaps
].from
= maplist
[nmaps
*2];
457 map
[nmaps
].from_len
= strlen (maplist
[nmaps
*2]);
458 map
[nmaps
].to
= maplist
[nmaps
*2+1];
459 map
[nmaps
].to_len
= strlen (maplist
[nmaps
*2+1]);
461 /* bubble sort - expect the maps to be short */
462 for (i
=0; i
<nmaps
-1; i
++)
463 for (j
=i
+1; j
<nmaps
; j
++)
464 if (map
[i
].from_len
< map
[j
].from_len
)
471 if (tar_open (pathname
))
473 while (c
= tar_next_file ())
476 for (i
=0; i
<nmaps
; i
++)
477 if (l
>= map
[i
].from_len
478 && strncmp (c
, map
[i
].from
, map
[i
].from_len
) == 0)
480 strcpy (newname
, map
[i
].to
);
481 strcpy (newname
+map
[i
].to_len
, c
+ map
[i
].from_len
);
487 fwrite (twiddles
+t
, 1, 2, stderr
);
489 if (tar_read_file (c
))
495 fwrite (" \b", 1, 2, stderr
);
497 vp2 (_tar_vfile
, "tar_auto returns %d\n", err
);