GNU tar 1.12
[debian/tar] / src / incremen.c
1 /* GNU dump extensions to tar.
2    Copyright (C) 1988, 92, 93, 94, 96, 97 Free Software Foundation, Inc.
3
4    This program is free software; you can redistribute it and/or modify it
5    under the terms of the GNU General Public License as published by the
6    Free Software Foundation; either version 2, or (at your option) any later
7    version.
8
9    This program is distributed in the hope that it will be useful, but
10    WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
12    Public License for more details.
13
14    You should have received a copy of the GNU General Public License along
15    with this program; if not, write to the Free Software Foundation, Inc.,
16    59 Place - Suite 330, Boston, MA 02111-1307, USA.  */
17
18 #include "system.h"
19
20 #include <time.h>
21 time_t time ();
22
23 #define ISDIGIT(Char) (ISASCII (Char) && isdigit (Char))
24 #define ISSPACE(Char) (ISASCII (Char) && isspace (Char))
25
26 #include "common.h"
27 \f
28 /* Variable sized generic character buffers.  */
29
30 struct accumulator
31 {
32   int allocated;
33   int length;
34   char *pointer;
35 };
36
37 /* Amount of space guaranteed just after a reallocation.  */
38 #define ACCUMULATOR_SLACK 50
39
40 /*---------------------------------------------------------.
41 | Return the accumulated data from an ACCUMULATOR buffer.  |
42 `---------------------------------------------------------*/
43
44 static char *
45 get_accumulator (struct accumulator *accumulator)
46 {
47   return accumulator->pointer;
48 }
49
50 /*-----------------------------------------------.
51 | Allocate and return a new accumulator buffer.  |
52 `-----------------------------------------------*/
53
54 static struct accumulator *
55 new_accumulator (void)
56 {
57   struct accumulator *accumulator
58     = (struct accumulator *) xmalloc (sizeof (struct accumulator));
59
60   accumulator->allocated = ACCUMULATOR_SLACK;
61   accumulator->pointer = (char *) xmalloc (ACCUMULATOR_SLACK);
62   accumulator->length = 0;
63   return accumulator;
64 }
65
66 /*-----------------------------------.
67 | Deallocate an ACCUMULATOR buffer.  |
68 `-----------------------------------*/
69
70 static void
71 delete_accumulator (struct accumulator *accumulator)
72 {
73   free (accumulator->pointer);
74   free (accumulator);
75 }
76
77 /*----------------------------------------------------------------------.
78 | At the end of an ACCUMULATOR buffer, add a DATA block of SIZE bytes.  |
79 `----------------------------------------------------------------------*/
80
81 static void
82 add_to_accumulator (struct accumulator *accumulator,
83                     const char *data, int size)
84 {
85   if (accumulator->length + size > accumulator->allocated)
86     {
87       accumulator->allocated = accumulator->length + size + ACCUMULATOR_SLACK;
88       accumulator->pointer = (char *)
89         xrealloc (accumulator->pointer, (size_t) accumulator->allocated);
90     }
91   memcpy (accumulator->pointer + accumulator->length, data, (size_t) size);
92   accumulator->length += size;
93 }
94 \f
95 /* Incremental dump specialities.  */
96
97 /* Current time.  */
98 static time_t time_now;
99
100 /* List of directory names.  */
101 struct directory
102   {
103     struct directory *next;     /* next entry in list */
104     const char *name;           /* path name of directory */
105     int device_number;          /* device number for directory */
106     int inode_number;           /* inode number for directory */
107     int allnew;
108     const char *dir_text;
109   };
110 static struct directory *directory_list = NULL;
111
112 /*-------------------------------------------------------------------.
113 | Create and link a new directory entry for directory NAME, having a |
114 | DEVICE_NUMBER and a INODE_NUMBER, with some TEXT.                  |
115 `-------------------------------------------------------------------*/
116
117 static void
118 note_directory (char *name, dev_t device_number, ino_t inode_number,
119                 const char *text)
120 {
121   struct directory *directory
122     = (struct directory *) xmalloc (sizeof (struct directory));
123
124   directory->next = directory_list;
125   directory_list = directory;
126
127   directory->device_number = device_number;
128   directory->inode_number = inode_number;
129   directory->name = xstrdup (name);
130   directory->dir_text = text;
131   directory->allnew = 0;
132 }
133
134 /*------------------------------------------------------------------------.
135 | Return a directory entry for a given path NAME, or NULL if none found.  |
136 `------------------------------------------------------------------------*/
137
138 static struct directory *
139 find_directory (char *name)
140 {
141   struct directory *directory;
142
143   for (directory = directory_list;
144        directory;
145        directory = directory->next)
146     {
147       if (!strcmp (directory->name, name))
148         return directory;
149     }
150   return NULL;
151 }
152
153 /*---.
154 | ?  |
155 `---*/
156
157 static int
158 compare_dirents (const voidstar first, const voidstar second)
159 {
160   return strcmp ((*(char *const *) first) + 1,
161                  (*(char *const *) second) + 1);
162 }
163
164 /*---.
165 | ?  |
166 `---*/
167
168 char *
169 get_directory_contents (char *path, int device)
170 {
171   struct accumulator *accumulator;
172
173   /* Recursively scan the given PATH.  */
174
175   {
176     DIR *dirp = opendir (path); /* for scanning directory */
177     struct dirent *entry;       /* directory entry being scanned */
178     char *name_buffer;          /* directory, `/', and directory member */
179     int name_buffer_size;       /* allocated size of name_buffer, minus 2 */
180     int name_length;            /* used length in name_buffer */
181     struct directory *directory; /* for checking if already already seen */
182     int all_children;
183
184     if (dirp == NULL)
185       {
186         ERROR ((0, errno, _("Cannot open directory %s"), path));
187         return NULL;
188       }
189     errno = 0;                  /* FIXME: errno should be read-only */
190
191     name_buffer_size = strlen (path) + NAME_FIELD_SIZE;
192     name_buffer = xmalloc ((size_t) (name_buffer_size + 2));
193     strcpy (name_buffer, path);
194     if (path[strlen (path) - 1] != '/')
195       strcat (name_buffer, "/");
196     name_length = strlen (name_buffer);
197
198     directory = find_directory (path);
199     all_children = directory ? directory->allnew : 0;
200
201     accumulator = new_accumulator ();
202
203     while (entry = readdir (dirp), entry)
204       {
205         struct stat stat_data;
206
207         /* Skip `.' and `..'.  */
208
209         if (is_dot_or_dotdot (entry->d_name))
210           continue;
211
212         if ((int) NAMLEN (entry) + name_length >= name_buffer_size)
213           {
214             while ((int) NAMLEN (entry) + name_length >= name_buffer_size)
215               name_buffer_size += NAME_FIELD_SIZE;
216             name_buffer = (char *)
217               xrealloc (name_buffer, (size_t) (name_buffer_size + 2));
218           }
219         strcpy (name_buffer + name_length, entry->d_name);
220
221         if (dereference_option
222 #ifdef AIX
223             ? statx (name_buffer, &stat_data, STATSIZE, STX_HIDDEN)
224             : statx (name_buffer, &stat_data, STATSIZE, STX_HIDDEN | STX_LINK)
225 #else
226             ? stat (name_buffer, &stat_data)
227             : lstat (name_buffer, &stat_data)
228 #endif
229             )
230           {
231             ERROR ((0, errno, _("Cannot stat %s"), name_buffer));
232             continue;
233           }
234
235         if ((one_file_system_option && device != stat_data.st_dev)
236             || (exclude_option && check_exclude (name_buffer)))
237           add_to_accumulator (accumulator, "N", 1);
238
239 #ifdef AIX
240         else if (S_ISHIDDEN (stat_data.st_mode))
241           {
242             add_to_accumulator (accumulator, "D", 1);
243             strcat (entry->d_name, "A");
244             entry->d_namlen++;
245           }
246 #endif
247
248         else if (S_ISDIR (stat_data.st_mode))
249           {
250             if (directory = find_directory (name_buffer), directory)
251               {
252                 /* Devices having the high bit set are NFS devices, which are
253                    attributed somewhat randomly in automounting situations.
254                    For avoiding spurious incremental redumping of directories,
255                    we have to plainly consider all NFS devices as equal,
256                    relying on the i-node only to establish differences.  */
257
258                 /* FIXME: Göran Uddeborg <goeran@uddeborg.pp.se> says, on
259                    1996-09-20, that SunOS 5/Solaris 2 uses unsigned long for
260                    the device number type.  */
261
262                 if ((((short) directory->device_number >= 0
263                       || (short) stat_data.st_dev >= 0)
264                      && directory->device_number != stat_data.st_dev)
265                     || directory->inode_number != stat_data.st_ino)
266                   {
267                     if (verbose_option)
268                       WARN ((0, 0, _("Directory %s has been renamed"),
269                              name_buffer));
270                     directory->allnew = 1;
271                     directory->device_number = stat_data.st_dev;
272                     directory->inode_number = stat_data.st_ino;
273                   }
274                 directory->dir_text = "";
275               }
276             else
277               {
278                 if (verbose_option)
279                   WARN ((0, 0, _("Directory %s is new"), name_buffer));
280                 note_directory (name_buffer, stat_data.st_dev, stat_data.st_ino,
281                                 "");
282                 directory = find_directory (name_buffer);
283                 directory->allnew = 1;
284               }
285             if (all_children && directory)
286               directory->allnew = 1;
287
288             add_to_accumulator (accumulator, "D", 1);
289           }
290
291         else
292           if (!all_children
293               && stat_data.st_mtime < newer_mtime_option
294               && (!after_date_option
295                   || stat_data.st_ctime < newer_ctime_option))
296             add_to_accumulator (accumulator, "N", 1);
297           else
298             add_to_accumulator (accumulator, "Y", 1);
299
300         add_to_accumulator (accumulator,
301                             entry->d_name, (int) (NAMLEN (entry) + 1));
302       }
303     add_to_accumulator (accumulator, "\000\000", 2);
304
305     free (name_buffer);
306     closedir (dirp);
307   }
308
309   /* Sort the contents of the directory, now that we have it all.  */
310
311   {
312     char *pointer = get_accumulator (accumulator);
313     size_t counter;
314     char *cursor;
315     char *buffer;
316     char **array;
317     char **array_cursor;
318
319     counter = 0;
320     for (cursor = pointer; *cursor; cursor += strlen (cursor) + 1)
321       counter++;
322
323     if (counter == 0)
324       {
325         delete_accumulator (accumulator);
326         return NULL;
327       }
328
329     array = (char **) xmalloc (sizeof (char *) * (counter + 1));
330
331     array_cursor = array;
332     for (cursor = pointer; *cursor; cursor += strlen (cursor) + 1)
333       *array_cursor++ = cursor;
334     *array_cursor = NULL;
335
336     qsort ((voidstar) array, counter, sizeof (char *), compare_dirents);
337
338     buffer = (char *) xmalloc ((size_t) (cursor - pointer + 2));
339
340     cursor = buffer;
341     for (array_cursor = array; *array_cursor; array_cursor++)
342       {
343         char *string = *array_cursor;
344
345         while ((*cursor++ = *string++))
346           continue;
347       }
348     *cursor = '\0';
349
350     delete_accumulator (accumulator);
351     free (array);
352     return buffer;
353   }
354 }
355
356 /*----------------------------------------------------------------------.
357 | Add all the files in PATH, which is a directory, to the namelist.  If |
358 | any of the files is a directory, recurse on the subdirectory.         |
359 `----------------------------------------------------------------------*/
360
361 static void
362 add_hierarchy_to_namelist (char *path, int device)
363 {
364   char *buffer = get_directory_contents (path, device);
365
366   {
367     struct name *name;
368
369     for (name = namelist; name; name = name->next)
370       if (strcmp (name->name, path) == 0)
371           break;
372     if (name)
373       name->dir_contents = buffer ? buffer : "\0\0\0\0";
374   }
375
376   if (buffer)
377     {
378       int name_length = strlen (path);
379       int allocated_length = (name_length >= NAME_FIELD_SIZE
380                               ? name_length + NAME_FIELD_SIZE
381                               : NAME_FIELD_SIZE);
382       char *name_buffer = xmalloc ((size_t) (allocated_length + 1));
383                                 /* FIXME: + 2 above?  */
384       char *string;
385       int string_length;
386
387       strcpy (name_buffer, path);
388       if (name_buffer[name_length - 1] != '/')
389         {
390           name_buffer[name_length++] = '/';
391           name_buffer[name_length] = '\0';
392         }
393
394       for (string = buffer; *string; string += string_length + 1)
395         {
396           string_length = strlen (string);
397           if (*string == 'D')
398             {
399               if (name_length + string_length >= allocated_length)
400                 {
401                   while (name_length + string_length >= allocated_length)
402                     allocated_length += NAME_FIELD_SIZE;
403                   name_buffer = (char *)
404                     xrealloc (name_buffer, (size_t) (allocated_length + 1));
405                 }
406               strcpy (name_buffer + name_length, string + 1);
407               addname (name_buffer);
408               add_hierarchy_to_namelist (name_buffer, device);
409             }
410         }
411
412       free (name_buffer);
413     }
414 }
415 \f
416 /*---.
417 | ?  |
418 `---*/
419
420 static void
421 read_directory_file (void)
422 {
423   dev_t device_number;
424   ino_t inode_number;
425   char *strp;
426   FILE *fp;
427   char buf[512];
428   static char *path = NULL;
429
430   if (path == NULL)
431     path = xmalloc (PATH_MAX);
432   time (&time_now);
433   if (listed_incremental_option[0] != '/')
434     {
435 #if HAVE_GETCWD
436       if (!getcwd (path, PATH_MAX))
437         FATAL_ERROR ((0, 0, _("Could not get current directory")));
438 #else
439       char *getwd ();
440
441       if (!getwd (path))
442         FATAL_ERROR ((0, 0, _("Could not get current directory: %s"), path));
443 #endif
444
445       if (strlen (path) + 1 + strlen (listed_incremental_option) + 1 > PATH_MAX)
446         ERROR ((TAREXIT_FAILURE, 0, _("File name %s/%s too long"),
447                 path, listed_incremental_option));
448
449       strcat (path, "/");
450       strcat (path, listed_incremental_option);
451       listed_incremental_option = path;
452     }
453   fp = fopen (listed_incremental_option, "r");
454   if (fp == 0 && errno != ENOENT)
455     {
456       ERROR ((0, errno, _("Cannot open %s"), listed_incremental_option));
457       return;
458     }
459   if (!fp)
460     return;
461   fgets (buf, sizeof (buf), fp);
462
463   /* FIXME: Using after_date_option as a first time flag looks fairly
464      dubious to me!  So, using -N with incremental might be buggy just
465      because of the next few lines.  I saw a few unexplained, almost harsh
466      advices, from other GNU people, about *not* using -N with incremental
467      dumps, and here might lie (part of) the reason.  */
468   if (!after_date_option)
469     {
470       newer_mtime_option = atol (buf);
471       after_date_option = 1;
472     }
473
474   while (fgets (buf, sizeof (buf), fp))
475     {
476       strp = &buf[strlen (buf)];
477       if (strp[-1] == '\n')
478         strp[-1] = '\0';
479       /* FIXME: For files ending with an incomplete line, maybe a NUL might
480          be missing, here...  */
481
482       strp = buf;
483       device_number = atol (strp);
484       while (ISDIGIT (*strp))
485         strp++;
486       inode_number = atol (strp);
487       while (ISSPACE (*strp))
488         strp++;
489       while (ISDIGIT (*strp))
490         strp++;
491       strp++;
492       unquote_string (strp);
493       note_directory (strp, device_number, inode_number, NULL);
494     }
495   if (fclose (fp) == EOF)
496     ERROR ((0, errno, "%s", listed_incremental_option));
497 }
498
499 /*---.
500 | ?  |
501 `---*/
502
503 void
504 write_dir_file (void)
505 {
506   FILE *fp;
507   struct directory *directory;
508   char *str;
509
510   fp = fopen (listed_incremental_option, "w");
511   if (fp == 0)
512     {
513       ERROR ((0, errno, _("Cannot write to %s"), listed_incremental_option));
514       return;
515     }
516   fprintf (fp, "%lu\n", time_now);
517   for (directory = directory_list; directory; directory = directory->next)
518     {
519       if (!directory->dir_text)
520         continue;
521       str = quote_copy_string (directory->name);
522       if (str)
523         {
524           fprintf (fp, "%u %u %s\n", directory->device_number,
525                    directory->inode_number, str);
526           free (str);
527         }
528       else
529         fprintf (fp, "%u %u %s\n", directory->device_number,
530                  directory->inode_number, directory->name);
531     }
532   if (fclose (fp) == EOF)
533     ERROR ((0, errno, "%s", listed_incremental_option));
534 }
535
536 /*---.
537 | ?  |
538 `---*/
539
540 static int
541 compare_names (char *param1, char *param2)
542 {
543   struct name *n1 = (struct name *) param1;
544   struct name *n2 = (struct name *) param2;
545
546   if (n1->found)
547     return n2->found ? strcmp (n1->name, n2->name) : -1;
548
549   if (n2->found)
550     return 1;
551
552   return strcmp (n1->name, n2->name);
553 }
554
555 /*-------------------------------------------------------------------------.
556 | Collect all the names from argv[] (or whatever), then expand them into a |
557 | directory tree, and put all the directories at the beginning.            |
558 `-------------------------------------------------------------------------*/
559
560 void
561 collect_and_sort_names (void)
562 {
563   struct name *name;
564   struct name *next_name;
565   int num_names;
566   struct stat statbuf;
567
568   name_gather ();
569
570   if (listed_incremental_option)
571     read_directory_file ();
572
573   if (!namelist)
574     addname (".");
575
576   for (name = namelist; name; name = next_name)
577     {
578       next_name = name->next;
579       if (name->found || name->dir_contents)
580         continue;
581       if (name->regexp)         /* FIXME: just skip regexps for now */
582         continue;
583       if (name->change_dir)
584         if (chdir (name->change_dir) < 0)
585           {
586             ERROR ((0, errno, _("Cannot chdir to %s"), name->change_dir));
587             continue;
588           }
589
590       if (
591 #ifdef AIX
592           statx (name->name, &statbuf, STATSIZE, STX_HIDDEN | STX_LINK)
593 #else
594           lstat (name->name, &statbuf) < 0
595 #endif
596           )
597         {
598           ERROR ((0, errno, _("Cannot stat %s"), name->name));
599           continue;
600         }
601       if (S_ISDIR (statbuf.st_mode))
602         {
603           name->found = 1;
604           add_hierarchy_to_namelist (name->name, statbuf.st_dev);
605         }
606     }
607
608   num_names = 0;
609   for (name = namelist; name; name = name->next)
610     num_names++;
611   namelist = (struct name *)
612     merge_sort ((voidstar) namelist, num_names,
613                 (char *) (&(namelist->next)) - (char *) namelist,
614                 compare_names);
615
616   for (name = namelist; name; name = name->next)
617     name->found = 0;
618
619   if (listed_incremental_option)
620     write_dir_file ();
621 }
622 \f
623 /* Restoration of incremental dumps.  */
624
625 /*---.
626 | ?  |
627 `---*/
628
629 void
630 gnu_restore (int skipcrud)
631 {
632   char *current_dir;
633   char *archive_dir;
634   struct accumulator *accumulator;
635   char *p;
636   DIR *dirp;
637   struct dirent *d;
638   char *cur, *arc;
639   long size, copied;
640   union block *data_block;
641   char *to;
642
643 #define CURRENT_FILE_NAME (skipcrud + current_file_name)
644
645   dirp = opendir (CURRENT_FILE_NAME);
646
647   if (!dirp)
648     {
649       /* The directory doesn't exist now.  It'll be created.  In any
650          case, we don't have to delete any files out of it.  */
651
652       skip_file ((long) current_stat.st_size);
653       return;
654     }
655
656   accumulator = new_accumulator ();
657   while (d = readdir (dirp), d)
658     {
659       if (is_dot_or_dotdot (d->d_name))
660         continue;
661
662       add_to_accumulator (accumulator, d->d_name, (int) (NAMLEN (d) + 1));
663     }
664   closedir (dirp);
665   add_to_accumulator (accumulator, "", 1);
666
667   current_dir = get_accumulator (accumulator);
668   archive_dir = (char *) xmalloc ((size_t) current_stat.st_size);
669   to = archive_dir;
670   for (size = current_stat.st_size; size > 0; size -= copied)
671     {
672       data_block = find_next_block ();
673       if (!data_block)
674         {
675           ERROR ((0, 0, _("Unexpected EOF in archive")));
676           break;                /* FIXME: What happens then?  */
677         }
678       copied = available_space_after (data_block);
679       if (copied > size)
680         copied = size;
681       memcpy (to, data_block->buffer, (size_t) copied);
682       to += copied;
683       set_next_block_after ((union block *)
684                             (data_block->buffer + copied - 1));
685     }
686
687   for (cur = current_dir; *cur; cur += strlen (cur) + 1)
688     {
689       for (arc = archive_dir; *arc; arc += strlen (arc) + 1)
690         {
691           arc++;
692           if (!strcmp (arc, cur))
693             break;
694         }
695       if (*arc == '\0')
696         {
697           p = new_name (CURRENT_FILE_NAME, cur);
698           if (interactive_option && !confirm ("delete", p))
699             {
700               free (p);
701               continue;
702             }
703           if (verbose_option)
704             fprintf (stdlis, _("%s: Deleting %s\n"), program_name, p);
705           if (!remove_any_file (p, 1))
706             ERROR ((0, errno, _("Error while deleting %s"), p));
707           free (p);
708         }
709
710     }
711   delete_accumulator (accumulator);
712   free (archive_dir);
713
714 #undef CURRENT_FILE_NAME
715 }