]> Dogcows Code - chaz/tar/blob - src/gnu.c
Update
[chaz/tar] / src / gnu.c
1 /* GNU dump extensions to tar.
2 Copyright (C) 1988, 1992, 1993 Free Software Foundation
3
4 This file is part of GNU Tar.
5
6 GNU Tar is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 GNU Tar is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU Tar; see the file COPYING. If not, write to
18 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
19
20 #include <stdio.h>
21 #include <sys/types.h>
22 #include <ctype.h>
23 #include <errno.h>
24 #ifndef STDC_HEADERS
25 extern int errno;
26 #endif
27 #include <time.h>
28 time_t time ();
29
30 #include "tar.h"
31 #include "port.h"
32
33 #ifndef S_ISLNK
34 #define lstat stat
35 #endif
36
37 extern time_t new_time;
38 extern FILE *msg_file;
39
40 void addname ();
41 int check_exclude ();
42 extern PTR ck_malloc ();
43 extern PTR ck_realloc ();
44 int confirm ();
45 extern PTR init_buffer ();
46 extern char *get_buffer ();
47 int is_dot_or_dotdot ();
48 extern void add_buffer ();
49 extern void flush_buffer ();
50 void name_gather ();
51 int recursively_delete ();
52 void skip_file ();
53 char *un_quote_string ();
54
55 extern char *new_name ();
56
57 static void add_dir_name ();
58
59 struct dirname
60 {
61 struct dirname *next;
62 char *name;
63 char *dir_text;
64 int dev;
65 int ino;
66 int allnew;
67 };
68 static struct dirname *dir_list;
69 static time_t this_time;
70
71 void
72 add_dir (name, dev, ino, text)
73 char *name;
74 char *text;
75 dev_t dev;
76 ino_t ino;
77 {
78 struct dirname *dp;
79
80 dp = (struct dirname *) ck_malloc (sizeof (struct dirname));
81 if (!dp)
82 abort ();
83 dp->next = dir_list;
84 dir_list = dp;
85 dp->dev = dev;
86 dp->ino = ino;
87 dp->name = ck_malloc (strlen (name) + 1);
88 strcpy (dp->name, name);
89 dp->dir_text = text;
90 dp->allnew = 0;
91 }
92
93 void
94 read_dir_file ()
95 {
96 int dev;
97 int ino;
98 char *strp;
99 FILE *fp;
100 char buf[512];
101 static char *path = 0;
102
103 if (path == 0)
104 path = ck_malloc (PATH_MAX);
105 time (&this_time);
106 if (gnu_dumpfile[0] != '/')
107 {
108 #if defined(__MSDOS__) || defined(HAVE_GETCWD) || defined(_POSIX_VERSION)
109 if (!getcwd (path, PATH_MAX))
110 {
111 msg ("Couldn't get current directory.");
112 exit (EX_SYSTEM);
113 }
114 #else
115 char *getwd ();
116
117 if (!getwd (path))
118 {
119 msg ("Couldn't get current directory: %s", path);
120 exit (EX_SYSTEM);
121 }
122 #endif
123 /* If this doesn't fit, we're in serious trouble */
124 strcat (path, "/");
125 strcat (path, gnu_dumpfile);
126 gnu_dumpfile = path;
127 }
128 fp = fopen (gnu_dumpfile, "r");
129 if (fp == 0 && errno != ENOENT)
130 {
131 msg_perror ("Can't open %s", gnu_dumpfile);
132 return;
133 }
134 if (!fp)
135 return;
136 fgets (buf, sizeof (buf), fp);
137 if (!f_new_files)
138 {
139 f_new_files++;
140 new_time = atol (buf);
141 }
142 while (fgets (buf, sizeof (buf), fp))
143 {
144 strp = &buf[strlen (buf)];
145 if (strp[-1] == '\n')
146 strp[-1] = '\0';
147 strp = buf;
148 dev = atol (strp);
149 while (isdigit (*strp))
150 strp++;
151 ino = atol (strp);
152 while (isspace (*strp))
153 strp++;
154 while (isdigit (*strp))
155 strp++;
156 strp++;
157 add_dir (un_quote_string (strp), dev, ino, (char *) 0);
158 }
159 fclose (fp);
160 }
161
162 void
163 write_dir_file ()
164 {
165 FILE *fp;
166 struct dirname *dp;
167 char *str;
168 extern char *quote_copy_string ();
169
170 fp = fopen (gnu_dumpfile, "w");
171 if (fp == 0)
172 {
173 msg_perror ("Can't write to %s", gnu_dumpfile);
174 return;
175 }
176 fprintf (fp, "%lu\n", this_time);
177 for (dp = dir_list; dp; dp = dp->next)
178 {
179 if (!dp->dir_text)
180 continue;
181 str = quote_copy_string (dp->name);
182 if (str)
183 {
184 fprintf (fp, "%u %u %s\n", dp->dev, dp->ino, str);
185 free (str);
186 }
187 else
188 fprintf (fp, "%u %u %s\n", dp->dev, dp->ino, dp->name);
189 }
190 fclose (fp);
191 }
192
193 struct dirname *
194 get_dir (name)
195 char *name;
196 {
197 struct dirname *dp;
198
199 for (dp = dir_list; dp; dp = dp->next)
200 {
201 if (!strcmp (dp->name, name))
202 return dp;
203 }
204 return 0;
205 }
206
207
208 /* Collect all the names from argv[] (or whatever), then expand them into
209 a directory tree, and put all the directories at the beginning. */
210 void
211 collect_and_sort_names ()
212 {
213 struct name *n, *n_next;
214 int num_names;
215 struct stat statbuf;
216 int name_cmp ();
217 char *merge_sort ();
218
219 name_gather ();
220
221 if (gnu_dumpfile)
222 read_dir_file ();
223 if (!namelist)
224 addname (".");
225 for (n = namelist; n; n = n_next)
226 {
227 n_next = n->next;
228 if (n->found || n->dir_contents)
229 continue;
230 if (n->regexp) /* FIXME just skip regexps for now */
231 continue;
232 if (n->change_dir)
233 if (chdir (n->change_dir) < 0)
234 {
235 msg_perror ("can't chdir to %s", n->change_dir);
236 continue;
237 }
238
239 #ifdef AIX
240 if (statx (n->name, &statbuf, STATSIZE, STX_HIDDEN | STX_LINK))
241 #else
242 if (lstat (n->name, &statbuf) < 0)
243 #endif /* AIX */
244 {
245 msg_perror ("can't stat %s", n->name);
246 continue;
247 }
248 if (S_ISDIR (statbuf.st_mode))
249 {
250 n->found++;
251 add_dir_name (n->name, statbuf.st_dev);
252 }
253 }
254
255 num_names = 0;
256 for (n = namelist; n; n = n->next)
257 num_names++;
258 namelist = (struct name *) merge_sort ((PTR) namelist, num_names, (char *) (&(namelist->next)) - (char *) namelist, name_cmp);
259
260 for (n = namelist; n; n = n->next)
261 {
262 n->found = 0;
263 }
264 if (gnu_dumpfile)
265 write_dir_file ();
266 }
267
268 int
269 name_cmp (n1, n2)
270 struct name *n1, *n2;
271 {
272 if (n1->found)
273 {
274 if (n2->found)
275 return strcmp (n1->name, n2->name);
276 else
277 return -1;
278 }
279 else if (n2->found)
280 return 1;
281 else
282 return strcmp (n1->name, n2->name);
283 }
284
285 int
286 dirent_cmp (p1, p2)
287 const PTR p1;
288 const PTR p2;
289 {
290 char *frst, *scnd;
291
292 frst = (*(char **) p1) + 1;
293 scnd = (*(char **) p2) + 1;
294
295 return strcmp (frst, scnd);
296 }
297
298 char *
299 get_dir_contents (p, device)
300 char *p;
301 int device;
302 {
303 DIR *dirp;
304 register struct dirent *d;
305 char *new_buf;
306 char *namebuf;
307 int bufsiz;
308 int len;
309 PTR the_buffer;
310 char *buf;
311 size_t n_strs;
312 /* int n_size;*/
313 char *p_buf;
314 char **vec, **p_vec;
315
316 extern int errno;
317
318 errno = 0;
319 dirp = opendir (p);
320 bufsiz = strlen (p) + NAMSIZ;
321 namebuf = ck_malloc (bufsiz + 2);
322 if (!dirp)
323 {
324 if (errno)
325 msg_perror ("can't open directory %s", p);
326 else
327 msg ("error opening directory %s", p);
328 new_buf = NULL;
329 }
330 else
331 {
332 struct dirname *dp;
333 int all_children;
334
335 dp = get_dir (p);
336 all_children = dp ? dp->allnew : 0;
337 (void) strcpy (namebuf, p);
338 if (p[strlen (p) - 1] != '/')
339 (void) strcat (namebuf, "/");
340 len = strlen (namebuf);
341
342 the_buffer = init_buffer ();
343 while (d = readdir (dirp))
344 {
345 struct stat hs;
346
347 /* Skip . and .. */
348 if (is_dot_or_dotdot (d->d_name))
349 continue;
350 if (NLENGTH (d) + len >= bufsiz)
351 {
352 bufsiz += NAMSIZ;
353 namebuf = ck_realloc (namebuf, bufsiz + 2);
354 }
355 (void) strcpy (namebuf + len, d->d_name);
356 #ifdef AIX
357 if (0 != f_follow_links ?
358 statx (namebuf, &hs, STATSIZE, STX_HIDDEN) :
359 statx (namebuf, &hs, STATSIZE, STX_HIDDEN | STX_LINK))
360 #else
361 if (0 != f_follow_links ? stat (namebuf, &hs) : lstat (namebuf, &hs))
362 #endif
363 {
364 msg_perror ("can't stat %s", namebuf);
365 continue;
366 }
367 if ((f_local_filesys && device != hs.st_dev)
368 || (f_exclude && check_exclude (namebuf)))
369 add_buffer (the_buffer, "N", 1);
370 #ifdef AIX
371 else if (S_ISHIDDEN (hs.st_mode))
372 {
373 add_buffer (the_buffer, "D", 1);
374 strcat (d->d_name, "A");
375 d->d_namlen++;
376 }
377 #endif /* AIX */
378 else if (S_ISDIR (hs.st_mode))
379 {
380 if (dp = get_dir (namebuf))
381 {
382 if (dp->dev != hs.st_dev
383 || dp->ino != hs.st_ino)
384 {
385 if (f_verbose)
386 msg ("directory %s has been renamed.", namebuf);
387 dp->allnew = 1;
388 dp->dev = hs.st_dev;
389 dp->ino = hs.st_ino;
390 }
391 dp->dir_text = "";
392 }
393 else
394 {
395 if (f_verbose)
396 msg ("Directory %s is new", namebuf);
397 add_dir (namebuf, hs.st_dev, hs.st_ino, "");
398 dp = get_dir (namebuf);
399 dp->allnew = 1;
400 }
401 if (all_children)
402 dp->allnew = 1;
403
404 add_buffer (the_buffer, "D", 1);
405 }
406 else if (!all_children
407 && f_new_files
408 && new_time > hs.st_mtime
409 && (f_new_files > 1
410 || new_time > hs.st_ctime))
411 add_buffer (the_buffer, "N", 1);
412 else
413 add_buffer (the_buffer, "Y", 1);
414 add_buffer (the_buffer, d->d_name, (int) (NLENGTH (d) + 1));
415 }
416 add_buffer (the_buffer, "\000\000", 2);
417 closedir (dirp);
418
419 /* Well, we've read in the contents of the dir, now sort them */
420 buf = get_buffer (the_buffer);
421 if (buf[0] == '\0')
422 {
423 flush_buffer (the_buffer);
424 new_buf = NULL;
425 }
426 else
427 {
428 n_strs = 0;
429 for (p_buf = buf; *p_buf;)
430 {
431 int tmp;
432
433 tmp = strlen (p_buf) + 1;
434 n_strs++;
435 p_buf += tmp;
436 }
437 vec = (char **) ck_malloc (sizeof (char *) * (n_strs + 1));
438 for (p_vec = vec, p_buf = buf; *p_buf; p_buf += strlen (p_buf) + 1)
439 *p_vec++ = p_buf;
440 *p_vec = 0;
441 qsort ((PTR) vec, n_strs, sizeof (char *), dirent_cmp);
442 new_buf = (char *) ck_malloc (p_buf - buf + 2);
443 for (p_vec = vec, p_buf = new_buf; *p_vec; p_vec++)
444 {
445 char *p_tmp;
446
447 for (p_tmp = *p_vec; *p_buf++ = *p_tmp++;)
448 ;
449 }
450 *p_buf++ = '\0';
451 free (vec);
452 flush_buffer (the_buffer);
453 }
454 }
455 free (namebuf);
456 return new_buf;
457 }
458
459 /* p is a directory. Add all the files in P to the namelist. If any of the
460 files is a directory, recurse on the subdirectory. . . */
461 static void
462 add_dir_name (p, device)
463 char *p;
464 int device;
465 {
466 char *new_buf;
467 char *p_buf;
468
469 char *namebuf;
470 int buflen;
471 register int len;
472 int sublen;
473
474 /* PTR the_buffer;*/
475
476 /* char *buf;*/
477 /* char **vec,**p_vec;*/
478 /* int n_strs,n_size;*/
479
480 struct name *n;
481
482 int dirent_cmp ();
483
484 new_buf = get_dir_contents (p, device);
485
486 for (n = namelist; n; n = n->next)
487 {
488 if (!strcmp (n->name, p))
489 {
490 n->dir_contents = new_buf ? new_buf : "\0\0\0\0";
491 break;
492 }
493 }
494
495 if (new_buf)
496 {
497 len = strlen (p);
498 buflen = NAMSIZ <= len ? len + NAMSIZ : NAMSIZ;
499 namebuf = ck_malloc (buflen + 1);
500
501 (void) strcpy (namebuf, p);
502 if (namebuf[len - 1] != '/')
503 {
504 namebuf[len++] = '/';
505 namebuf[len] = '\0';
506 }
507 for (p_buf = new_buf; *p_buf; p_buf += sublen + 1)
508 {
509 sublen = strlen (p_buf);
510 if (*p_buf == 'D')
511 {
512 if (len + sublen >= buflen)
513 {
514 buflen += NAMSIZ;
515 namebuf = ck_realloc (namebuf, buflen + 1);
516 }
517 (void) strcpy (namebuf + len, p_buf + 1);
518 addname (namebuf);
519 add_dir_name (namebuf, device);
520 }
521 }
522 free (namebuf);
523 }
524 }
525
526 /* Returns non-zero if p is . or .. This could be a macro for speed. */
527 int
528 is_dot_or_dotdot (p)
529 char *p;
530 {
531 return (p[0] == '.' && (p[1] == '\0' || (p[1] == '.' && p[2] == '\0')));
532 }
533
534
535
536
537
538
539 void
540 gnu_restore (skipcrud)
541 int skipcrud;
542 {
543 char *current_dir;
544 /* int current_dir_length; */
545
546 char *archive_dir;
547 /* int archive_dir_length; */
548 PTR the_buffer;
549 char *p;
550 DIR *dirp;
551 struct dirent *d;
552 char *cur, *arc;
553 extern struct stat hstat; /* Stat struct corresponding */
554 long size, copied;
555 char *from, *to;
556 extern union record *head;
557
558 dirp = opendir (skipcrud + current_file_name);
559
560 if (!dirp)
561 {
562 /* The directory doesn't exist now. It'll be created.
563 In any case, we don't have to delete any files out
564 of it */
565 skip_file ((long) hstat.st_size);
566 return;
567 }
568
569 the_buffer = init_buffer ();
570 while (d = readdir (dirp))
571 {
572 if (is_dot_or_dotdot (d->d_name))
573 continue;
574
575 add_buffer (the_buffer, d->d_name, (int) (NLENGTH (d) + 1));
576 }
577 closedir (dirp);
578 add_buffer (the_buffer, "", 1);
579
580 current_dir = get_buffer (the_buffer);
581 archive_dir = (char *) ck_malloc (hstat.st_size);
582 if (archive_dir == 0)
583 {
584 msg ("Can't allocate %d bytes for restore", hstat.st_size);
585 skip_file ((long) hstat.st_size);
586 return;
587 }
588 to = archive_dir;
589 for (size = hstat.st_size; size > 0; size -= copied)
590 {
591 from = findrec ()->charptr;
592 if (!from)
593 {
594 msg ("Unexpected EOF in archive\n");
595 break;
596 }
597 copied = endofrecs ()->charptr - from;
598 if (copied > size)
599 copied = size;
600 bcopy ((PTR) from, (PTR) to, (int) copied);
601 to += copied;
602 userec ((union record *) (from + copied - 1));
603 }
604
605 for (cur = current_dir; *cur; cur += strlen (cur) + 1)
606 {
607 for (arc = archive_dir; *arc; arc += strlen (arc) + 1)
608 {
609 arc++;
610 if (!strcmp (arc, cur))
611 break;
612 }
613 if (*arc == '\0')
614 {
615 p = new_name (skipcrud + current_file_name, cur);
616 if (f_confirm && !confirm ("delete", p))
617 {
618 free (p);
619 continue;
620 }
621 if (f_verbose)
622 fprintf (msg_file, "%s: deleting %s\n", tar, p);
623 if (recursively_delete (p))
624 {
625 msg ("%s: Error while deleting %s\n", tar, p);
626 }
627 free (p);
628 }
629
630 }
631 flush_buffer (the_buffer);
632 free (archive_dir);
633 }
634
635 int
636 recursively_delete (path)
637 char *path;
638 {
639 struct stat sbuf;
640 DIR *dirp;
641 struct dirent *dp;
642 char *path_buf;
643 /* int path_len; */
644
645
646 if (lstat (path, &sbuf) < 0)
647 return 1;
648 if (S_ISDIR (sbuf.st_mode))
649 {
650
651 /* path_len=strlen(path); */
652 dirp = opendir (path);
653 if (dirp == 0)
654 return 1;
655 while (dp = readdir (dirp))
656 {
657 if (is_dot_or_dotdot (dp->d_name))
658 continue;
659 path_buf = new_name (path, dp->d_name);
660 if (recursively_delete (path_buf))
661 {
662 free (path_buf);
663 closedir (dirp);
664 return 1;
665 }
666 free (path_buf);
667 }
668 closedir (dirp);
669
670 if (rmdir (path) < 0)
671 return 1;
672 return 0;
673 }
674 if (unlink (path) < 0)
675 return 1;
676 return 0;
677 }
This page took 0.07107 seconds and 4 git commands to generate.