data_extract_all.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. /* vi: set sw=4 ts=4: */
  2. /*
  3. * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
  4. */
  5. #include "libbb.h"
  6. #include "unarchive.h"
  7. void FAST_FUNC data_extract_all(archive_handle_t *archive_handle)
  8. {
  9. file_header_t *file_header = archive_handle->file_header;
  10. int dst_fd;
  11. int res;
  12. if (archive_handle->ah_flags & ARCHIVE_CREATE_LEADING_DIRS) {
  13. char *name = xstrdup(file_header->name);
  14. bb_make_directory(dirname(name), -1, FILEUTILS_RECUR);
  15. free(name);
  16. }
  17. /* Check if the file already exists */
  18. if (archive_handle->ah_flags & ARCHIVE_EXTRACT_UNCONDITIONAL) {
  19. /* Remove the entry if it exists */
  20. if (((file_header->mode & S_IFMT) != S_IFDIR)
  21. && (unlink(file_header->name) == -1)
  22. && (errno != ENOENT)
  23. ) {
  24. bb_perror_msg_and_die("cannot remove old file %s",
  25. file_header->name);
  26. }
  27. }
  28. else if (archive_handle->ah_flags & ARCHIVE_EXTRACT_NEWER) {
  29. /* Remove the existing entry if its older than the extracted entry */
  30. struct stat statbuf;
  31. if (lstat(file_header->name, &statbuf) == -1) {
  32. if (errno != ENOENT) {
  33. bb_perror_msg_and_die("cannot stat old file");
  34. }
  35. }
  36. else if (statbuf.st_mtime <= file_header->mtime) {
  37. if (!(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET)) {
  38. bb_error_msg("%s not created: newer or "
  39. "same age file exists", file_header->name);
  40. }
  41. data_skip(archive_handle);
  42. return;
  43. }
  44. else if ((unlink(file_header->name) == -1) && (errno != EISDIR)) {
  45. bb_perror_msg_and_die("cannot remove old file %s",
  46. file_header->name);
  47. }
  48. }
  49. /* Handle hard links separately
  50. * We identified hard links as regular files of size 0 with a symlink */
  51. if (S_ISREG(file_header->mode) && (file_header->link_target)
  52. && (file_header->size == 0)
  53. ) {
  54. /* hard link */
  55. res = link(file_header->link_target, file_header->name);
  56. if ((res == -1) && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET)) {
  57. bb_perror_msg("cannot create %slink "
  58. "from %s to %s", "hard",
  59. file_header->name,
  60. file_header->link_target);
  61. }
  62. } else {
  63. /* Create the filesystem entry */
  64. switch (file_header->mode & S_IFMT) {
  65. case S_IFREG: {
  66. /* Regular file */
  67. dst_fd = xopen3(file_header->name, O_WRONLY | O_CREAT | O_EXCL,
  68. file_header->mode);
  69. bb_copyfd_exact_size(archive_handle->src_fd, dst_fd, file_header->size);
  70. close(dst_fd);
  71. break;
  72. }
  73. case S_IFDIR:
  74. res = mkdir(file_header->name, file_header->mode);
  75. if ((res == -1) && (errno != EISDIR)
  76. && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET)
  77. ) {
  78. bb_perror_msg("cannot make dir %s", file_header->name);
  79. }
  80. break;
  81. case S_IFLNK:
  82. /* Symlink */
  83. res = symlink(file_header->link_target, file_header->name);
  84. if ((res == -1)
  85. && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET)
  86. ) {
  87. bb_perror_msg("cannot create %slink "
  88. "from %s to %s", "sym",
  89. file_header->name,
  90. file_header->link_target);
  91. }
  92. break;
  93. case S_IFSOCK:
  94. case S_IFBLK:
  95. case S_IFCHR:
  96. case S_IFIFO:
  97. res = mknod(file_header->name, file_header->mode, file_header->device);
  98. if ((res == -1)
  99. && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET)
  100. ) {
  101. bb_perror_msg("cannot create node %s", file_header->name);
  102. }
  103. break;
  104. default:
  105. bb_error_msg_and_die("unrecognized file type");
  106. }
  107. }
  108. if (!(archive_handle->ah_flags & ARCHIVE_NOPRESERVE_OWN)) {
  109. #if ENABLE_FEATURE_TAR_UNAME_GNAME
  110. uid_t uid = file_header->uid;
  111. gid_t gid = file_header->gid;
  112. if (file_header->uname) {
  113. struct passwd *pwd = getpwnam(file_header->uname);
  114. if (pwd) uid = pwd->pw_uid;
  115. }
  116. if (file_header->gname) {
  117. struct group *grp = getgrnam(file_header->gname);
  118. if (grp) gid = grp->gr_gid;
  119. }
  120. lchown(file_header->name, uid, gid);
  121. #else
  122. lchown(file_header->name, file_header->uid, file_header->gid);
  123. #endif
  124. }
  125. if ((file_header->mode & S_IFMT) != S_IFLNK) {
  126. /* uclibc has no lchmod, glibc is even stranger -
  127. * it has lchmod which seems to do nothing!
  128. * so we use chmod... */
  129. if (!(archive_handle->ah_flags & ARCHIVE_NOPRESERVE_PERM)) {
  130. chmod(file_header->name, file_header->mode);
  131. }
  132. /* same for utime */
  133. if (archive_handle->ah_flags & ARCHIVE_PRESERVE_DATE) {
  134. struct utimbuf t;
  135. t.actime = t.modtime = file_header->mtime;
  136. utime(file_header->name, &t);
  137. }
  138. }
  139. }