1 /* GNU dump extensions to tar.
2 Copyright (C) 1988, 1992, 1993 Free Software Foundation
4 This file is part of GNU Tar.
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)
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.
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. */
21 #include <sys/types.h>
37 extern time_t new_time;
38 extern FILE *msg_file;
42 extern PTR ck_malloc ();
43 extern PTR ck_realloc ();
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 ();
51 int recursively_delete ();
53 char *un_quote_string ();
55 extern char *new_name ();
57 static void add_dir_name ();
68 static struct dirname *dir_list;
69 static time_t this_time;
72 add_dir (name, dev, ino, text)
80 dp = (struct dirname *) ck_malloc (sizeof (struct dirname));
87 dp->name = ck_malloc (strlen (name) + 1);
88 strcpy (dp->name, name);
101 static char *path = 0;
104 path = ck_malloc (PATH_MAX);
106 if (gnu_dumpfile[0] != '/')
108 #if defined(__MSDOS__) || defined(HAVE_GETCWD) || defined(_POSIX_VERSION)
109 if (!getcwd (path, PATH_MAX))
111 msg ("Couldn't get current directory.");
119 msg ("Couldn't get current directory: %s", path);
123 /* If this doesn't fit, we're in serious trouble */
125 strcat (path, gnu_dumpfile);
128 fp = fopen (gnu_dumpfile, "r");
129 if (fp == 0 && errno != ENOENT)
131 msg_perror ("Can't open %s", gnu_dumpfile);
136 fgets (buf, sizeof (buf), fp);
140 new_time = atol (buf);
142 while (fgets (buf, sizeof (buf), fp))
144 strp = &buf[strlen (buf)];
145 if (strp[-1] == '\n')
149 while (isdigit (*strp))
152 while (isspace (*strp))
154 while (isdigit (*strp))
157 add_dir (un_quote_string (strp), dev, ino, (char *) 0);
168 extern char *quote_copy_string ();
170 fp = fopen (gnu_dumpfile, "w");
173 msg_perror ("Can't write to %s", gnu_dumpfile);
176 fprintf (fp, "%lu\n", this_time);
177 for (dp = dir_list; dp; dp = dp->next)
181 str = quote_copy_string (dp->name);
184 fprintf (fp, "%u %u %s\n", dp->dev, dp->ino, str);
188 fprintf (fp, "%u %u %s\n", dp->dev, dp->ino, dp->name);
199 for (dp = dir_list; dp; dp = dp->next)
201 if (!strcmp (dp->name, name))
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. */
211 collect_and_sort_names ()
213 struct name *n, *n_next;
225 for (n = namelist; n; n = n_next)
228 if (n->found || n->dir_contents)
230 if (n->regexp) /* FIXME just skip regexps for now */
233 if (chdir (n->change_dir) < 0)
235 msg_perror ("can't chdir to %s", n->change_dir);
240 if (statx (n->name, &statbuf, STATSIZE, STX_HIDDEN | STX_LINK))
242 if (lstat (n->name, &statbuf) < 0)
245 msg_perror ("can't stat %s", n->name);
248 if (S_ISDIR (statbuf.st_mode))
251 add_dir_name (n->name, statbuf.st_dev);
256 for (n = namelist; n; n = n->next)
258 namelist = (struct name *) merge_sort ((PTR) namelist, num_names, (char *) (&(namelist->next)) - (char *) namelist, name_cmp);
260 for (n = namelist; n; n = n->next)
270 struct name *n1, *n2;
275 return strcmp (n1->name, n2->name);
282 return strcmp (n1->name, n2->name);
292 frst = (*(char **) p1) + 1;
293 scnd = (*(char **) p2) + 1;
295 return strcmp (frst, scnd);
299 get_dir_contents (p, device)
304 register struct dirent *d;
320 bufsiz = strlen (p) + NAMSIZ;
321 namebuf = ck_malloc (bufsiz + 2);
325 msg_perror ("can't open directory %s", p);
327 msg ("error opening directory %s", 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);
342 the_buffer = init_buffer ();
343 while (d = readdir (dirp))
348 if (is_dot_or_dotdot (d->d_name))
350 if (NLENGTH (d) + len >= bufsiz)
353 namebuf = ck_realloc (namebuf, bufsiz + 2);
355 (void) strcpy (namebuf + len, d->d_name);
357 if (0 != f_follow_links ?
358 statx (namebuf, &hs, STATSIZE, STX_HIDDEN) :
359 statx (namebuf, &hs, STATSIZE, STX_HIDDEN | STX_LINK))
361 if (0 != f_follow_links ? stat (namebuf, &hs) : lstat (namebuf, &hs))
364 msg_perror ("can't stat %s", namebuf);
367 if ((f_local_filesys && device != hs.st_dev)
368 || (f_exclude && check_exclude (namebuf)))
369 add_buffer (the_buffer, "N", 1);
371 else if (S_ISHIDDEN (hs.st_mode))
373 add_buffer (the_buffer, "D", 1);
374 strcat (d->d_name, "A");
378 else if (S_ISDIR (hs.st_mode))
380 if (dp = get_dir (namebuf))
382 if (dp->dev != hs.st_dev
383 || dp->ino != hs.st_ino)
386 msg ("directory %s has been renamed.", namebuf);
396 msg ("Directory %s is new", namebuf);
397 add_dir (namebuf, hs.st_dev, hs.st_ino, "");
398 dp = get_dir (namebuf);
404 add_buffer (the_buffer, "D", 1);
406 else if (!all_children
408 && new_time > hs.st_mtime
410 || new_time > hs.st_ctime))
411 add_buffer (the_buffer, "N", 1);
413 add_buffer (the_buffer, "Y", 1);
414 add_buffer (the_buffer, d->d_name, (int) (NLENGTH (d) + 1));
416 add_buffer (the_buffer, "\000\000", 2);
419 /* Well, we've read in the contents of the dir, now sort them */
420 buf = get_buffer (the_buffer);
423 flush_buffer (the_buffer);
429 for (p_buf = buf; *p_buf;)
433 tmp = strlen (p_buf) + 1;
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)
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++)
447 for (p_tmp = *p_vec; *p_buf++ = *p_tmp++;)
452 flush_buffer (the_buffer);
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. . . */
462 add_dir_name (p, device)
477 /* char **vec,**p_vec;*/
478 /* int n_strs,n_size;*/
484 new_buf = get_dir_contents (p, device);
486 for (n = namelist; n; n = n->next)
488 if (!strcmp (n->name, p))
490 n->dir_contents = new_buf ? new_buf : "\0\0\0\0";
498 buflen = NAMSIZ <= len ? len + NAMSIZ : NAMSIZ;
499 namebuf = ck_malloc (buflen + 1);
501 (void) strcpy (namebuf, p);
502 if (namebuf[len - 1] != '/')
504 namebuf[len++] = '/';
507 for (p_buf = new_buf; *p_buf; p_buf += sublen + 1)
509 sublen = strlen (p_buf);
512 if (len + sublen >= buflen)
515 namebuf = ck_realloc (namebuf, buflen + 1);
517 (void) strcpy (namebuf + len, p_buf + 1);
519 add_dir_name (namebuf, device);
526 /* Returns non-zero if p is . or .. This could be a macro for speed. */
531 return (p[0] == '.' && (p[1] == '\0' || (p[1] == '.' && p[2] == '\0')));
540 gnu_restore (skipcrud)
544 /* int current_dir_length; */
547 /* int archive_dir_length; */
553 extern struct stat hstat; /* Stat struct corresponding */
556 extern union record *head;
558 dirp = opendir (skipcrud + current_file_name);
562 /* The directory doesn't exist now. It'll be created.
563 In any case, we don't have to delete any files out
565 skip_file ((long) hstat.st_size);
569 the_buffer = init_buffer ();
570 while (d = readdir (dirp))
572 if (is_dot_or_dotdot (d->d_name))
575 add_buffer (the_buffer, d->d_name, (int) (NLENGTH (d) + 1));
578 add_buffer (the_buffer, "", 1);
580 current_dir = get_buffer (the_buffer);
581 archive_dir = (char *) ck_malloc (hstat.st_size);
582 if (archive_dir == 0)
584 msg ("Can't allocate %d bytes for restore", hstat.st_size);
585 skip_file ((long) hstat.st_size);
589 for (size = hstat.st_size; size > 0; size -= copied)
591 from = findrec ()->charptr;
594 msg ("Unexpected EOF in archive\n");
597 copied = endofrecs ()->charptr - from;
600 bcopy ((PTR) from, (PTR) to, (int) copied);
602 userec ((union record *) (from + copied - 1));
605 for (cur = current_dir; *cur; cur += strlen (cur) + 1)
607 for (arc = archive_dir; *arc; arc += strlen (arc) + 1)
610 if (!strcmp (arc, cur))
615 p = new_name (skipcrud + current_file_name, cur);
616 if (f_confirm && !confirm ("delete", p))
622 fprintf (msg_file, "%s: deleting %s\n", tar, p);
623 if (recursively_delete (p))
625 msg ("%s: Error while deleting %s\n", tar, p);
631 flush_buffer (the_buffer);
636 recursively_delete (path)
646 if (lstat (path, &sbuf) < 0)
648 if (S_ISDIR (sbuf.st_mode))
651 /* path_len=strlen(path); */
652 dirp = opendir (path);
655 while (dp = readdir (dirp))
657 if (is_dot_or_dotdot (dp->d_name))
659 path_buf = new_name (path, dp->d_name);
660 if (recursively_delete (path_buf))
670 if (rmdir (path) < 0)
674 if (unlink (path) < 0)