data_extract_all.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  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 ((!S_ISDIR(file_header->mode))
  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)
  76. && (errno != EISDIR) /* btw, Linux doesn't return this */
  77. && (errno != EEXIST)
  78. && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET)
  79. ) {
  80. bb_perror_msg("cannot make dir %s", file_header->name);
  81. }
  82. break;
  83. case S_IFLNK:
  84. /* Symlink */
  85. res = symlink(file_header->link_target, file_header->name);
  86. if ((res == -1)
  87. && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET)
  88. ) {
  89. bb_perror_msg("cannot create %slink "
  90. "from %s to %s", "sym",
  91. file_header->name,
  92. file_header->link_target);
  93. }
  94. break;
  95. case S_IFSOCK:
  96. case S_IFBLK:
  97. case S_IFCHR:
  98. case S_IFIFO:
  99. res = mknod(file_header->name, file_header->mode, file_header->device);
  100. if ((res == -1)
  101. && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET)
  102. ) {
  103. bb_perror_msg("cannot create node %s", file_header->name);
  104. }
  105. break;
  106. default:
  107. bb_error_msg_and_die("unrecognized file type");
  108. }
  109. }
  110. if (!(archive_handle->ah_flags & ARCHIVE_NOPRESERVE_OWN)) {
  111. #if ENABLE_FEATURE_TAR_UNAME_GNAME
  112. if (!(archive_handle->ah_flags & ARCHIVE_NUMERIC_OWNER)) {
  113. uid_t uid = file_header->uid;
  114. gid_t gid = file_header->gid;
  115. if (file_header->uname) {
  116. struct passwd *pwd = getpwnam(file_header->uname);
  117. if (pwd) uid = pwd->pw_uid;
  118. }
  119. if (file_header->gname) {
  120. struct group *grp = getgrnam(file_header->gname);
  121. if (grp) gid = grp->gr_gid;
  122. }
  123. lchown(file_header->name, uid, gid);
  124. } else
  125. #endif
  126. lchown(file_header->name, file_header->uid, file_header->gid);
  127. }
  128. if (S_ISLNK(file_header->mode)) {
  129. /* uclibc has no lchmod, glibc is even stranger -
  130. * it has lchmod which seems to do nothing!
  131. * so we use chmod... */
  132. if (!(archive_handle->ah_flags & ARCHIVE_NOPRESERVE_PERM)) {
  133. chmod(file_header->name, file_header->mode);
  134. }
  135. /* same for utime */
  136. if (archive_handle->ah_flags & ARCHIVE_PRESERVE_DATE) {
  137. struct utimbuf t;
  138. t.actime = t.modtime = file_header->mtime;
  139. utime(file_header->name, &t);
  140. }
  141. }
  142. }