incremen.c 15 KB

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