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