gunzip.c 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. /* vi: set sw=4 ts=4: */
  2. /*
  3. * Gzip implementation for busybox
  4. *
  5. * Based on GNU gzip v1.2.4 Copyright (C) 1992-1993 Jean-loup Gailly.
  6. *
  7. * Originally adjusted for busybox by Sven Rudolph <sr1@inf.tu-dresden.de>
  8. * based on gzip sources
  9. *
  10. * Adjusted further by Erik Andersen <andersen@codepoet.org> to support files as
  11. * well as stdin/stdout, and to generally behave itself wrt command line
  12. * handling.
  13. *
  14. * General cleanup to better adhere to the style guide and make use of standard
  15. * busybox functions by Glenn McGrath <bug1@iinet.net.au>
  16. *
  17. * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
  18. *
  19. * gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface
  20. * Copyright (C) 1992-1993 Jean-loup Gailly
  21. * The unzip code was written and put in the public domain by Mark Adler.
  22. * Portions of the lzw code are derived from the public domain 'compress'
  23. * written by Spencer Thomas, Joe Orost, James Woods, Jim McKie, Steve Davies,
  24. * Ken Turkowski, Dave Mack and Peter Jannesen.
  25. *
  26. * See the license_msg below and the file COPYING for the software license.
  27. * See the file algorithm.doc for the compression algorithms and file formats.
  28. */
  29. #include "busybox.h"
  30. #include "unarchive.h"
  31. #define GUNZIP_OPT_STDOUT 1
  32. #define GUNZIP_OPT_FORCE 2
  33. #define GUNZIP_OPT_TEST 4
  34. #define GUNZIP_OPT_DECOMPRESS 8
  35. #define GUNZIP_OPT_VERBOSE 0x10
  36. int gunzip_main(int argc, char **argv)
  37. {
  38. USE_DESKTOP(long long) int status;
  39. int exitcode = 0;
  40. unsigned opt;
  41. opt = getopt32(argc, argv, "cftdv");
  42. /* if called as zcat */
  43. if (strcmp(applet_name, "zcat") == 0) {
  44. opt |= GUNZIP_OPT_STDOUT;
  45. }
  46. do {
  47. struct stat stat_buf;
  48. char *old_path = argv[optind];
  49. char *delete_path = NULL;
  50. char *new_path = NULL;
  51. int src_fd;
  52. int dst_fd;
  53. optind++;
  54. if (old_path == NULL || strcmp(old_path, "-") == 0) {
  55. src_fd = STDIN_FILENO;
  56. opt |= GUNZIP_OPT_STDOUT;
  57. USE_DESKTOP(opt &= ~GUNZIP_OPT_VERBOSE;)
  58. optind = argc; /* we don't handle "gunzip - a.gz b.gz" */
  59. } else {
  60. src_fd = xopen(old_path, O_RDONLY);
  61. /* Get the time stamp on the input file. */
  62. fstat(src_fd, &stat_buf);
  63. }
  64. /* Check that the input is sane. */
  65. if (isatty(src_fd) && !(opt & GUNZIP_OPT_FORCE)) {
  66. bb_error_msg_and_die
  67. ("compressed data not read from terminal, use -f to force it");
  68. }
  69. /* Set output filename and number */
  70. if (opt & GUNZIP_OPT_TEST) {
  71. dst_fd = xopen(bb_dev_null, O_WRONLY); /* why does test use filenum 2 ? */
  72. } else if (opt & GUNZIP_OPT_STDOUT) {
  73. dst_fd = STDOUT_FILENO;
  74. } else {
  75. char *extension;
  76. new_path = xstrdup(old_path);
  77. extension = strrchr(new_path, '.');
  78. #ifdef CONFIG_FEATURE_GUNZIP_UNCOMPRESS
  79. if (extension && (strcmp(extension, ".Z") == 0)) {
  80. *extension = '\0';
  81. } else
  82. #endif
  83. if (extension && (strcmp(extension, ".gz") == 0)) {
  84. *extension = '\0';
  85. } else if (extension && (strcmp(extension, ".tgz") == 0)) {
  86. extension[2] = 'a';
  87. extension[3] = 'r';
  88. } else {
  89. // FIXME: should we die or just skip to next?
  90. bb_error_msg_and_die("invalid extension");
  91. }
  92. /* Open output file (with correct permissions) */
  93. dst_fd = xopen3(new_path, O_WRONLY | O_CREAT | O_TRUNC,
  94. stat_buf.st_mode);
  95. /* If unzip succeeds remove the old file */
  96. delete_path = old_path;
  97. }
  98. status = -1;
  99. /* do the decompression, and cleanup */
  100. if (xread_char(src_fd) == 0x1f) {
  101. unsigned char magic2;
  102. magic2 = xread_char(src_fd);
  103. if (ENABLE_FEATURE_GUNZIP_UNCOMPRESS && magic2 == 0x9d) {
  104. status = uncompress(src_fd, dst_fd);
  105. } else if (magic2 == 0x8b) {
  106. check_header_gzip(src_fd); // FIXME: xfunc? _or_die?
  107. status = inflate_gunzip(src_fd, dst_fd);
  108. } else {
  109. bb_error_msg("invalid magic");
  110. exitcode = 1;
  111. }
  112. if (status < 0) {
  113. bb_error_msg("error inflating");
  114. exitcode = 1;
  115. }
  116. else if (ENABLE_DESKTOP && (opt & GUNZIP_OPT_VERBOSE)) {
  117. fprintf(stderr, "%s: %u%% - replaced with %s\n",
  118. old_path, (unsigned)(stat_buf.st_size*100 / (status+1)), new_path);
  119. }
  120. } else {
  121. bb_error_msg("invalid magic");
  122. exitcode = 1;
  123. }
  124. if (status < 0 && new_path) {
  125. /* Unzip failed, remove new path instead of old path */
  126. delete_path = new_path;
  127. }
  128. if (dst_fd != STDOUT_FILENO) {
  129. close(dst_fd);
  130. }
  131. if (src_fd != STDIN_FILENO) {
  132. close(src_fd);
  133. }
  134. /* delete_path will be NULL if in test mode or from stdin */
  135. if (delete_path && (unlink(delete_path) == -1)) {
  136. bb_error_msg("cannot remove %s", delete_path);
  137. exitcode = 1;
  138. }
  139. free(new_path);
  140. } while (optind < argc);
  141. return exitcode;
  142. }