1 /* GNU dump extensions to tar.
2 Copyright (C) 1988, 92, 93, 94, 96, 97 Free Software Foundation, Inc.
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
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.
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. */
23 #define ISDIGIT(Char) (ISASCII (Char) && isdigit (Char))
24 #define ISSPACE(Char) (ISASCII (Char) && isspace (Char))
28 /* Variable sized generic character buffers. */
37 /* Amount of space guaranteed just after a reallocation. */
38 #define ACCUMULATOR_SLACK 50
40 /*---------------------------------------------------------.
41 | Return the accumulated data from an ACCUMULATOR buffer. |
42 `---------------------------------------------------------*/
45 get_accumulator (struct accumulator
*accumulator
)
47 return accumulator
->pointer
;
50 /*-----------------------------------------------.
51 | Allocate and return a new accumulator buffer. |
52 `-----------------------------------------------*/
54 static struct accumulator
*
55 new_accumulator (void)
57 struct accumulator
*accumulator
58 = (struct accumulator
*) xmalloc (sizeof (struct accumulator
));
60 accumulator
->allocated
= ACCUMULATOR_SLACK
;
61 accumulator
->pointer
= (char *) xmalloc (ACCUMULATOR_SLACK
);
62 accumulator
->length
= 0;
66 /*-----------------------------------.
67 | Deallocate an ACCUMULATOR buffer. |
68 `-----------------------------------*/
71 delete_accumulator (struct accumulator
*accumulator
)
73 free (accumulator
->pointer
);
77 /*----------------------------------------------------------------------.
78 | At the end of an ACCUMULATOR buffer, add a DATA block of SIZE bytes. |
79 `----------------------------------------------------------------------*/
82 add_to_accumulator (struct accumulator
*accumulator
,
83 const char *data
, int size
)
85 if (accumulator
->length
+ size
> accumulator
->allocated
)
87 accumulator
->allocated
= accumulator
->length
+ size
+ ACCUMULATOR_SLACK
;
88 accumulator
->pointer
= (char *)
89 xrealloc (accumulator
->pointer
, (size_t) accumulator
->allocated
);
91 memcpy (accumulator
->pointer
+ accumulator
->length
, data
, (size_t) size
);
92 accumulator
->length
+= size
;
95 /* Incremental dump specialities. */
98 static time_t time_now
;
100 /* List of directory names. */
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 */
108 const char *dir_text
;
110 static struct directory
*directory_list
= NULL
;
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 `-------------------------------------------------------------------*/
118 note_directory (char *name
, dev_t device_number
, ino_t inode_number
,
121 struct directory
*directory
122 = (struct directory
*) xmalloc (sizeof (struct directory
));
124 directory
->next
= directory_list
;
125 directory_list
= directory
;
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;
134 /*------------------------------------------------------------------------.
135 | Return a directory entry for a given path NAME, or NULL if none found. |
136 `------------------------------------------------------------------------*/
138 static struct directory
*
139 find_directory (char *name
)
141 struct directory
*directory
;
143 for (directory
= directory_list
;
145 directory
= directory
->next
)
147 if (!strcmp (directory
->name
, name
))
158 compare_dirents (const voidstar first
, const voidstar second
)
160 return strcmp ((*(char *const *) first
) + 1,
161 (*(char *const *) second
) + 1);
169 get_directory_contents (char *path
, int device
)
171 struct accumulator
*accumulator
;
173 /* Recursively scan the given PATH. */
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 */
186 ERROR ((0, errno
, _("Cannot open directory %s"), path
));
189 errno
= 0; /* FIXME: errno should be read-only */
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
);
198 directory
= find_directory (path
);
199 all_children
= directory
? directory
->allnew
: 0;
201 accumulator
= new_accumulator ();
203 while (entry
= readdir (dirp
), entry
)
205 struct stat stat_data
;
207 /* Skip `.' and `..'. */
209 if (is_dot_or_dotdot (entry
->d_name
))
212 if ((int) NAMLEN (entry
) + name_length
>= name_buffer_size
)
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));
219 strcpy (name_buffer
+ name_length
, entry
->d_name
);
221 if (dereference_option
223 ? statx (name_buffer
, &stat_data
, STATSIZE
, STX_HIDDEN
)
224 : statx (name_buffer
, &stat_data
, STATSIZE
, STX_HIDDEN
| STX_LINK
)
226 ? stat (name_buffer
, &stat_data
)
227 : lstat (name_buffer
, &stat_data
)
231 ERROR ((0, errno
, _("Cannot stat %s"), name_buffer
));
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);
240 else if (S_ISHIDDEN (stat_data
.st_mode
))
242 add_to_accumulator (accumulator
, "D", 1);
243 strcat (entry
->d_name
, "A");
248 else if (S_ISDIR (stat_data
.st_mode
))
250 if (directory
= find_directory (name_buffer
), directory
)
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. */
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. */
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
)
268 WARN ((0, 0, _("Directory %s has been renamed"),
270 directory
->allnew
= 1;
271 directory
->device_number
= stat_data
.st_dev
;
272 directory
->inode_number
= stat_data
.st_ino
;
274 directory
->dir_text
= "";
279 WARN ((0, 0, _("Directory %s is new"), name_buffer
));
280 note_directory (name_buffer
, stat_data
.st_dev
, stat_data
.st_ino
,
282 directory
= find_directory (name_buffer
);
283 directory
->allnew
= 1;
285 if (all_children
&& directory
)
286 directory
->allnew
= 1;
288 add_to_accumulator (accumulator
, "D", 1);
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);
298 add_to_accumulator (accumulator
, "Y", 1);
300 add_to_accumulator (accumulator
,
301 entry
->d_name
, (int) (NAMLEN (entry
) + 1));
303 add_to_accumulator (accumulator
, "\000\000", 2);
309 /* Sort the contents of the directory, now that we have it all. */
312 char *pointer
= get_accumulator (accumulator
);
320 for (cursor
= pointer
; *cursor
; cursor
+= strlen (cursor
) + 1)
325 delete_accumulator (accumulator
);
329 array
= (char **) xmalloc (sizeof (char *) * (counter
+ 1));
331 array_cursor
= array
;
332 for (cursor
= pointer
; *cursor
; cursor
+= strlen (cursor
) + 1)
333 *array_cursor
++ = cursor
;
334 *array_cursor
= NULL
;
336 qsort ((voidstar
) array
, counter
, sizeof (char *), compare_dirents
);
338 buffer
= (char *) xmalloc ((size_t) (cursor
- pointer
+ 2));
341 for (array_cursor
= array
; *array_cursor
; array_cursor
++)
343 char *string
= *array_cursor
;
345 while ((*cursor
++ = *string
++))
350 delete_accumulator (accumulator
);
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 `----------------------------------------------------------------------*/
362 add_hierarchy_to_namelist (char *path
, int device
)
364 char *buffer
= get_directory_contents (path
, device
);
369 for (name
= namelist
; name
; name
= name
->next
)
370 if (strcmp (name
->name
, path
) == 0)
373 name
->dir_contents
= buffer
? buffer
: "\0\0\0\0";
378 int name_length
= strlen (path
);
379 int allocated_length
= (name_length
>= NAME_FIELD_SIZE
380 ? name_length
+ NAME_FIELD_SIZE
382 char *name_buffer
= xmalloc ((size_t) (allocated_length
+ 1));
383 /* FIXME: + 2 above? */
387 strcpy (name_buffer
, path
);
388 if (name_buffer
[name_length
- 1] != '/')
390 name_buffer
[name_length
++] = '/';
391 name_buffer
[name_length
] = '\0';
394 for (string
= buffer
; *string
; string
+= string_length
+ 1)
396 string_length
= strlen (string
);
399 if (name_length
+ string_length
>= allocated_length
)
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));
406 strcpy (name_buffer
+ name_length
, string
+ 1);
407 addname (name_buffer
);
408 add_hierarchy_to_namelist (name_buffer
, device
);
421 read_directory_file (void)
428 static char *path
= NULL
;
431 path
= xmalloc (PATH_MAX
);
433 if (listed_incremental_option
[0] != '/')
436 if (!getcwd (path
, PATH_MAX
))
437 FATAL_ERROR ((0, 0, _("Could not get current directory")));
442 FATAL_ERROR ((0, 0, _("Could not get current directory: %s"), path
));
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
));
450 strcat (path
, listed_incremental_option
);
451 listed_incremental_option
= path
;
453 fp
= fopen (listed_incremental_option
, "r");
454 if (fp
== 0 && errno
!= ENOENT
)
456 ERROR ((0, errno
, _("Cannot open %s"), listed_incremental_option
));
461 fgets (buf
, sizeof (buf
), fp
);
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
)
470 newer_mtime_option
= atol (buf
);
471 after_date_option
= 1;
474 while (fgets (buf
, sizeof (buf
), fp
))
476 strp
= &buf
[strlen (buf
)];
477 if (strp
[-1] == '\n')
479 /* FIXME: For files ending with an incomplete line, maybe a NUL might
480 be missing, here... */
483 device_number
= atol (strp
);
484 while (ISDIGIT (*strp
))
486 inode_number
= atol (strp
);
487 while (ISSPACE (*strp
))
489 while (ISDIGIT (*strp
))
492 unquote_string (strp
);
493 note_directory (strp
, device_number
, inode_number
, NULL
);
495 if (fclose (fp
) == EOF
)
496 ERROR ((0, errno
, "%s", listed_incremental_option
));
504 write_dir_file (void)
507 struct directory
*directory
;
510 fp
= fopen (listed_incremental_option
, "w");
513 ERROR ((0, errno
, _("Cannot write to %s"), listed_incremental_option
));
516 fprintf (fp
, "%lu\n", time_now
);
517 for (directory
= directory_list
; directory
; directory
= directory
->next
)
519 if (!directory
->dir_text
)
521 str
= quote_copy_string (directory
->name
);
524 fprintf (fp
, "%u %u %s\n", directory
->device_number
,
525 directory
->inode_number
, str
);
529 fprintf (fp
, "%u %u %s\n", directory
->device_number
,
530 directory
->inode_number
, directory
->name
);
532 if (fclose (fp
) == EOF
)
533 ERROR ((0, errno
, "%s", listed_incremental_option
));
541 compare_names (char *param1
, char *param2
)
543 struct name
*n1
= (struct name
*) param1
;
544 struct name
*n2
= (struct name
*) param2
;
547 return n2
->found
? strcmp (n1
->name
, n2
->name
) : -1;
552 return strcmp (n1
->name
, n2
->name
);
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 `-------------------------------------------------------------------------*/
561 collect_and_sort_names (void)
564 struct name
*next_name
;
570 if (listed_incremental_option
)
571 read_directory_file ();
576 for (name
= namelist
; name
; name
= next_name
)
578 next_name
= name
->next
;
579 if (name
->found
|| name
->dir_contents
)
581 if (name
->regexp
) /* FIXME: just skip regexps for now */
583 if (name
->change_dir
)
584 if (chdir (name
->change_dir
) < 0)
586 ERROR ((0, errno
, _("Cannot chdir to %s"), name
->change_dir
));
592 statx (name
->name
, &statbuf
, STATSIZE
, STX_HIDDEN
| STX_LINK
)
594 lstat (name
->name
, &statbuf
) < 0
598 ERROR ((0, errno
, _("Cannot stat %s"), name
->name
));
601 if (S_ISDIR (statbuf
.st_mode
))
604 add_hierarchy_to_namelist (name
->name
, statbuf
.st_dev
);
609 for (name
= namelist
; name
; name
= name
->next
)
611 namelist
= (struct name
*)
612 merge_sort ((voidstar
) namelist
, num_names
,
613 (char *) (&(namelist
->next
)) - (char *) namelist
,
616 for (name
= namelist
; name
; name
= name
->next
)
619 if (listed_incremental_option
)
623 /* Restoration of incremental dumps. */
630 gnu_restore (int skipcrud
)
634 struct accumulator
*accumulator
;
640 union block
*data_block
;
643 #define CURRENT_FILE_NAME (skipcrud + current_file_name)
645 dirp
= opendir (CURRENT_FILE_NAME
);
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. */
652 skip_file ((long) current_stat
.st_size
);
656 accumulator
= new_accumulator ();
657 while (d
= readdir (dirp
), d
)
659 if (is_dot_or_dotdot (d
->d_name
))
662 add_to_accumulator (accumulator
, d
->d_name
, (int) (NAMLEN (d
) + 1));
665 add_to_accumulator (accumulator
, "", 1);
667 current_dir
= get_accumulator (accumulator
);
668 archive_dir
= (char *) xmalloc ((size_t) current_stat
.st_size
);
670 for (size
= current_stat
.st_size
; size
> 0; size
-= copied
)
672 data_block
= find_next_block ();
675 ERROR ((0, 0, _("Unexpected EOF in archive")));
676 break; /* FIXME: What happens then? */
678 copied
= available_space_after (data_block
);
681 memcpy (to
, data_block
->buffer
, (size_t) copied
);
683 set_next_block_after ((union block
*)
684 (data_block
->buffer
+ copied
- 1));
687 for (cur
= current_dir
; *cur
; cur
+= strlen (cur
) + 1)
689 for (arc
= archive_dir
; *arc
; arc
+= strlen (arc
) + 1)
692 if (!strcmp (arc
, cur
))
697 p
= new_name (CURRENT_FILE_NAME
, cur
);
698 if (interactive_option
&& !confirm ("delete", p
))
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
));
711 delete_accumulator (accumulator
);
714 #undef CURRENT_FILE_NAME