extract.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895
  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 & 07777) == -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. ssize_t 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 : (unsigned int)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. ssize_t 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. #ifndef WIN32
  420. if (pathname)
  421. {
  422. free(pathname);
  423. }
  424. return 0;
  425. #endif
  426. }
  427. /* symlink */
  428. int
  429. tar_extract_symlink(TAR *t, char *realname)
  430. {
  431. char *filename;
  432. char buf[T_BLOCKSIZE];
  433. char *pathname = 0;
  434. #ifndef _WIN32
  435. if (!TH_ISSYM(t))
  436. {
  437. errno = EINVAL;
  438. return -1;
  439. }
  440. #endif
  441. if (realname)
  442. {
  443. filename = realname;
  444. }
  445. else
  446. {
  447. pathname = th_get_pathname(t);
  448. filename = pathname;
  449. }
  450. /* Make a copy of the string because dirname and mkdirhier may modify the
  451. * string */
  452. strncpy(buf, filename, sizeof(buf)-1);
  453. buf[sizeof(buf)-1] = 0;
  454. if (mkdirhier(dirname(buf)) == -1)
  455. {
  456. if (pathname)
  457. {
  458. free(pathname);
  459. }
  460. return -1;
  461. }
  462. if (unlink(filename) == -1 && errno != ENOENT)
  463. {
  464. if (pathname)
  465. {
  466. free(pathname);
  467. }
  468. return -1;
  469. }
  470. #ifdef DEBUG
  471. printf(" ==> extracting: %s (symlink to %s)\n",
  472. filename, th_get_linkname(t));
  473. #endif
  474. #ifndef WIN32
  475. if (symlink(th_get_linkname(t), filename) == -1)
  476. #endif
  477. {
  478. #ifdef DEBUG
  479. perror("symlink()");
  480. #endif
  481. if (pathname)
  482. {
  483. free(pathname);
  484. }
  485. return -1;
  486. }
  487. #ifndef WIN32
  488. if (pathname)
  489. {
  490. free(pathname);
  491. }
  492. return 0;
  493. #endif
  494. }
  495. /* character device */
  496. int
  497. tar_extract_chardev(TAR *t, char *realname)
  498. {
  499. mode_t mode;
  500. unsigned long devmaj, devmin;
  501. char *filename;
  502. char buf[T_BLOCKSIZE];
  503. char *pathname = 0;
  504. #ifndef _WIN32
  505. if (!TH_ISCHR(t))
  506. {
  507. errno = EINVAL;
  508. return -1;
  509. }
  510. #endif
  511. if (realname)
  512. {
  513. filename = realname;
  514. }
  515. else
  516. {
  517. pathname = th_get_pathname(t);
  518. filename = pathname;
  519. }
  520. mode = th_get_mode(t);
  521. devmaj = th_get_devmajor(t);
  522. devmin = th_get_devminor(t);
  523. /* Make a copy of the string because dirname and mkdirhier may modify the
  524. * string */
  525. strncpy(buf, filename, sizeof(buf)-1);
  526. buf[sizeof(buf)-1] = 0;
  527. if (mkdirhier(dirname(buf)) == -1)
  528. {
  529. if (pathname)
  530. {
  531. free(pathname);
  532. }
  533. return -1;
  534. }
  535. #ifdef DEBUG
  536. printf(" ==> extracting: %s (character device %ld,%ld)\n",
  537. filename, devmaj, devmin);
  538. #endif
  539. #ifndef WIN32
  540. if (mknod(filename, mode | S_IFCHR,
  541. compat_makedev(devmaj, devmin)) == -1)
  542. #else
  543. (void)devmin;
  544. (void)devmaj;
  545. (void)mode;
  546. #endif
  547. {
  548. #ifdef DEBUG
  549. perror("mknod()");
  550. #endif
  551. if (pathname)
  552. {
  553. free(pathname);
  554. }
  555. return -1;
  556. }
  557. #ifndef WIN32
  558. if (pathname)
  559. {
  560. free(pathname);
  561. }
  562. return 0;
  563. #endif
  564. }
  565. /* block device */
  566. int
  567. tar_extract_blockdev(TAR *t, char *realname)
  568. {
  569. mode_t mode;
  570. unsigned long devmaj, devmin;
  571. char *filename;
  572. char buf[T_BLOCKSIZE];
  573. char *pathname = 0;
  574. if (!TH_ISBLK(t))
  575. {
  576. errno = EINVAL;
  577. return -1;
  578. }
  579. if (realname)
  580. {
  581. filename = realname;
  582. }
  583. else
  584. {
  585. pathname = th_get_pathname(t);
  586. filename = pathname;
  587. }
  588. mode = th_get_mode(t);
  589. devmaj = th_get_devmajor(t);
  590. devmin = th_get_devminor(t);
  591. /* Make a copy of the string because dirname and mkdirhier may modify the
  592. * string */
  593. strncpy(buf, filename, sizeof(buf)-1);
  594. buf[sizeof(buf)-1] = 0;
  595. if (mkdirhier(dirname(buf)) == -1)
  596. {
  597. if (pathname)
  598. {
  599. free(pathname);
  600. }
  601. return -1;
  602. }
  603. #ifdef DEBUG
  604. printf(" ==> extracting: %s (block device %ld,%ld)\n",
  605. filename, devmaj, devmin);
  606. #endif
  607. #ifndef WIN32
  608. if (mknod(filename, mode | S_IFBLK,
  609. compat_makedev(devmaj, devmin)) == -1)
  610. #else
  611. (void)devmin;
  612. (void)devmaj;
  613. (void)mode;
  614. #endif
  615. {
  616. #ifdef DEBUG
  617. perror("mknod()");
  618. #endif
  619. if (pathname)
  620. {
  621. free(pathname);
  622. }
  623. return -1;
  624. }
  625. #ifndef WIN32
  626. if (pathname)
  627. {
  628. free(pathname);
  629. }
  630. return 0;
  631. #endif
  632. }
  633. /* directory */
  634. int
  635. tar_extract_dir(TAR *t, char *realname)
  636. {
  637. mode_t mode;
  638. char *filename;
  639. char buf[T_BLOCKSIZE];
  640. char *pathname = 0;
  641. size_t len = 0;
  642. if (!TH_ISDIR(t))
  643. {
  644. errno = EINVAL;
  645. return -1;
  646. }
  647. if (realname)
  648. {
  649. filename = realname;
  650. }
  651. else
  652. {
  653. pathname = th_get_pathname(t);
  654. filename = pathname;
  655. }
  656. mode = th_get_mode(t);
  657. /* Make a copy of the string because dirname and mkdirhier may modify the
  658. * string */
  659. strncpy(buf, filename, sizeof(buf)-1);
  660. buf[sizeof(buf)-1] = 0;
  661. if (mkdirhier(dirname(buf)) == -1)
  662. {
  663. if (pathname)
  664. {
  665. free(pathname);
  666. }
  667. return -1;
  668. }
  669. /* Strip trailing '/'...it confuses some Unixes (and BeOS)... */
  670. strncpy(buf, filename, sizeof(buf)-1);
  671. buf[sizeof(buf)-1] = 0;
  672. len = strlen(buf);
  673. if ((len > 0) && (buf[len-1] == '/'))
  674. {
  675. buf[len-1] = '\0';
  676. }
  677. #ifdef DEBUG
  678. printf(" ==> extracting: %s (mode %04o, directory)\n", filename,
  679. mode);
  680. #endif
  681. #ifdef WIN32
  682. if (mkdir(buf) == -1)
  683. #else
  684. if (mkdir(buf, mode & 07777) == -1)
  685. #endif
  686. {
  687. #ifdef __BORLANDC__
  688. /* There is a bug in the Borland Run time library which makes MKDIR
  689. return EACCES when it should return EEXIST
  690. if it is some other error besides directory exists
  691. then return false */
  692. if ( errno == EACCES)
  693. {
  694. errno = EEXIST;
  695. }
  696. #endif
  697. if (errno == EEXIST)
  698. {
  699. if (chmod(filename, mode & 07777) == -1)
  700. {
  701. #ifdef DEBUG
  702. perror("chmod()");
  703. #endif
  704. if (pathname)
  705. {
  706. free(pathname);
  707. }
  708. return -1;
  709. }
  710. else
  711. {
  712. #ifdef DEBUG
  713. puts(" *** using existing directory");
  714. #endif
  715. if (pathname)
  716. {
  717. free(pathname);
  718. }
  719. return 1;
  720. }
  721. }
  722. else
  723. {
  724. #ifdef DEBUG
  725. perror("mkdir()");
  726. #endif
  727. if (pathname)
  728. {
  729. free(pathname);
  730. }
  731. return -1;
  732. }
  733. }
  734. if (pathname)
  735. {
  736. free(pathname);
  737. }
  738. return 0;
  739. }
  740. /* FIFO */
  741. int
  742. tar_extract_fifo(TAR *t, char *realname)
  743. {
  744. mode_t mode;
  745. char *filename;
  746. char buf[T_BLOCKSIZE];
  747. char *pathname = 0;
  748. if (!TH_ISFIFO(t))
  749. {
  750. errno = EINVAL;
  751. return -1;
  752. }
  753. if (realname)
  754. {
  755. filename = realname;
  756. }
  757. else
  758. {
  759. pathname = th_get_pathname(t);
  760. filename = pathname;
  761. }
  762. mode = th_get_mode(t);
  763. /* Make a copy of the string because dirname and mkdirhier may modify the
  764. * string */
  765. strncpy(buf, filename, sizeof(buf)-1);
  766. buf[sizeof(buf)-1] = 0;
  767. if (mkdirhier(dirname(buf)) == -1)
  768. {
  769. if (pathname)
  770. {
  771. free(pathname);
  772. }
  773. return -1;
  774. }
  775. #ifdef DEBUG
  776. printf(" ==> extracting: %s (fifo)\n", filename);
  777. #endif
  778. #ifndef WIN32
  779. if (mkfifo(filename, mode & 07777) == -1)
  780. #else
  781. (void)mode;
  782. #endif
  783. {
  784. #ifdef DEBUG
  785. perror("mkfifo()");
  786. #endif
  787. if (pathname)
  788. {
  789. free(pathname);
  790. }
  791. return -1;
  792. }
  793. #ifndef WIN32
  794. if (pathname)
  795. {
  796. free(pathname);
  797. }
  798. return 0;
  799. #endif
  800. }