extract.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875
  1. /*
  2. ** Copyright 1998-2003 University of Illinois Board of Trustees
  3. ** Copyright 1998-2003 Mark D. Roth
  4. ** All rights reserved.
  5. **
  6. ** extract.c - libtar code to extract a file from a tar archive
  7. **
  8. ** Mark D. Roth <[email protected]>
  9. ** Campus Information Technologies and Educational Services
  10. ** University of Illinois at Urbana-Champaign
  11. */
  12. #include <libtarint/internal.h>
  13. #include <stdio.h>
  14. #include <libtar/compat.h>
  15. #include <sys/types.h>
  16. #include <fcntl.h>
  17. #include <errno.h>
  18. #if defined(_WIN32) && !defined(__CYGWIN__)
  19. # ifdef _MSC_VER
  20. # include <sys/utime.h>
  21. # else
  22. # include <utime.h>
  23. # endif
  24. # include <io.h>
  25. # include <direct.h>
  26. #else
  27. # include <utime.h>
  28. # include <sys/param.h>
  29. #endif
  30. #ifdef STDC_HEADERS
  31. # include <stdlib.h>
  32. # include <string.h>
  33. #endif
  34. #ifdef HAVE_UNISTD_H
  35. # include <unistd.h>
  36. #endif
  37. #ifdef HAVE_SYS_MKDEV_H
  38. # include <sys/mkdev.h>
  39. #endif
  40. struct linkname
  41. {
  42. char ln_save[TAR_MAXPATHLEN];
  43. char ln_real[TAR_MAXPATHLEN];
  44. };
  45. typedef struct linkname linkname_t;
  46. static int
  47. tar_set_file_perms(TAR *t, char *realname)
  48. {
  49. mode_t mode;
  50. uid_t uid;
  51. gid_t gid;
  52. struct utimbuf ut;
  53. char *filename;
  54. char *pathname = 0;
  55. if (realname)
  56. {
  57. filename = realname;
  58. }
  59. else
  60. {
  61. pathname = th_get_pathname(t);
  62. filename = pathname;
  63. }
  64. mode = th_get_mode(t);
  65. uid = th_get_uid(t);
  66. gid = th_get_gid(t);
  67. ut.modtime = ut.actime = th_get_mtime(t);
  68. /* change owner/group */
  69. #ifndef WIN32
  70. if (geteuid() == 0)
  71. #ifdef HAVE_LCHOWN
  72. if (lchown(filename, uid, gid) == -1)
  73. {
  74. # ifdef DEBUG
  75. fprintf(stderr, "lchown(\"%s\", %d, %d): %s\n",
  76. filename, uid, gid, strerror(errno));
  77. # endif
  78. #else /* ! HAVE_LCHOWN */
  79. if (!TH_ISSYM(t) && chown(filename, uid, gid) == -1)
  80. {
  81. # ifdef DEBUG
  82. fprintf(stderr, "chown(\"%s\", %d, %d): %s\n",
  83. filename, uid, gid, strerror(errno));
  84. # endif
  85. #endif /* HAVE_LCHOWN */
  86. if (pathname)
  87. {
  88. free(pathname);
  89. }
  90. return -1;
  91. }
  92. /* change access/modification time */
  93. if (!TH_ISSYM(t) && utime(filename, &ut) == -1)
  94. {
  95. #ifdef DEBUG
  96. perror("utime()");
  97. #endif
  98. if (pathname)
  99. {
  100. free(pathname);
  101. }
  102. return -1;
  103. }
  104. /* change permissions */
  105. if (!TH_ISSYM(t) && chmod(filename, mode) == -1)
  106. {
  107. #ifdef DEBUG
  108. perror("chmod()");
  109. #endif
  110. if (pathname)
  111. {
  112. free(pathname);
  113. }
  114. return -1;
  115. }
  116. #else /* WIN32 */
  117. (void)filename;
  118. (void)gid;
  119. (void)uid;
  120. (void)mode;
  121. #endif /* WIN32 */
  122. if (pathname)
  123. {
  124. free(pathname);
  125. }
  126. return 0;
  127. }
  128. /* switchboard */
  129. int
  130. tar_extract_file(TAR *t, char *realname)
  131. {
  132. int i;
  133. linkname_t *lnp;
  134. char *pathname;
  135. if (t->options & TAR_NOOVERWRITE)
  136. {
  137. struct stat s;
  138. #ifdef WIN32
  139. if (stat(realname, &s) == 0 || errno != ENOENT)
  140. #else
  141. if (lstat(realname, &s) == 0 || errno != ENOENT)
  142. #endif
  143. {
  144. errno = EEXIST;
  145. return -1;
  146. }
  147. }
  148. if (TH_ISDIR(t))
  149. {
  150. i = tar_extract_dir(t, realname);
  151. if (i == 1)
  152. i = 0;
  153. }
  154. #ifndef _WIN32
  155. else if (TH_ISLNK(t))
  156. i = tar_extract_hardlink(t, realname);
  157. else if (TH_ISSYM(t))
  158. i = tar_extract_symlink(t, realname);
  159. else if (TH_ISCHR(t))
  160. i = tar_extract_chardev(t, realname);
  161. else if (TH_ISBLK(t))
  162. i = tar_extract_blockdev(t, realname);
  163. else if (TH_ISFIFO(t))
  164. i = tar_extract_fifo(t, realname);
  165. #endif
  166. else /* if (TH_ISREG(t)) */
  167. i = tar_extract_regfile(t, realname);
  168. if (i != 0)
  169. return i;
  170. i = tar_set_file_perms(t, realname);
  171. if (i != 0)
  172. return i;
  173. lnp = (linkname_t *)calloc(1, sizeof(linkname_t));
  174. if (lnp == NULL)
  175. return -1;
  176. pathname = th_get_pathname(t);
  177. strlcpy(lnp->ln_save, pathname, sizeof(lnp->ln_save));
  178. strlcpy(lnp->ln_real, realname, sizeof(lnp->ln_real));
  179. #ifdef DEBUG
  180. printf("tar_extract_file(): calling libtar_hash_add(): key=\"%s\", "
  181. "value=\"%s\"\n", pathname, realname);
  182. #endif
  183. if (pathname)
  184. {
  185. free(pathname);
  186. }
  187. if (libtar_hash_add(t->h, lnp) != 0)
  188. return -1;
  189. return 0;
  190. }
  191. /* extract regular file */
  192. int
  193. tar_extract_regfile(TAR *t, char *realname)
  194. {
  195. mode_t mode;
  196. size_t size;
  197. uid_t uid;
  198. gid_t gid;
  199. int fdout;
  200. int i, k;
  201. char buf[T_BLOCKSIZE];
  202. char *filename;
  203. char *pathname = 0;
  204. #ifdef DEBUG
  205. printf("==> tar_extract_regfile(t=0x%lx, realname=\"%s\")\n", t,
  206. realname);
  207. #endif
  208. if (!TH_ISREG(t))
  209. {
  210. errno = EINVAL;
  211. return -1;
  212. }
  213. if (realname)
  214. {
  215. filename = realname;
  216. }
  217. else
  218. {
  219. pathname = th_get_pathname(t);
  220. filename = pathname;
  221. }
  222. mode = th_get_mode(t);
  223. size = th_get_size(t);
  224. uid = th_get_uid(t);
  225. gid = th_get_gid(t);
  226. /* Make a copy of the string because dirname and mkdirhier may modify the
  227. * string */
  228. strncpy(buf, filename, sizeof(buf)-1);
  229. buf[sizeof(buf)-1] = 0;
  230. if (mkdirhier(dirname(buf)) == -1)
  231. {
  232. if (pathname)
  233. {
  234. free(pathname);
  235. }
  236. return -1;
  237. }
  238. #ifdef DEBUG
  239. printf(" ==> extracting: %s (mode %04o, uid %d, gid %d, %d bytes)\n",
  240. filename, mode, uid, gid, size);
  241. #endif
  242. fdout = open(filename, O_WRONLY | O_CREAT | O_TRUNC
  243. #ifdef O_BINARY
  244. | O_BINARY
  245. #endif
  246. , 0666);
  247. if (fdout == -1)
  248. {
  249. #ifdef DEBUG
  250. perror("open()");
  251. #endif
  252. if (pathname)
  253. {
  254. free(pathname);
  255. }
  256. return -1;
  257. }
  258. #if 0
  259. /* change the owner. (will only work if run as root) */
  260. if (fchown(fdout, uid, gid) == -1 && errno != EPERM)
  261. {
  262. #ifdef DEBUG
  263. perror("fchown()");
  264. #endif
  265. if (pathname)
  266. {
  267. free(pathname);
  268. }
  269. return -1;
  270. }
  271. /* make sure the mode isn't inheritted from a file we're overwriting */
  272. if (fchmod(fdout, mode & 07777) == -1)
  273. {
  274. #ifdef DEBUG
  275. perror("fchmod()");
  276. #endif
  277. if (pathname)
  278. {
  279. free(pathname);
  280. }
  281. return -1;
  282. }
  283. #endif
  284. /* extract the file */
  285. for (i = size; i > 0; i -= T_BLOCKSIZE)
  286. {
  287. k = tar_block_read(t, buf);
  288. if (k != T_BLOCKSIZE)
  289. {
  290. if (k != -1)
  291. errno = EINVAL;
  292. if (pathname)
  293. {
  294. free(pathname);
  295. }
  296. return -1;
  297. }
  298. /* write block to output file */
  299. if (write(fdout, buf,
  300. ((i > T_BLOCKSIZE) ? T_BLOCKSIZE : i)) == -1)
  301. {
  302. if (pathname)
  303. {
  304. free(pathname);
  305. }
  306. return -1;
  307. }
  308. }
  309. /* close output file */
  310. if (close(fdout) == -1)
  311. {
  312. if (pathname)
  313. {
  314. free(pathname);
  315. }
  316. return -1;
  317. }
  318. #ifdef DEBUG
  319. printf("### done extracting %s\n", filename);
  320. #endif
  321. (void)filename;
  322. (void)gid;
  323. (void)uid;
  324. (void)mode;
  325. if (pathname)
  326. {
  327. free(pathname);
  328. }
  329. return 0;
  330. }
  331. /* skip regfile */
  332. int
  333. tar_skip_regfile(TAR *t)
  334. {
  335. int i, k;
  336. size_t size;
  337. char buf[T_BLOCKSIZE];
  338. if (!TH_ISREG(t))
  339. {
  340. errno = EINVAL;
  341. return -1;
  342. }
  343. size = th_get_size(t);
  344. for (i = size; i > 0; i -= T_BLOCKSIZE)
  345. {
  346. k = tar_block_read(t, buf);
  347. if (k != T_BLOCKSIZE)
  348. {
  349. if (k != -1)
  350. errno = EINVAL;
  351. return -1;
  352. }
  353. }
  354. return 0;
  355. }
  356. /* hardlink */
  357. int
  358. tar_extract_hardlink(TAR * t, char *realname)
  359. {
  360. char *filename;
  361. char *linktgt;
  362. linkname_t *lnp;
  363. libtar_hashptr_t hp;
  364. char buf[T_BLOCKSIZE];
  365. char *pathname = 0;
  366. if (!TH_ISLNK(t))
  367. {
  368. errno = EINVAL;
  369. return -1;
  370. }
  371. if (realname)
  372. {
  373. filename = realname;
  374. }
  375. else
  376. {
  377. pathname = th_get_pathname(t);
  378. filename = pathname;
  379. }
  380. /* Make a copy of the string because dirname and mkdirhier may modify the
  381. * string */
  382. strncpy(buf, filename, sizeof(buf)-1);
  383. buf[sizeof(buf)-1] = 0;
  384. if (mkdirhier(dirname(buf)) == -1)
  385. {
  386. if (pathname)
  387. {
  388. free(pathname);
  389. }
  390. return -1;
  391. }
  392. libtar_hashptr_reset(&hp);
  393. if (libtar_hash_getkey(t->h, &hp, th_get_linkname(t),
  394. (libtar_matchfunc_t)libtar_str_match) != 0)
  395. {
  396. lnp = (linkname_t *)libtar_hashptr_data(&hp);
  397. linktgt = lnp->ln_real;
  398. }
  399. else
  400. linktgt = th_get_linkname(t);
  401. #ifdef DEBUG
  402. printf(" ==> extracting: %s (link to %s)\n", filename, linktgt);
  403. #endif
  404. #ifndef WIN32
  405. if (link(linktgt, filename) == -1)
  406. #else
  407. (void)linktgt;
  408. #endif
  409. {
  410. #ifdef DEBUG
  411. perror("link()");
  412. #endif
  413. if (pathname)
  414. {
  415. free(pathname);
  416. }
  417. return -1;
  418. }
  419. if (pathname)
  420. {
  421. free(pathname);
  422. }
  423. return 0;
  424. }
  425. /* symlink */
  426. int
  427. tar_extract_symlink(TAR *t, char *realname)
  428. {
  429. char *filename;
  430. char buf[T_BLOCKSIZE];
  431. char *pathname = 0;
  432. #ifndef _WIN32
  433. if (!TH_ISSYM(t))
  434. {
  435. errno = EINVAL;
  436. return -1;
  437. }
  438. #endif
  439. if (realname)
  440. {
  441. filename = realname;
  442. }
  443. else
  444. {
  445. pathname = th_get_pathname(t);
  446. filename = pathname;
  447. }
  448. /* Make a copy of the string because dirname and mkdirhier may modify the
  449. * string */
  450. strncpy(buf, filename, sizeof(buf)-1);
  451. buf[sizeof(buf)-1] = 0;
  452. if (mkdirhier(dirname(buf)) == -1)
  453. {
  454. if (pathname)
  455. {
  456. free(pathname);
  457. }
  458. return -1;
  459. }
  460. if (unlink(filename) == -1 && errno != ENOENT)
  461. {
  462. if (pathname)
  463. {
  464. free(pathname);
  465. }
  466. return -1;
  467. }
  468. #ifdef DEBUG
  469. printf(" ==> extracting: %s (symlink to %s)\n",
  470. filename, th_get_linkname(t));
  471. #endif
  472. #ifndef WIN32
  473. if (symlink(th_get_linkname(t), filename) == -1)
  474. #endif
  475. {
  476. #ifdef DEBUG
  477. perror("symlink()");
  478. #endif
  479. if (pathname)
  480. {
  481. free(pathname);
  482. }
  483. return -1;
  484. }
  485. if (pathname)
  486. {
  487. free(pathname);
  488. }
  489. return 0;
  490. }
  491. /* character device */
  492. int
  493. tar_extract_chardev(TAR *t, char *realname)
  494. {
  495. mode_t mode;
  496. unsigned long devmaj, devmin;
  497. char *filename;
  498. char buf[T_BLOCKSIZE];
  499. char *pathname = 0;
  500. #ifndef _WIN32
  501. if (!TH_ISCHR(t))
  502. {
  503. errno = EINVAL;
  504. return -1;
  505. }
  506. #endif
  507. if (realname)
  508. {
  509. filename = realname;
  510. }
  511. else
  512. {
  513. pathname = th_get_pathname(t);
  514. filename = pathname;
  515. }
  516. mode = th_get_mode(t);
  517. devmaj = th_get_devmajor(t);
  518. devmin = th_get_devminor(t);
  519. /* Make a copy of the string because dirname and mkdirhier may modify the
  520. * string */
  521. strncpy(buf, filename, sizeof(buf)-1);
  522. buf[sizeof(buf)-1] = 0;
  523. if (mkdirhier(dirname(buf)) == -1)
  524. {
  525. if (pathname)
  526. {
  527. free(pathname);
  528. }
  529. return -1;
  530. }
  531. #ifdef DEBUG
  532. printf(" ==> extracting: %s (character device %ld,%ld)\n",
  533. filename, devmaj, devmin);
  534. #endif
  535. #ifndef WIN32
  536. if (mknod(filename, mode | S_IFCHR,
  537. compat_makedev(devmaj, devmin)) == -1)
  538. #else
  539. (void)devmin;
  540. (void)devmaj;
  541. (void)mode;
  542. #endif
  543. {
  544. #ifdef DEBUG
  545. perror("mknod()");
  546. #endif
  547. if (pathname)
  548. {
  549. free(pathname);
  550. }
  551. return -1;
  552. }
  553. if (pathname)
  554. {
  555. free(pathname);
  556. }
  557. return 0;
  558. }
  559. /* block device */
  560. int
  561. tar_extract_blockdev(TAR *t, char *realname)
  562. {
  563. mode_t mode;
  564. unsigned long devmaj, devmin;
  565. char *filename;
  566. char buf[T_BLOCKSIZE];
  567. char *pathname = 0;
  568. if (!TH_ISBLK(t))
  569. {
  570. errno = EINVAL;
  571. return -1;
  572. }
  573. if (realname)
  574. {
  575. filename = realname;
  576. }
  577. else
  578. {
  579. pathname = th_get_pathname(t);
  580. filename = pathname;
  581. }
  582. mode = th_get_mode(t);
  583. devmaj = th_get_devmajor(t);
  584. devmin = th_get_devminor(t);
  585. /* Make a copy of the string because dirname and mkdirhier may modify the
  586. * string */
  587. strncpy(buf, filename, sizeof(buf)-1);
  588. buf[sizeof(buf)-1] = 0;
  589. if (mkdirhier(dirname(buf)) == -1)
  590. {
  591. if (pathname)
  592. {
  593. free(pathname);
  594. }
  595. return -1;
  596. }
  597. #ifdef DEBUG
  598. printf(" ==> extracting: %s (block device %ld,%ld)\n",
  599. filename, devmaj, devmin);
  600. #endif
  601. #ifndef WIN32
  602. if (mknod(filename, mode | S_IFBLK,
  603. compat_makedev(devmaj, devmin)) == -1)
  604. #else
  605. (void)devmin;
  606. (void)devmaj;
  607. (void)mode;
  608. #endif
  609. {
  610. #ifdef DEBUG
  611. perror("mknod()");
  612. #endif
  613. if (pathname)
  614. {
  615. free(pathname);
  616. }
  617. return -1;
  618. }
  619. if (pathname)
  620. {
  621. free(pathname);
  622. }
  623. return 0;
  624. }
  625. /* directory */
  626. int
  627. tar_extract_dir(TAR *t, char *realname)
  628. {
  629. mode_t mode;
  630. char *filename;
  631. char buf[T_BLOCKSIZE];
  632. char *pathname = 0;
  633. if (!TH_ISDIR(t))
  634. {
  635. errno = EINVAL;
  636. return -1;
  637. }
  638. if (realname)
  639. {
  640. filename = realname;
  641. }
  642. else
  643. {
  644. pathname = th_get_pathname(t);
  645. filename = pathname;
  646. }
  647. mode = th_get_mode(t);
  648. /* Make a copy of the string because dirname and mkdirhier may modify the
  649. * string */
  650. strncpy(buf, filename, sizeof(buf)-1);
  651. buf[sizeof(buf)-1] = 0;
  652. if (mkdirhier(dirname(buf)) == -1)
  653. {
  654. if (pathname)
  655. {
  656. free(pathname);
  657. }
  658. return -1;
  659. }
  660. #ifdef DEBUG
  661. printf(" ==> extracting: %s (mode %04o, directory)\n", filename,
  662. mode);
  663. #endif
  664. #ifdef WIN32
  665. if (mkdir(filename) == -1)
  666. #else
  667. if (mkdir(filename, mode) == -1)
  668. #endif
  669. {
  670. #ifdef __BORLANDC__
  671. /* There is a bug in the Borland Run time library which makes MKDIR
  672. return EACCES when it should return EEXIST
  673. if it is some other error besides directory exists
  674. then return false */
  675. if ( errno == EACCES)
  676. {
  677. errno = EEXIST;
  678. }
  679. #endif
  680. if (errno == EEXIST)
  681. {
  682. if (chmod(filename, mode) == -1)
  683. {
  684. #ifdef DEBUG
  685. perror("chmod()");
  686. #endif
  687. if (pathname)
  688. {
  689. free(pathname);
  690. }
  691. return -1;
  692. }
  693. else
  694. {
  695. #ifdef DEBUG
  696. puts(" *** using existing directory");
  697. #endif
  698. if (pathname)
  699. {
  700. free(pathname);
  701. }
  702. return 1;
  703. }
  704. }
  705. else
  706. {
  707. #ifdef DEBUG
  708. perror("mkdir()");
  709. #endif
  710. if (pathname)
  711. {
  712. free(pathname);
  713. }
  714. return -1;
  715. }
  716. }
  717. if (pathname)
  718. {
  719. free(pathname);
  720. }
  721. return 0;
  722. }
  723. /* FIFO */
  724. int
  725. tar_extract_fifo(TAR *t, char *realname)
  726. {
  727. mode_t mode;
  728. char *filename;
  729. char buf[T_BLOCKSIZE];
  730. char *pathname = 0;
  731. if (!TH_ISFIFO(t))
  732. {
  733. errno = EINVAL;
  734. return -1;
  735. }
  736. if (realname)
  737. {
  738. filename = realname;
  739. }
  740. else
  741. {
  742. pathname = th_get_pathname(t);
  743. filename = pathname;
  744. }
  745. mode = th_get_mode(t);
  746. /* Make a copy of the string because dirname and mkdirhier may modify the
  747. * string */
  748. strncpy(buf, filename, sizeof(buf)-1);
  749. buf[sizeof(buf)-1] = 0;
  750. if (mkdirhier(dirname(buf)) == -1)
  751. {
  752. if (pathname)
  753. {
  754. free(pathname);
  755. }
  756. return -1;
  757. }
  758. #ifdef DEBUG
  759. printf(" ==> extracting: %s (fifo)\n", filename);
  760. #endif
  761. #ifndef WIN32
  762. if (mkfifo(filename, mode) == -1)
  763. #else
  764. (void)mode;
  765. #endif
  766. {
  767. #ifdef DEBUG
  768. perror("mkfifo()");
  769. #endif
  770. if (pathname)
  771. {
  772. free(pathname);
  773. }
  774. return -1;
  775. }
  776. if (pathname)
  777. {
  778. free(pathname);
  779. }
  780. return 0;
  781. }