gnu.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677
  1. /* GNU dump extensions to tar.
  2. Copyright (C) 1988, 1992, 1993 Free Software Foundation
  3. This file is part of GNU Tar.
  4. GNU Tar is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2, or (at your option)
  7. any later version.
  8. GNU Tar is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with GNU Tar; see the file COPYING. If not, write to
  14. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
  15. #include <stdio.h>
  16. #include <sys/types.h>
  17. #include <ctype.h>
  18. #include <errno.h>
  19. #ifndef STDC_HEADERS
  20. extern int errno;
  21. #endif
  22. #include <time.h>
  23. time_t time ();
  24. #include "tar.h"
  25. #include "port.h"
  26. #ifndef S_ISLNK
  27. #define lstat stat
  28. #endif
  29. extern time_t new_time;
  30. extern FILE *msg_file;
  31. void addname ();
  32. int check_exclude ();
  33. extern PTR ck_malloc ();
  34. extern PTR ck_realloc ();
  35. int confirm ();
  36. extern PTR init_buffer ();
  37. extern char *get_buffer ();
  38. int is_dot_or_dotdot ();
  39. extern void add_buffer ();
  40. extern void flush_buffer ();
  41. void name_gather ();
  42. int recursively_delete ();
  43. void skip_file ();
  44. char *un_quote_string ();
  45. extern char *new_name ();
  46. static void add_dir_name ();
  47. struct dirname
  48. {
  49. struct dirname *next;
  50. char *name;
  51. char *dir_text;
  52. int dev;
  53. int ino;
  54. int allnew;
  55. };
  56. static struct dirname *dir_list;
  57. static time_t this_time;
  58. void
  59. add_dir (name, dev, ino, text)
  60. char *name;
  61. char *text;
  62. dev_t dev;
  63. ino_t ino;
  64. {
  65. struct dirname *dp;
  66. dp = (struct dirname *) ck_malloc (sizeof (struct dirname));
  67. if (!dp)
  68. abort ();
  69. dp->next = dir_list;
  70. dir_list = dp;
  71. dp->dev = dev;
  72. dp->ino = ino;
  73. dp->name = ck_malloc (strlen (name) + 1);
  74. strcpy (dp->name, name);
  75. dp->dir_text = text;
  76. dp->allnew = 0;
  77. }
  78. void
  79. read_dir_file ()
  80. {
  81. int dev;
  82. int ino;
  83. char *strp;
  84. FILE *fp;
  85. char buf[512];
  86. static char *path = 0;
  87. if (path == 0)
  88. path = ck_malloc (PATH_MAX);
  89. time (&this_time);
  90. if (gnu_dumpfile[0] != '/')
  91. {
  92. #if defined(__MSDOS__) || defined(HAVE_GETCWD) || defined(_POSIX_VERSION)
  93. if (!getcwd (path, PATH_MAX))
  94. {
  95. msg ("Couldn't get current directory.");
  96. exit (EX_SYSTEM);
  97. }
  98. #else
  99. char *getwd ();
  100. if (!getwd (path))
  101. {
  102. msg ("Couldn't get current directory: %s", path);
  103. exit (EX_SYSTEM);
  104. }
  105. #endif
  106. /* If this doesn't fit, we're in serious trouble */
  107. strcat (path, "/");
  108. strcat (path, gnu_dumpfile);
  109. gnu_dumpfile = path;
  110. }
  111. fp = fopen (gnu_dumpfile, "r");
  112. if (fp == 0 && errno != ENOENT)
  113. {
  114. msg_perror ("Can't open %s", gnu_dumpfile);
  115. return;
  116. }
  117. if (!fp)
  118. return;
  119. fgets (buf, sizeof (buf), fp);
  120. if (!f_new_files)
  121. {
  122. f_new_files++;
  123. new_time = atol (buf);
  124. }
  125. while (fgets (buf, sizeof (buf), fp))
  126. {
  127. strp = &buf[strlen (buf)];
  128. if (strp[-1] == '\n')
  129. strp[-1] = '\0';
  130. strp = buf;
  131. dev = atol (strp);
  132. while (isdigit (*strp))
  133. strp++;
  134. ino = atol (strp);
  135. while (isspace (*strp))
  136. strp++;
  137. while (isdigit (*strp))
  138. strp++;
  139. strp++;
  140. add_dir (un_quote_string (strp), dev, ino, (char *) 0);
  141. }
  142. fclose (fp);
  143. }
  144. void
  145. write_dir_file ()
  146. {
  147. FILE *fp;
  148. struct dirname *dp;
  149. char *str;
  150. extern char *quote_copy_string ();
  151. fp = fopen (gnu_dumpfile, "w");
  152. if (fp == 0)
  153. {
  154. msg_perror ("Can't write to %s", gnu_dumpfile);
  155. return;
  156. }
  157. fprintf (fp, "%lu\n", this_time);
  158. for (dp = dir_list; dp; dp = dp->next)
  159. {
  160. if (!dp->dir_text)
  161. continue;
  162. str = quote_copy_string (dp->name);
  163. if (str)
  164. {
  165. fprintf (fp, "%u %u %s\n", dp->dev, dp->ino, str);
  166. free (str);
  167. }
  168. else
  169. fprintf (fp, "%u %u %s\n", dp->dev, dp->ino, dp->name);
  170. }
  171. fclose (fp);
  172. }
  173. struct dirname *
  174. get_dir (name)
  175. char *name;
  176. {
  177. struct dirname *dp;
  178. for (dp = dir_list; dp; dp = dp->next)
  179. {
  180. if (!strcmp (dp->name, name))
  181. return dp;
  182. }
  183. return 0;
  184. }
  185. /* Collect all the names from argv[] (or whatever), then expand them into
  186. a directory tree, and put all the directories at the beginning. */
  187. void
  188. collect_and_sort_names ()
  189. {
  190. struct name *n, *n_next;
  191. int num_names;
  192. struct stat statbuf;
  193. int name_cmp ();
  194. char *merge_sort ();
  195. name_gather ();
  196. if (gnu_dumpfile)
  197. read_dir_file ();
  198. if (!namelist)
  199. addname (".");
  200. for (n = namelist; n; n = n_next)
  201. {
  202. n_next = n->next;
  203. if (n->found || n->dir_contents)
  204. continue;
  205. if (n->regexp) /* FIXME just skip regexps for now */
  206. continue;
  207. if (n->change_dir)
  208. if (chdir (n->change_dir) < 0)
  209. {
  210. msg_perror ("can't chdir to %s", n->change_dir);
  211. continue;
  212. }
  213. #ifdef AIX
  214. if (statx (n->name, &statbuf, STATSIZE, STX_HIDDEN | STX_LINK))
  215. #else
  216. if (lstat (n->name, &statbuf) < 0)
  217. #endif /* AIX */
  218. {
  219. msg_perror ("can't stat %s", n->name);
  220. continue;
  221. }
  222. if (S_ISDIR (statbuf.st_mode))
  223. {
  224. n->found++;
  225. add_dir_name (n->name, statbuf.st_dev);
  226. }
  227. }
  228. num_names = 0;
  229. for (n = namelist; n; n = n->next)
  230. num_names++;
  231. namelist = (struct name *) merge_sort ((PTR) namelist, num_names, (char *) (&(namelist->next)) - (char *) namelist, name_cmp);
  232. for (n = namelist; n; n = n->next)
  233. {
  234. n->found = 0;
  235. }
  236. if (gnu_dumpfile)
  237. write_dir_file ();
  238. }
  239. int
  240. name_cmp (n1, n2)
  241. struct name *n1, *n2;
  242. {
  243. if (n1->found)
  244. {
  245. if (n2->found)
  246. return strcmp (n1->name, n2->name);
  247. else
  248. return -1;
  249. }
  250. else if (n2->found)
  251. return 1;
  252. else
  253. return strcmp (n1->name, n2->name);
  254. }
  255. int
  256. dirent_cmp (p1, p2)
  257. const PTR p1;
  258. const PTR p2;
  259. {
  260. char *frst, *scnd;
  261. frst = (*(char **) p1) + 1;
  262. scnd = (*(char **) p2) + 1;
  263. return strcmp (frst, scnd);
  264. }
  265. char *
  266. get_dir_contents (p, device)
  267. char *p;
  268. int device;
  269. {
  270. DIR *dirp;
  271. register struct dirent *d;
  272. char *new_buf;
  273. char *namebuf;
  274. int bufsiz;
  275. int len;
  276. PTR the_buffer;
  277. char *buf;
  278. size_t n_strs;
  279. /* int n_size;*/
  280. char *p_buf;
  281. char **vec, **p_vec;
  282. extern int errno;
  283. errno = 0;
  284. dirp = opendir (p);
  285. bufsiz = strlen (p) + NAMSIZ;
  286. namebuf = ck_malloc (bufsiz + 2);
  287. if (!dirp)
  288. {
  289. if (errno)
  290. msg_perror ("can't open directory %s", p);
  291. else
  292. msg ("error opening directory %s", p);
  293. new_buf = NULL;
  294. }
  295. else
  296. {
  297. struct dirname *dp;
  298. int all_children;
  299. dp = get_dir (p);
  300. all_children = dp ? dp->allnew : 0;
  301. (void) strcpy (namebuf, p);
  302. if (p[strlen (p) - 1] != '/')
  303. (void) strcat (namebuf, "/");
  304. len = strlen (namebuf);
  305. the_buffer = init_buffer ();
  306. while (d = readdir (dirp))
  307. {
  308. struct stat hs;
  309. /* Skip . and .. */
  310. if (is_dot_or_dotdot (d->d_name))
  311. continue;
  312. if (NLENGTH (d) + len >= bufsiz)
  313. {
  314. bufsiz += NAMSIZ;
  315. namebuf = ck_realloc (namebuf, bufsiz + 2);
  316. }
  317. (void) strcpy (namebuf + len, d->d_name);
  318. #ifdef AIX
  319. if (0 != f_follow_links ?
  320. statx (namebuf, &hs, STATSIZE, STX_HIDDEN) :
  321. statx (namebuf, &hs, STATSIZE, STX_HIDDEN | STX_LINK))
  322. #else
  323. if (0 != f_follow_links ? stat (namebuf, &hs) : lstat (namebuf, &hs))
  324. #endif
  325. {
  326. msg_perror ("can't stat %s", namebuf);
  327. continue;
  328. }
  329. if ((f_local_filesys && device != hs.st_dev)
  330. || (f_exclude && check_exclude (namebuf)))
  331. add_buffer (the_buffer, "N", 1);
  332. #ifdef AIX
  333. else if (S_ISHIDDEN (hs.st_mode))
  334. {
  335. add_buffer (the_buffer, "D", 1);
  336. strcat (d->d_name, "A");
  337. d->d_namlen++;
  338. }
  339. #endif /* AIX */
  340. else if (S_ISDIR (hs.st_mode))
  341. {
  342. if (dp = get_dir (namebuf))
  343. {
  344. if (dp->dev != hs.st_dev
  345. || dp->ino != hs.st_ino)
  346. {
  347. if (f_verbose)
  348. msg ("directory %s has been renamed.", namebuf);
  349. dp->allnew = 1;
  350. dp->dev = hs.st_dev;
  351. dp->ino = hs.st_ino;
  352. }
  353. dp->dir_text = "";
  354. }
  355. else
  356. {
  357. if (f_verbose)
  358. msg ("Directory %s is new", namebuf);
  359. add_dir (namebuf, hs.st_dev, hs.st_ino, "");
  360. dp = get_dir (namebuf);
  361. dp->allnew = 1;
  362. }
  363. if (all_children)
  364. dp->allnew = 1;
  365. add_buffer (the_buffer, "D", 1);
  366. }
  367. else if (!all_children
  368. && f_new_files
  369. && new_time > hs.st_mtime
  370. && (f_new_files > 1
  371. || new_time > hs.st_ctime))
  372. add_buffer (the_buffer, "N", 1);
  373. else
  374. add_buffer (the_buffer, "Y", 1);
  375. add_buffer (the_buffer, d->d_name, (int) (NLENGTH (d) + 1));
  376. }
  377. add_buffer (the_buffer, "\000\000", 2);
  378. closedir (dirp);
  379. /* Well, we've read in the contents of the dir, now sort them */
  380. buf = get_buffer (the_buffer);
  381. if (buf[0] == '\0')
  382. {
  383. flush_buffer (the_buffer);
  384. new_buf = NULL;
  385. }
  386. else
  387. {
  388. n_strs = 0;
  389. for (p_buf = buf; *p_buf;)
  390. {
  391. int tmp;
  392. tmp = strlen (p_buf) + 1;
  393. n_strs++;
  394. p_buf += tmp;
  395. }
  396. vec = (char **) ck_malloc (sizeof (char *) * (n_strs + 1));
  397. for (p_vec = vec, p_buf = buf; *p_buf; p_buf += strlen (p_buf) + 1)
  398. *p_vec++ = p_buf;
  399. *p_vec = 0;
  400. qsort ((PTR) vec, n_strs, sizeof (char *), dirent_cmp);
  401. new_buf = (char *) ck_malloc (p_buf - buf + 2);
  402. for (p_vec = vec, p_buf = new_buf; *p_vec; p_vec++)
  403. {
  404. char *p_tmp;
  405. for (p_tmp = *p_vec; *p_buf++ = *p_tmp++;)
  406. ;
  407. }
  408. *p_buf++ = '\0';
  409. free (vec);
  410. flush_buffer (the_buffer);
  411. }
  412. }
  413. free (namebuf);
  414. return new_buf;
  415. }
  416. /* p is a directory. Add all the files in P to the namelist. If any of the
  417. files is a directory, recurse on the subdirectory. . . */
  418. static void
  419. add_dir_name (p, device)
  420. char *p;
  421. int device;
  422. {
  423. char *new_buf;
  424. char *p_buf;
  425. char *namebuf;
  426. int buflen;
  427. register int len;
  428. int sublen;
  429. /* PTR the_buffer;*/
  430. /* char *buf;*/
  431. /* char **vec,**p_vec;*/
  432. /* int n_strs,n_size;*/
  433. struct name *n;
  434. int dirent_cmp ();
  435. new_buf = get_dir_contents (p, device);
  436. for (n = namelist; n; n = n->next)
  437. {
  438. if (!strcmp (n->name, p))
  439. {
  440. n->dir_contents = new_buf ? new_buf : "\0\0\0\0";
  441. break;
  442. }
  443. }
  444. if (new_buf)
  445. {
  446. len = strlen (p);
  447. buflen = NAMSIZ <= len ? len + NAMSIZ : NAMSIZ;
  448. namebuf = ck_malloc (buflen + 1);
  449. (void) strcpy (namebuf, p);
  450. if (namebuf[len - 1] != '/')
  451. {
  452. namebuf[len++] = '/';
  453. namebuf[len] = '\0';
  454. }
  455. for (p_buf = new_buf; *p_buf; p_buf += sublen + 1)
  456. {
  457. sublen = strlen (p_buf);
  458. if (*p_buf == 'D')
  459. {
  460. if (len + sublen >= buflen)
  461. {
  462. buflen += NAMSIZ;
  463. namebuf = ck_realloc (namebuf, buflen + 1);
  464. }
  465. (void) strcpy (namebuf + len, p_buf + 1);
  466. addname (namebuf);
  467. add_dir_name (namebuf, device);
  468. }
  469. }
  470. free (namebuf);
  471. }
  472. }
  473. /* Returns non-zero if p is . or .. This could be a macro for speed. */
  474. int
  475. is_dot_or_dotdot (p)
  476. char *p;
  477. {
  478. return (p[0] == '.' && (p[1] == '\0' || (p[1] == '.' && p[2] == '\0')));
  479. }
  480. void
  481. gnu_restore (skipcrud)
  482. int skipcrud;
  483. {
  484. char *current_dir;
  485. /* int current_dir_length; */
  486. char *archive_dir;
  487. /* int archive_dir_length; */
  488. PTR the_buffer;
  489. char *p;
  490. DIR *dirp;
  491. struct dirent *d;
  492. char *cur, *arc;
  493. extern struct stat hstat; /* Stat struct corresponding */
  494. long size, copied;
  495. char *from, *to;
  496. extern union record *head;
  497. dirp = opendir (skipcrud + current_file_name);
  498. if (!dirp)
  499. {
  500. /* The directory doesn't exist now. It'll be created.
  501. In any case, we don't have to delete any files out
  502. of it */
  503. skip_file ((long) hstat.st_size);
  504. return;
  505. }
  506. the_buffer = init_buffer ();
  507. while (d = readdir (dirp))
  508. {
  509. if (is_dot_or_dotdot (d->d_name))
  510. continue;
  511. add_buffer (the_buffer, d->d_name, (int) (NLENGTH (d) + 1));
  512. }
  513. closedir (dirp);
  514. add_buffer (the_buffer, "", 1);
  515. current_dir = get_buffer (the_buffer);
  516. archive_dir = (char *) ck_malloc (hstat.st_size);
  517. if (archive_dir == 0)
  518. {
  519. msg ("Can't allocate %d bytes for restore", hstat.st_size);
  520. skip_file ((long) hstat.st_size);
  521. return;
  522. }
  523. to = archive_dir;
  524. for (size = hstat.st_size; size > 0; size -= copied)
  525. {
  526. from = findrec ()->charptr;
  527. if (!from)
  528. {
  529. msg ("Unexpected EOF in archive\n");
  530. break;
  531. }
  532. copied = endofrecs ()->charptr - from;
  533. if (copied > size)
  534. copied = size;
  535. bcopy ((PTR) from, (PTR) to, (int) copied);
  536. to += copied;
  537. userec ((union record *) (from + copied - 1));
  538. }
  539. for (cur = current_dir; *cur; cur += strlen (cur) + 1)
  540. {
  541. for (arc = archive_dir; *arc; arc += strlen (arc) + 1)
  542. {
  543. arc++;
  544. if (!strcmp (arc, cur))
  545. break;
  546. }
  547. if (*arc == '\0')
  548. {
  549. p = new_name (skipcrud + current_file_name, cur);
  550. if (f_confirm && !confirm ("delete", p))
  551. {
  552. free (p);
  553. continue;
  554. }
  555. if (f_verbose)
  556. fprintf (msg_file, "%s: deleting %s\n", tar, p);
  557. if (recursively_delete (p))
  558. {
  559. msg ("%s: Error while deleting %s\n", tar, p);
  560. }
  561. free (p);
  562. }
  563. }
  564. flush_buffer (the_buffer);
  565. free (archive_dir);
  566. }
  567. int
  568. recursively_delete (path)
  569. char *path;
  570. {
  571. struct stat sbuf;
  572. DIR *dirp;
  573. struct dirent *dp;
  574. char *path_buf;
  575. /* int path_len; */
  576. if (lstat (path, &sbuf) < 0)
  577. return 1;
  578. if (S_ISDIR (sbuf.st_mode))
  579. {
  580. /* path_len=strlen(path); */
  581. dirp = opendir (path);
  582. if (dirp == 0)
  583. return 1;
  584. while (dp = readdir (dirp))
  585. {
  586. if (is_dot_or_dotdot (dp->d_name))
  587. continue;
  588. path_buf = new_name (path, dp->d_name);
  589. if (recursively_delete (path_buf))
  590. {
  591. free (path_buf);
  592. closedir (dirp);
  593. return 1;
  594. }
  595. free (path_buf);
  596. }
  597. closedir (dirp);
  598. if (rmdir (path) < 0)
  599. return 1;
  600. return 0;
  601. }
  602. if (unlink (path) < 0)
  603. return 1;
  604. return 0;
  605. }