(purge_directory): Fix format buffer typos in warning strings.
[debian/tar] / src / incremen.c
1 /* GNU dump extensions to tar.
2
3    Copyright (C) 1988, 1992, 1993, 1994, 1996, 1997, 1999, 2000, 2001,
4    2003, 2004 Free Software Foundation, Inc.
5
6    This program is free software; you can redistribute it and/or modify it
7    under the terms of the GNU General Public License as published by the
8    Free Software Foundation; either version 2, or (at your option) any later
9    version.
10
11    This program is distributed in the hope that it will be useful, but
12    WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
14    Public License for more details.
15
16    You should have received a copy of the GNU General Public License along
17    with this program; if not, write to the Free Software Foundation, Inc.,
18    59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
19
20 #include "system.h"
21 #include <getline.h>
22 #include <hash.h>
23 #include <quotearg.h>
24 #include "common.h"
25 #define obstack_chunk_alloc xmalloc
26 #define obstack_chunk_free free
27 #include <obstack.h>
28
29 /* Incremental dump specialities.  */
30
31 /* Which child files to save under a directory.  */
32 enum children {NO_CHILDREN, CHANGED_CHILDREN, ALL_CHILDREN};
33
34 /* Directory attributes.  */
35 struct directory
36   {
37     dev_t device_number;        /* device number for directory */
38     ino_t inode_number;         /* inode number for directory */
39     enum children children;
40     bool nfs;
41     bool found;
42     char name[1];               /* file name of directory */
43   };
44
45 static Hash_table *directory_table;
46
47 #if HAVE_ST_FSTYPE_STRING
48   static char const nfs_string[] = "nfs";
49 # define NFS_FILE_STAT(st) (strcmp ((st).st_fstype, nfs_string) == 0)
50 #else
51 # define ST_DEV_MSB(st) (~ (dev_t) 0 << (sizeof (st).st_dev * CHAR_BIT - 1))
52 # define NFS_FILE_STAT(st) (((st).st_dev & ST_DEV_MSB (st)) != 0)
53 #endif
54
55 /* Calculate the hash of a directory.  */
56 static unsigned
57 hash_directory (void const *entry, unsigned n_buckets)
58 {
59   struct directory const *directory = entry;
60   return hash_string (directory->name, n_buckets);
61 }
62
63 /* Compare two directories for equality.  */
64 static bool
65 compare_directories (void const *entry1, void const *entry2)
66 {
67   struct directory const *directory1 = entry1;
68   struct directory const *directory2 = entry2;
69   return strcmp (directory1->name, directory2->name) == 0;
70 }
71
72 /* Create and link a new directory entry for directory NAME, having a
73    device number DEV and an inode number INO, with NFS indicating
74    whether it is an NFS device and FOUND indicating whether we have
75    found that the directory exists.  */
76 static struct directory *
77 note_directory (char const *name, dev_t dev, ino_t ino, bool nfs, bool found)
78 {
79   size_t size = offsetof (struct directory, name) + strlen (name) + 1;
80   struct directory *directory = xmalloc (size);
81
82   directory->device_number = dev;
83   directory->inode_number = ino;
84   directory->children = CHANGED_CHILDREN;
85   directory->nfs = nfs;
86   directory->found = found;
87   strcpy (directory->name, name);
88
89   if (! ((directory_table
90           || (directory_table = hash_initialize (0, 0, hash_directory,
91                                                  compare_directories, 0)))
92          && hash_insert (directory_table, directory)))
93     xalloc_die ();
94
95   return directory;
96 }
97
98 /* Return a directory entry for a given file NAME, or zero if none found.  */
99 static struct directory *
100 find_directory (char *name)
101 {
102   if (! directory_table)
103     return 0;
104   else
105     {
106       size_t size = offsetof (struct directory, name) + strlen (name) + 1;
107       struct directory *dir = alloca (size);
108       strcpy (dir->name, name);
109       return hash_lookup (directory_table, dir);
110     }
111 }
112
113 static int
114 compare_dirents (const void *first, const void *second)
115 {
116   return strcmp ((*(char *const *) first) + 1,
117                  (*(char *const *) second) + 1);
118 }
119
120 /* Recursively scan the given directory. */
121 static void
122 scan_directory (struct obstack *stk, char *dir_name, dev_t device)
123 {
124   char *dirp = savedir (dir_name);      /* for scanning directory */
125   char const *entry;    /* directory entry being scanned */
126   size_t entrylen;      /* length of directory entry */
127   char *name_buffer;            /* directory, `/', and directory member */
128   size_t name_buffer_size;      /* allocated size of name_buffer, minus 2 */
129   size_t name_length;           /* used length in name_buffer */
130   struct directory *directory;  /* for checking if already seen */
131   enum children children;
132
133   if (! dirp)
134     {
135       savedir_error (dir_name);
136     }
137   errno = 0;
138
139   name_buffer_size = strlen (dir_name) + NAME_FIELD_SIZE;
140   name_buffer = xmalloc (name_buffer_size + 2);
141   strcpy (name_buffer, dir_name);
142   if (! ISSLASH (dir_name[strlen (dir_name) - 1]))
143     strcat (name_buffer, "/");
144   name_length = strlen (name_buffer);
145
146   directory = find_directory (dir_name);
147   children = directory ? directory->children : CHANGED_CHILDREN;
148
149   if (dirp && children != NO_CHILDREN)
150     for (entry = dirp;
151          (entrylen = strlen (entry)) != 0;
152          entry += entrylen + 1)
153       {
154         if (name_buffer_size <= entrylen + name_length)
155           {
156             do
157               name_buffer_size += NAME_FIELD_SIZE;
158             while (name_buffer_size <= entrylen + name_length);
159             name_buffer = xrealloc (name_buffer, name_buffer_size + 2);
160           }
161         strcpy (name_buffer + name_length, entry);
162
163         if (excluded_name (name_buffer))
164           obstack_1grow (stk, 'N');
165         else
166           {
167             struct stat stat_data;
168
169             if (deref_stat (dereference_option, name_buffer, &stat_data))
170               {
171                 stat_diag (name_buffer);
172                 continue;
173               }
174
175             if (S_ISDIR (stat_data.st_mode))
176               {
177                 bool nfs = NFS_FILE_STAT (stat_data);
178
179                 if ((directory = find_directory (name_buffer)) != NULL)
180                   {
181                     /* With NFS, the same file can have two different devices
182                        if an NFS directory is mounted in multiple locations,
183                        which is relatively common when automounting.
184                        To avoid spurious incremental redumping of
185                        directories, consider all NFS devices as equal,
186                        relying on the i-node to establish differences.  */
187
188                     if (! (((directory->nfs & nfs)
189                             || directory->device_number == stat_data.st_dev)
190                            && directory->inode_number == stat_data.st_ino))
191                         {
192                           if (verbose_option)
193                             WARN ((0, 0, _("%s: Directory has been renamed"),
194                                    quotearg_colon (name_buffer)));
195                           directory->children = ALL_CHILDREN;
196                           directory->nfs = nfs;
197                           directory->device_number = stat_data.st_dev;
198                           directory->inode_number = stat_data.st_ino;
199                         }
200                     directory->found = 1;
201                   }
202                 else
203                   {
204                     if (verbose_option)
205                       WARN ((0, 0, _("%s: Directory is new"),
206                              quotearg_colon (name_buffer)));
207                     directory = note_directory (name_buffer,
208                                                 stat_data.st_dev,
209                                                 stat_data.st_ino, nfs, 1);
210                     directory->children =
211                       ((listed_incremental_option
212                         || OLDER_STAT_TIME (stat_data, m)
213                         || (after_date_option
214                             && OLDER_STAT_TIME (stat_data, c)))
215                        ? ALL_CHILDREN
216                        : CHANGED_CHILDREN);
217                   }
218
219                 if (one_file_system_option && device != stat_data.st_dev)
220                   directory->children = NO_CHILDREN;
221                 else if (children == ALL_CHILDREN)
222                   directory->children = ALL_CHILDREN;
223
224                 obstack_1grow (stk, 'D');
225               }
226
227             else if (one_file_system_option && device != stat_data.st_dev)
228               obstack_1grow (stk, 'N');
229
230 #ifdef S_ISHIDDEN
231             else if (S_ISHIDDEN (stat_data.st_mode))
232               {
233                 obstack_1grow (stk, 'D');
234                 obstack_grow (stk, entry, entrylen);
235                 obstack_grow (stk, "A", 2);
236                 continue;
237               }
238 #endif
239
240             else
241               if (children == CHANGED_CHILDREN
242                   && OLDER_STAT_TIME (stat_data, m)
243                   && (!after_date_option || OLDER_STAT_TIME (stat_data, c)))
244                 obstack_1grow (stk, 'N');
245               else
246                 obstack_1grow (stk, 'Y');
247           }
248
249         obstack_grow (stk, entry, entrylen + 1);
250       }
251
252   obstack_grow (stk, "\000\000", 2);
253
254   free (name_buffer);
255   if (dirp)
256     free (dirp);
257 }
258
259 /* Sort the contents of the obstack, and convert it to the char * */
260 static char *
261 sort_obstack (struct obstack *stk)
262 {
263   char *pointer = obstack_finish (stk);
264   size_t counter;
265   char *cursor;
266   char *buffer;
267   char **array;
268   char **array_cursor;
269
270   counter = 0;
271   for (cursor = pointer; *cursor; cursor += strlen (cursor) + 1)
272     counter++;
273
274   if (!counter)
275     return NULL;
276
277   array = obstack_alloc (stk, sizeof (char *) * (counter + 1));
278
279   array_cursor = array;
280   for (cursor = pointer; *cursor; cursor += strlen (cursor) + 1)
281     *array_cursor++ = cursor;
282   *array_cursor = 0;
283
284   qsort (array, counter, sizeof (char *), compare_dirents);
285
286   buffer = xmalloc (cursor - pointer + 2);
287
288   cursor = buffer;
289   for (array_cursor = array; *array_cursor; array_cursor++)
290     {
291       char *string = *array_cursor;
292
293       while ((*cursor++ = *string++))
294         continue;
295     }
296   *cursor = '\0';
297   return buffer;
298 }
299
300 char *
301 get_directory_contents (char *dir_name, dev_t device)
302 {
303   struct obstack stk;
304   char *buffer;
305
306   obstack_init (&stk);
307   scan_directory (&stk, dir_name, device);
308   buffer = sort_obstack (&stk);
309   obstack_free (&stk, NULL);
310   return buffer;
311 }
312
313 \f
314
315 static FILE *listed_incremental_stream;
316
317 void
318 read_directory_file (void)
319 {
320   int fd;
321   FILE *fp;
322   char *buf = 0;
323   size_t bufsize;
324
325   /* Open the file for both read and write.  That way, we can write
326      it later without having to reopen it, and don't have to worry if
327      we chdir in the meantime.  */
328   fd = open (listed_incremental_option, O_RDWR | O_CREAT, MODE_RW);
329   if (fd < 0)
330     {
331       open_error (listed_incremental_option);
332       return;
333     }
334
335   fp = fdopen (fd, "r+");
336   if (! fp)
337     {
338       open_error (listed_incremental_option);
339       close (fd);
340       return;
341     }
342
343   listed_incremental_stream = fp;
344
345   if (0 < getline (&buf, &bufsize, fp))
346     {
347       char *ebuf;
348       int n;
349       long lineno = 1;
350       unsigned long u = (errno = 0, strtoul (buf, &ebuf, 10));
351       time_t t = u;
352       if (buf == ebuf || (u == 0 && errno == EINVAL))
353         ERROR ((0, 0, "%s:1: %s", quotearg_colon (listed_incremental_option),
354                 _("Invalid time stamp")));
355       else if (t != u || (u == -1 && errno == ERANGE))
356         ERROR ((0, 0, "%s:1: %s", quotearg_colon (listed_incremental_option),
357                 _("Time stamp out of range")));
358       else
359         {
360           newer_mtime_option.tv_sec = t;
361           newer_mtime_option.tv_nsec = 0;
362         }
363
364       while (0 < (n = getline (&buf, &bufsize, fp)))
365         {
366           dev_t dev;
367           ino_t ino;
368           bool nfs = buf[0] == '+';
369           char *strp = buf + nfs;
370
371           lineno++;
372
373           if (buf[n - 1] == '\n')
374             buf[n - 1] = '\0';
375
376           errno = 0;
377           dev = u = strtoul (strp, &ebuf, 10);
378           if (strp == ebuf || (u == 0 && errno == EINVAL))
379             ERROR ((0, 0, "%s:%ld: %s",
380                     quotearg_colon (listed_incremental_option), lineno,
381                     _("Invalid device number")));
382           else if (dev != u || (u == -1 && errno == ERANGE))
383             ERROR ((0, 0, "%s:%ld: %s",
384                     quotearg_colon (listed_incremental_option), lineno,
385                     _("Device number out of range")));
386           strp = ebuf;
387
388           errno = 0;
389           ino = u = strtoul (strp, &ebuf, 10);
390           if (strp == ebuf || (u == 0 && errno == EINVAL))
391             ERROR ((0, 0, "%s:%ld: %s",
392                     quotearg_colon (listed_incremental_option), lineno,
393                     _("Invalid inode number")));
394           else if (ino != u || (u == -1 && errno == ERANGE))
395             ERROR ((0, 0, "%s:%ld: %s",
396                     quotearg_colon (listed_incremental_option), lineno,
397                     _("Inode number out of range")));
398           strp = ebuf;
399
400           strp++;
401           unquote_string (strp);
402           note_directory (strp, dev, ino, nfs, 0);
403         }
404     }
405
406   if (ferror (fp))
407     read_error (listed_incremental_option);
408   if (buf)
409     free (buf);
410 }
411
412 /* Output incremental data for the directory ENTRY to the file DATA.
413    Return nonzero if successful, preserving errno on write failure.  */
414 static bool
415 write_directory_file_entry (void *entry, void *data)
416 {
417   struct directory const *directory = entry;
418   FILE *fp = data;
419
420   if (directory->found)
421     {
422       int e;
423       char *str = quote_copy_string (directory->name);
424       fprintf (fp, "+%lu %lu %s\n" + ! directory->nfs,
425                (unsigned long) directory->device_number,
426                (unsigned long) directory->inode_number,
427                str ? str : directory->name);
428       e = errno;
429       if (str)
430         free (str);
431       errno = e;
432     }
433
434   return ! ferror (fp);
435 }
436
437 void
438 write_directory_file (void)
439 {
440   FILE *fp = listed_incremental_stream;
441
442   if (! fp)
443     return;
444
445   if (fseek (fp, 0L, SEEK_SET) != 0)
446     seek_error (listed_incremental_option);
447   if (sys_truncate (fileno (fp)) != 0)
448     truncate_error (listed_incremental_option);
449
450   fprintf (fp, "%lu\n", (unsigned long) start_time);
451   if (! ferror (fp) && directory_table)
452     hash_do_for_each (directory_table, write_directory_file_entry, fp);
453   if (ferror (fp))
454     write_error (listed_incremental_option);
455   if (fclose (fp) != 0)
456     close_error (listed_incremental_option);
457 }
458
459 \f
460 /* Restoration of incremental dumps.  */
461
462 /* Examine the directories under directory_name and delete any
463    files that were not there at the time of the back-up. */
464 void
465 purge_directory (char const *directory_name)
466 {
467   char *archive_dir;
468   char *current_dir;
469   char *cur, *arc;
470   size_t size;
471   size_t copied;
472   union block *data_block;
473   char *to;
474
475   current_dir = savedir (directory_name);
476
477   if (!current_dir)
478     {
479       /* The directory doesn't exist now.  It'll be created.  In any
480          case, we don't have to delete any files out of it.  */
481
482       skip_member ();
483       return;
484     }
485
486   size = current_stat_info.stat.st_size;
487   if (size != current_stat_info.stat.st_size)
488     xalloc_die ();
489   archive_dir = xmalloc (size);
490   to = archive_dir;
491   for (; size > 0; size -= copied)
492     {
493       data_block = find_next_block ();
494       if (!data_block)
495         {
496           ERROR ((0, 0, _("Unexpected EOF in archive")));
497           break;                /* FIXME: What happens then?  */
498         }
499       copied = available_space_after (data_block);
500       if (copied > size)
501         copied = size;
502       memcpy (to, data_block->buffer, copied);
503       to += copied;
504       set_next_block_after ((union block *)
505                             (data_block->buffer + copied - 1));
506     }
507
508   for (cur = current_dir; *cur; cur += strlen (cur) + 1)
509     {
510       for (arc = archive_dir; *arc; arc += strlen (arc) + 1)
511         {
512           arc++;
513           if (!strcmp (arc, cur))
514             break;
515         }
516       if (*arc == '\0')
517         {
518           struct stat st;
519           char *p = new_name (directory_name, cur);
520
521           if (deref_stat (true, p, &st))
522             {
523               stat_diag (p);
524               WARN((0, 0, _("%s: Not purging directory: unable to stat"),
525                     quotearg_colon (p)));
526               continue; 
527             }
528           else if (one_file_system_option && st.st_dev != root_device)
529             {
530               WARN((0, 0,
531                     _("%s: directory is on a different device: not purging"),
532                     quotearg_colon (p)));
533               continue;
534             }
535             
536           if (! interactive_option || confirm ("delete", p))
537             {
538               if (verbose_option)
539                 fprintf (stdlis, _("%s: Deleting %s\n"),
540                          program_name, quote (p));
541               if (! remove_any_file (p, RECURSIVE_REMOVE_OPTION))
542                 {
543                   int e = errno;
544                   ERROR ((0, e, _("%s: Cannot remove"), quotearg_colon (p)));
545                 }
546             }
547           free (p);
548         }
549
550     }
551   free (current_dir);
552   free (archive_dir);
553 }