]> cygwin.com Git - cygwin-apps/setup.git/blame - tar.cc
* coding standards fixups, many files
[cygwin-apps/setup.git] / tar.cc
CommitLineData
c1a6a761
DD
1/*
2 * Copyright (c) 2000, 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
23c9e63c
DD
16/* Built-in tar functionality. See tar.h for usage. */
17
18#include "win32.h"
99d1bf2d
DD
19#include <stdio.h>
20#include <stdlib.h>
23c9e63c
DD
21#include <sys/types.h>
22#include <sys/stat.h>
23
99d1bf2d
DD
24#include "zlib/zlib.h"
25#include "tar.h"
23c9e63c
DD
26#include "mkdir.h"
27
28#include "port.h"
99d1bf2d
DD
29
30#define FACTOR (0x19db1ded53ea710LL)
31#define NSPERSEC 10000000LL
32#define SYMLINK_COOKIE "!<symlink>"
33
34typedef struct {
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 */
52} tar_header_type;
53
54typedef struct tar_map_result_type_s {
55 struct tar_map_result_type_s *next;
56 char *stored_name;
57 char *mapped_name;
58} tar_map_result_type;
59
60static tar_map_result_type *tar_map_result = 0;
61
62static int err;
63
64static char file_name[_MAX_PATH+512];
65static char have_longname = 0;
66static int file_length;
67
68static tar_header_type tar_header;
69static char buf[512];
70
23c9e63c 71static int _tar_file_size = 0;
99d1bf2d
DD
72int _tar_verbose = 0;
73FILE * _tar_vfile = 0;
1fd6d0a2
DD
74#define vp if (_tar_verbose) fprintf
75#define vp2 if (_tar_verbose>1) fprintf
99d1bf2d 76
23c9e63c 77static gzFile g = 0;
99d1bf2d
DD
78
79static char *
80xstrdup (char *c)
81{
82 char *r = (char *) malloc (strlen (c) + 1);
83 if (!r)
84 exit (1);
85 strcpy (r, c);
86 return r;
87}
88
89int
90tar_open (char *pathname)
91{
23c9e63c 92 struct stat s;
99d1bf2d
DD
93 if (_tar_vfile == 0)
94 _tar_vfile = stderr;
95
96 vp2 (_tar_vfile, "tar: open `%s'\n", pathname);
23c9e63c
DD
97 if (stat (pathname, &s) < 0)
98 return 1;
99 _tar_file_size = s.st_size;
100
99d1bf2d
DD
101 g = gzopen (pathname, "rb");
102 if (sizeof (tar_header) != 512)
103 {
104 /* drastic, but important */
105 fprintf (stderr, "compilation error: tar header struct not 512"
106 " bytes (it's %d)\n", sizeof (tar_header));
107 exit (1);
108 }
109 err = 0;
110 return g ? 0 : 1;
111}
112
23c9e63c
DD
113int
114tar_ftell ()
115{
116 return gzctell (g);
117}
118
99d1bf2d
DD
119static void
120skip_file ()
121{
122 while (file_length > 0)
123 {
124 gzread (g, buf, 512);
125 file_length -= 512;
126 }
127}
128
129char *
130tar_next_file ()
131{
132 int r, n;
133 char *c;
1fd6d0a2 134 r = gzread (g, &tar_header, 512);
99d1bf2d
DD
135
136 /* See if we're at end of file */
137 if (r != 512)
138 return 0;
139
140 /* See if the header is all zeros (i.e. last block) */
141 n = 0;
1fd6d0a2 142 for (r = 512/sizeof (int); r; r--)
99d1bf2d
DD
143 n |= ((int *)&tar_header)[r-1];
144 if (n == 0)
145 return 0;
146
147 if (!have_longname && tar_header.typeflag != 'L')
148 {
1fd6d0a2 149 memcpy (file_name, tar_header.name, 100);
99d1bf2d
DD
150 file_name[100] = 0;
151 }
152
1fd6d0a2 153 sscanf (tar_header.size, "%o", &file_length);
99d1bf2d
DD
154
155 vp2 (_tar_vfile, "%c %9d %s\n", tar_header.typeflag, file_length, file_name);
156
157 switch (tar_header.typeflag)
158 {
159 case 'L': /* GNU tar long name extension */
160 if (file_length > _MAX_PATH)
161 {
162 skip_file ();
1fd6d0a2
DD
163 fprintf (stderr, "error: long file name exceeds %d characters\n",
164 _MAX_PATH);
99d1bf2d
DD
165 err ++;
166 gzread (g, &tar_header, 512);
1fd6d0a2 167 sscanf (tar_header.size, "%o", &file_length);
99d1bf2d
DD
168 skip_file ();
169 return tar_next_file ();
170 }
171 c = file_name;
172 while (file_length > 0)
173 {
174 int need = file_length > 512 ? 512 : file_length;
175 if (gzread (g, buf, 512) < 512)
176 return 0;
177 memcpy (c, buf, need);
178 c += need;
179 file_length -= need;
180 }
181 *c = 0;
182 have_longname = 1;
183 return tar_next_file ();
184
185 case '3': /* char */
186 case '4': /* block */
187 case '6': /* fifo */
1fd6d0a2
DD
188 fprintf (stderr, "warning: not extracting special file %s\n",
189 file_name);
99d1bf2d
DD
190 err ++;
191 return tar_next_file ();
192
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 */
198 return file_name;
199
200 case '1': /* hard link, we just copy */
201 return file_name;
202
203 default:
204 fprintf (stderr, "error: unknown (or unsupported) file type `%c'\n",
205 tar_header.typeflag);
206 err ++;
207 skip_file ();
208 return tar_next_file ();
209 }
210}
211
99d1bf2d
DD
212static void
213fix_time_stamp (char *path)
214{
215 int mtime;
216 long long ftimev;
217 FILETIME ftime;
218 HANDLE h;
219
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,
225 0, OPEN_EXISTING,
226 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS, 0);
227 if (h)
228 {
229 SetFileTime (h, 0, 0, &ftime);
230 CloseHandle (h);
231 }
232}
233
234static FILE *
235common_fopen (char *path)
236{
237 FILE *out;
238 out = fopen (path, "wb");
239 if (!out)
240 {
241 /* maybe we need to create a directory */
242 if (mkdir_p (0, path))
243 {
244 skip_file ();
245 return 0;
246 }
247 out = fopen (path, "wb");
248 }
249 if (!out)
250 {
1fd6d0a2
DD
251 fprintf (stderr, "unable to write to file %s\n", path);
252 perror ("The error was");
99d1bf2d
DD
253 skip_file ();
254 return 0;
255 }
256 return out;
257}
258
259static void
260prepare_for_file (char *path)
261{
262 DWORD w;
263 mkdir_p (0, path);
264
265 w = GetFileAttributes (path);
266 if (w != 0xffffffff && w & FILE_ATTRIBUTE_DIRECTORY)
267 {
268 char *tmp = (char *) malloc (strlen (path) + 10);
269 int i = 0;
270 do {
271 i++;
272 sprintf (tmp, "%s.old-%d", path, i);
273 } while (GetFileAttributes (tmp) != 0xffffffff);
1fd6d0a2 274 fprintf (stderr, "warning: moving directory \"%s\" out of the way.\n", path);
99d1bf2d
DD
275 MoveFile (path, tmp);
276 free (tmp);
277 }
278
279 DeleteFileA (path);
280}
281
282int
283tar_read_file (char *path)
284{
285 FILE *out, *copy;
286 HANDLE h;
287 DWORD w, startticks;
288 int got;
289 tar_map_result_type *tmr;
290
291 switch (tar_header.typeflag)
292 {
293 case '0': /* regular files */
294 case 0:
295 case '7':
296 vp (_tar_vfile, "F %s\n", path);
297 prepare_for_file (path);
298 out = common_fopen (path);
299 if (!out)
300 return 1;
301
302 while (file_length > 0)
303 {
304 int put;
305 int want = file_length > 512 ? 512 : file_length;
306 got = gzread (g, buf, 512);
307 if (got < 512)
308 {
309 fprintf (stderr, "tar: unexpected end of file reading %s\n", path);
310 fclose (out);
311 remove (path);
312 return 1;
313 }
314 put = fwrite (buf, 1, want, out);
315 if (put < want)
316 {
317 fprintf (stderr, "tar: out of disk space writing %s\n", path);
318 fclose (out);
319 remove (path);
320 skip_file ();
321 return 1;
322 }
323 file_length -= want;
324 }
325 fclose (out);
326
327 fix_time_stamp (path);
328
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;
335
336 return 0;
337
338 case '1': /* hard links; we just copy */
339 for (tmr = tar_map_result; tmr; tmr=tmr->next)
1fd6d0a2 340 if (strcmp (tmr->stored_name, tar_header.linkname) == 0)
99d1bf2d
DD
341 break;
342 if (!tmr)
343 {
344 fprintf (stderr, "tar: can't find %s to link %s to\n",
345 tar_header.linkname, path);
346 return 1;
347 }
348 vp (_tar_vfile, "H %s <- %s\n", path, tmr->mapped_name);
349 prepare_for_file (path);
350 copy = fopen (tmr->mapped_name, "rb");
351 if (!copy)
352 {
353 fprintf (stderr, "tar: unable to read %s\n", tmr->mapped_name);
354 return 1;
355 }
356 out = common_fopen (path);
357 if (!out)
358 return 1;
359
360 while ((got = fread (buf, 1, 512, copy)) > 0)
361 {
362 int put = fwrite (buf, 1, got, out);
363 if (put < got)
364 {
365 fprintf (stderr, "tar: out of disk space writing %s\n", path);
366 fclose (out);
367 fclose (copy);
368 remove (path);
369 return 1;
370 }
371 }
372 fclose (out);
373 fclose (copy);
374
375 fix_time_stamp (path);
376 return 0;
377
378 case '5': /* directories */
379 vp (_tar_vfile, "D %s\n", path);
1fd6d0a2
DD
380 while (path[0] && path[strlen (path)-1] == '/')
381 path[strlen (path) - 1] = 0;
99d1bf2d
DD
382 return mkdir_p (1, path);
383
384
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)
391 {
1fd6d0a2
DD
392 fprintf (stderr, "error: unable to create symlink \"%s\" -> \"%s\"\n",
393 path, tar_header.linkname);
99d1bf2d
DD
394 return 1;
395 }
396 strcpy (buf, SYMLINK_COOKIE);
397 strcat (buf, tar_header.linkname);
1fd6d0a2 398 if (WriteFile (h, buf, strlen (buf) + 1, &w, NULL))
99d1bf2d
DD
399 {
400 CloseHandle (h);
401 SetFileAttributesA (path, FILE_ATTRIBUTE_SYSTEM);
402 return 0;
403 }
404 CloseHandle (h);
1fd6d0a2 405 fprintf (stderr, "error: unable to write symlink \"%s\"\n", path);
99d1bf2d
DD
406 DeleteFileA (path);
407 return 1;
408 }
409}
410
411int
412tar_close ()
413{
414#if 0
415 while (tar_map_result)
416 {
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);
421 tar_map_result = t;
422 }
423#endif
424 tar_map_result = 0;
425
426 if (gzclose (g))
427 err ++;
428 return err; /* includes errors for skipped files, etc */
429}
430
431typedef struct {
432 char *from;
433 int from_len;
434 char *to;
435 int to_len;
436} map_type;
437
438static map_type *map;
439static int nmaps;
440
441int
442tar_auto (char *pathname, char **maplist)
443{
444 char *c;
445 int err = 0;
446 int i, j;
447 map_type mtemp;
448 char newname[_MAX_PATH+512];
449 static char twiddles[] = "|\b/\b-\b\\\b";
450 int t = 0;
451
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++)
455 {
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]);
460 }
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)
465 {
466 mtemp = map[i];
467 map[i] = map[j];
468 map[j] = mtemp;
469 }
470
471 if (tar_open (pathname))
472 return 1;
473 while (c = tar_next_file ())
474 {
475 int l = strlen (c);
476 for (i=0; i<nmaps; i++)
477 if (l >= map[i].from_len
1fd6d0a2 478 && strncmp (c, map[i].from, map[i].from_len) == 0)
99d1bf2d
DD
479 {
480 strcpy (newname, map[i].to);
481 strcpy (newname+map[i].to_len, c + map[i].from_len);
482 c = newname;
483 break;
484 }
485
486 t = (t+2) % 8;
487 fwrite (twiddles+t, 1, 2, stderr);
488
489 if (tar_read_file (c))
490 err ++;
491 }
492 if (tar_close ())
493 err ++;
494
495 fwrite (" \b", 1, 2, stderr);
496
497 vp2 (_tar_vfile, "tar_auto returns %d\n", err);
498 return err;
499}
This page took 0.069074 seconds and 5 git commands to generate.