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. */
20 #include <sys/types.h>
31 #if defined(CYGWIN) || defined(MINGW)
32 #define FACTOR (0x19db1ded53ea710LL)
33 #define NSPERSEC 10000000LL
35 __int64 FACTOR=0x19db1ded53ea710L;
36 __int64 NSPERSEC=10000000L;
38 #define SYMLINK_COOKIE "!<symlink>"
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 */
60 typedef struct tar_map_result_type_s {
61 struct tar_map_result_type_s *next;
64 } tar_map_result_type;
66 static tar_map_result_type *tar_map_result = 0;
70 static char file_name[_MAX_PATH+512];
71 static char have_longname = 0;
72 static int file_length;
74 static tar_header_type tar_header;
77 static int _tar_file_size = 0;
79 FILE * _tar_vfile = 0;
80 #define vp if (_tar_verbose) fprintf
81 #define vp2 if (_tar_verbose>1) fprintf
88 char *r = (char *) malloc (strlen (c) + 1);
96 tar_open (char *pathname)
102 vp2 (_tar_vfile, "tar: open `%s'\n", pathname);
103 if (stat (pathname, &s) < 0)
105 _tar_file_size = s.st_size;
107 g = gzopen (pathname, "rb");
108 if (sizeof (tar_header) != 512)
110 /* drastic, but important */
111 fprintf (stderr, "compilation error: tar header struct not 512"
112 " bytes (it's %d)\n", sizeof (tar_header));
119 /* For some reason the cygwin version uses a function that is not in
120 the original source. We duplicate it here - although this does mean
121 revealing some internals. */
123 z_off_t ZEXPORT tar_gzctell (gzFile file);
124 typedef struct gz_stream {
126 int z_err; /* error code for last stream operation */
127 int z_eof; /* set if end of input file */
128 FILE *file; /* .gz file */
129 Byte *inbuf; /* input buffer */
130 Byte *outbuf; /* output buffer */
131 uLong crc; /* crc32 of uncompressed data */
132 char *msg; /* error message */
133 char *path; /* path name for debugging only */
134 int transparent; /* 1 if input file is not a .gz file */
135 char mode; /* 'w' or 'r' */
136 long startpos; /* start of compressed data in file (header skipped) */
140 z_off_t ZEXPORT tar_gzctell (gzFile file)
142 gz_stream *s = (gz_stream *)file;
143 return ftell(s->file);
149 return tar_gzctell (g);
155 while (file_length > 0)
157 gzread (g, buf, 512);
167 r = gzread (g, &tar_header, 512);
169 /* See if we're at end of file */
173 /* See if the header is all zeros (i.e. last block) */
175 for (r = 512/sizeof (int); r; r--)
176 n |= ((int *)&tar_header)[r-1];
180 if (!have_longname && tar_header.typeflag != 'L')
182 memcpy (file_name, tar_header.name, 100);
186 sscanf (tar_header.size, "%o", &file_length);
188 vp2 (_tar_vfile, "%c %9d %s\n", tar_header.typeflag, file_length, file_name);
190 switch (tar_header.typeflag)
192 case 'L': /* GNU tar long name extension */
193 if (file_length > _MAX_PATH)
196 fprintf (stderr, "error: long file name exceeds %d characters\n",
199 gzread (g, &tar_header, 512);
200 sscanf (tar_header.size, "%o", &file_length);
202 return tar_next_file ();
205 while (file_length > 0)
207 int need = file_length > 512 ? 512 : file_length;
208 if (gzread (g, buf, 512) < 512)
210 memcpy (c, buf, need);
216 return tar_next_file ();
219 case '4': /* block */
221 fprintf (stderr, "warning: not extracting special file %s\n",
224 return tar_next_file ();
226 case '0': /* regular file */
227 case 0: /* regular file also */
228 case '2': /* symbolic link */
229 case '5': /* directory */
230 case '7': /* contiguous file */
233 case '1': /* hard link, we just copy */
237 fprintf (stderr, "error: unknown (or unsupported) file type `%c'\n",
238 tar_header.typeflag);
241 return tar_next_file ();
246 fix_time_stamp (char *path)
249 #if defined(CYGWIN) || defined(MINGW)
257 sscanf (tar_header.mtime, "%o", &mtime);
258 ftimev = mtime * NSPERSEC + FACTOR;
259 ftime.dwHighDateTime = ftimev >> 32;
260 ftime.dwLowDateTime = ftimev;
261 h = CreateFileA (path, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
263 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS, 0);
266 SetFileTime (h, 0, 0, &ftime);
272 common_fopen (char *path)
275 out = fopen (path, "wb");
278 /* maybe we need to create a directory */
279 if (mkdir_p (0, path))
284 out = fopen (path, "wb");
288 fprintf (stderr, "unable to write to file %s\n", path);
289 perror ("The error was");
297 prepare_for_file (char *path)
302 w = GetFileAttributes (path);
303 if (w != 0xffffffff && w & FILE_ATTRIBUTE_DIRECTORY)
305 char *tmp = (char *) malloc (strlen (path) + 10);
309 sprintf (tmp, "%s.old-%d", path, i);
310 } while (GetFileAttributes (tmp) != 0xffffffff);
311 fprintf (stderr, "warning: moving directory \"%s\" out of the way.\n", path);
312 MoveFile (path, tmp);
320 tar_read_file (char *path)
326 tar_map_result_type *tmr;
328 switch (tar_header.typeflag)
330 case '0': /* regular files */
333 vp (_tar_vfile, "F %s\n", path);
334 prepare_for_file (path);
335 out = common_fopen (path);
339 while (file_length > 0)
342 int want = file_length > 512 ? 512 : file_length;
343 got = gzread (g, buf, 512);
346 fprintf (stderr, "tar: unexpected end of file reading %s\n", path);
351 put = fwrite (buf, 1, want, out);
354 fprintf (stderr, "tar: out of disk space writing %s\n", path);
364 fix_time_stamp (path);
366 /* we need this to do hard links below */
367 tmr = (tar_map_result_type *) malloc (sizeof (tar_map_result_type));
368 tmr->next = tar_map_result;
369 tmr->stored_name = xstrdup (file_name);
370 tmr->mapped_name = xstrdup (path);
371 tar_map_result = tmr;
375 case '1': /* hard links; we just copy */
376 for (tmr = tar_map_result; tmr; tmr=tmr->next)
377 if (strcmp (tmr->stored_name, tar_header.linkname) == 0)
381 fprintf (stderr, "tar: can't find %s to link %s to\n",
382 tar_header.linkname, path);
385 vp (_tar_vfile, "H %s <- %s\n", path, tmr->mapped_name);
386 prepare_for_file (path);
387 copy = fopen (tmr->mapped_name, "rb");
390 fprintf (stderr, "tar: unable to read %s\n", tmr->mapped_name);
393 out = common_fopen (path);
397 while ((got = fread (buf, 1, 512, copy)) > 0)
399 int put = fwrite (buf, 1, got, out);
402 fprintf (stderr, "tar: out of disk space writing %s\n", path);
412 fix_time_stamp (path);
415 case '5': /* directories */
416 vp (_tar_vfile, "D %s\n", path);
417 while (path[0] && path[strlen (path)-1] == '/')
418 path[strlen (path) - 1] = 0;
419 return mkdir_p (1, path);
422 case '2': /* symbolic links */
423 vp (_tar_vfile, "L %s -> %s\n", path, tar_header.linkname);
424 prepare_for_file (path);
425 h = CreateFileA (path, GENERIC_WRITE, 0, 0, CREATE_NEW,
426 FILE_ATTRIBUTE_NORMAL, 0);
427 if (h == INVALID_HANDLE_VALUE)
429 fprintf (stderr, "error: unable to create symlink \"%s\" -> \"%s\"\n",
430 path, tar_header.linkname);
433 strcpy (buf, SYMLINK_COOKIE);
434 strcat (buf, tar_header.linkname);
435 if (WriteFile (h, buf, strlen (buf) + 1, &w, NULL))
438 SetFileAttributesA (path, FILE_ATTRIBUTE_SYSTEM);
442 fprintf (stderr, "error: unable to write symlink \"%s\"\n", path);
454 while (tar_map_result)
456 tar_map_result_type *t = tar_map_result->next;
457 free (tar_map_result->stored_name);
458 free (tar_map_result->mapped_name);
459 free (tar_map_result);
467 return err; /* includes errors for skipped files, etc */
477 static map_type *map;
481 tar_auto (char *pathname, char **maplist)
487 char newname[_MAX_PATH+512];
488 static char twiddles[] = "|\b/\b-\b\\\b";
491 for (nmaps=0; maplist[nmaps*2]; nmaps++) ;
492 map = (map_type *) malloc ((nmaps+1) * sizeof (map_type));
493 for (nmaps=0; maplist[nmaps*2]; nmaps++)
495 map[nmaps].from = maplist[nmaps*2];
496 map[nmaps].from_len = strlen (maplist[nmaps*2]);
497 map[nmaps].to = maplist[nmaps*2+1];
498 map[nmaps].to_len = strlen (maplist[nmaps*2+1]);
500 /* bubble sort - expect the maps to be short */
501 for (i=0; i<nmaps-1; i++)
502 for (j=i+1; j<nmaps; j++)
503 if (map[i].from_len < map[j].from_len)
510 if ((tar_open (pathname)))
512 while ((c = tar_next_file ()))
515 for (i=0; i<nmaps; i++)
516 if (l >= map[i].from_len
517 && strncmp (c, map[i].from, map[i].from_len) == 0)
519 strcpy (newname, map[i].to);
520 strcpy (newname+map[i].to_len, c + map[i].from_len);
526 fwrite (twiddles+t, 1, 2, stderr);
528 if (tar_read_file (c))
534 fwrite (" \b", 1, 2, stderr);
536 vp2 (_tar_vfile, "tar_auto returns %d\n", errcount);