aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2017-07-20 18:34:51 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2017-07-20 18:34:51 +0200
commit13ae85edd1e097299297062a1054ccbe8fb97fe3 (patch)
treee52b3e822aa011a53e9401d04d5c024ee35ea45f
parentebe3c35d004463a423b0b9dc77a8a113a7353ba6 (diff)
downloadbusybox-w32-13ae85edd1e097299297062a1054ccbe8fb97fe3.tar.gz
busybox-w32-13ae85edd1e097299297062a1054ccbe8fb97fe3.tar.bz2
busybox-w32-13ae85edd1e097299297062a1054ccbe8fb97fe3.zip
unzip: support symlinks. Closes 10031
function old new delta unzip_main 2519 2667 +148 Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r--archival/unzip.c61
1 files changed, 48 insertions, 13 deletions
diff --git a/archival/unzip.c b/archival/unzip.c
index d6b8da347..44c4a3125 100644
--- a/archival/unzip.c
+++ b/archival/unzip.c
@@ -334,6 +334,38 @@ static void unzip_create_leading_dirs(const char *fn)
334 free(name); 334 free(name);
335} 335}
336 336
337static void unzip_extract_symlink(zip_header_t *zip, const char *dst_fn)
338{
339 char *target;
340
341 if (zip->fmt.ucmpsize > 0xfff) /* no funny business please */
342 bb_error_msg_and_die("bad archive");
343
344 if (zip->fmt.method == 0) {
345 /* Method 0 - stored (not compressed) */
346 target = xzalloc(zip->fmt.ucmpsize + 1);
347 xread(zip_fd, target, zip->fmt.ucmpsize);
348 } else {
349#if 1
350 bb_error_msg_and_die("compressed symlink is not supported");
351#else
352 transformer_state_t xstate;
353 init_transformer_state(&xstate);
354 xstate.mem_output_size_max = zip->fmt.ucmpsize;
355 /* ...unpack... */
356 if (!xstate.mem_output_buf)
357 WTF();
358 target = xstate.mem_output_buf;
359 target = xrealloc(target, xstate.mem_output_size + 1);
360 target[xstate.mem_output_size] = '\0';
361#endif
362 }
363//TODO: libbb candidate
364 if (symlink(target, dst_fn))
365 bb_perror_msg_and_die("can't create symlink '%s'", dst_fn);
366 free(target);
367}
368
337static void unzip_extract(zip_header_t *zip, int dst_fd) 369static void unzip_extract(zip_header_t *zip, int dst_fd)
338{ 370{
339 transformer_state_t xstate; 371 transformer_state_t xstate;
@@ -346,12 +378,6 @@ static void unzip_extract(zip_header_t *zip, int dst_fd)
346 return; 378 return;
347 } 379 }
348 380
349// NB: to support symlinks, need to extract symlink target. A-la:
350// xstate.mem_output_size_max = zip->fmt.ucmpsize;
351// ...unpack...
352// if (xstate.mem_output_buf) { success, xstate.mem_output_size is the size }
353// Although archives I've seen have fmt.method == 0 for symlinks.
354
355 init_transformer_state(&xstate); 381 init_transformer_state(&xstate);
356 xstate.bytes_in = zip->fmt.cmpsize; 382 xstate.bytes_in = zip->fmt.cmpsize;
357 xstate.src_fd = zip_fd; 383 xstate.src_fd = zip_fd;
@@ -719,7 +745,6 @@ int unzip_main(int argc, char **argv)
719 if ((cdf.fmt.version_made_by >> 8) == 3) { 745 if ((cdf.fmt.version_made_by >> 8) == 3) {
720 /* This archive is created on Unix */ 746 /* This archive is created on Unix */
721 dir_mode = file_mode = (cdf.fmt.external_attributes >> 16); 747 dir_mode = file_mode = (cdf.fmt.external_attributes >> 16);
722//TODO: if (S_ISLNK(file_mode)) this is a symlink
723 } 748 }
724 } 749 }
725#endif 750#endif
@@ -833,7 +858,7 @@ int unzip_main(int argc, char **argv)
833 } 858 }
834 check_file: 859 check_file:
835 /* Extract file */ 860 /* Extract file */
836 if (stat(dst_fn, &stat_buf) == -1) { 861 if (lstat(dst_fn, &stat_buf) == -1) {
837 /* File does not exist */ 862 /* File does not exist */
838 if (errno != ENOENT) { 863 if (errno != ENOENT) {
839 bb_perror_msg_and_die("can't stat '%s'", dst_fn); 864 bb_perror_msg_and_die("can't stat '%s'", dst_fn);
@@ -854,6 +879,7 @@ int unzip_main(int argc, char **argv)
854 goto do_open_and_extract; 879 goto do_open_and_extract;
855 printf("replace %s? [y]es, [n]o, [A]ll, [N]one, [r]ename: ", dst_fn); 880 printf("replace %s? [y]es, [n]o, [A]ll, [N]one, [r]ename: ", dst_fn);
856 my_fgets80(key_buf); 881 my_fgets80(key_buf);
882//TODO: redo lstat + ISREG check! user input could have taken a long time!
857 883
858 switch (key_buf[0]) { 884 switch (key_buf[0]) {
859 case 'A': 885 case 'A':
@@ -862,7 +888,8 @@ int unzip_main(int argc, char **argv)
862 do_open_and_extract: 888 do_open_and_extract:
863 unzip_create_leading_dirs(dst_fn); 889 unzip_create_leading_dirs(dst_fn);
864#if ENABLE_FEATURE_UNZIP_CDF 890#if ENABLE_FEATURE_UNZIP_CDF
865 dst_fd = xopen3(dst_fn, O_WRONLY | O_CREAT | O_TRUNC, file_mode); 891 if (!S_ISLNK(file_mode))
892 dst_fd = xopen3(dst_fn, O_WRONLY | O_CREAT | O_TRUNC, file_mode);
866#else 893#else
867 dst_fd = xopen(dst_fn, O_WRONLY | O_CREAT | O_TRUNC); 894 dst_fd = xopen(dst_fn, O_WRONLY | O_CREAT | O_TRUNC);
868#endif 895#endif
@@ -872,10 +899,18 @@ int unzip_main(int argc, char **argv)
872 ? " extracting: %s\n" 899 ? " extracting: %s\n"
873 : */ " inflating: %s\n", dst_fn); 900 : */ " inflating: %s\n", dst_fn);
874 } 901 }
875 unzip_extract(&zip, dst_fd); 902#if ENABLE_FEATURE_UNZIP_CDF
876 if (dst_fd != STDOUT_FILENO) { 903 if (S_ISLNK(file_mode)) {
877 /* closing STDOUT is potentially bad for future business */ 904 if (dst_fd != STDOUT_FILENO) /* no -p */
878 close(dst_fd); 905 unzip_extract_symlink(&zip, dst_fn);
906 } else
907#endif
908 {
909 unzip_extract(&zip, dst_fd);
910 if (dst_fd != STDOUT_FILENO) {
911 /* closing STDOUT is potentially bad for future business */
912 close(dst_fd);
913 }
879 } 914 }
880 break; 915 break;
881 916