diff options
| author | bug1 <bug1@69ca8d6d-28ef-0310-b511-8ec308f3f277> | 2001-06-22 09:22:06 +0000 |
|---|---|---|
| committer | bug1 <bug1@69ca8d6d-28ef-0310-b511-8ec308f3f277> | 2001-06-22 09:22:06 +0000 |
| commit | e1886edd0ca3ea6f622c70d687a27f2b7eef52a7 (patch) | |
| tree | 5a1924092009892cc80f0b0947ec1bae17ca3b1c | |
| parent | db3c0c3742717789043407a05c90c8c8eef0dd5e (diff) | |
| download | busybox-w32-e1886edd0ca3ea6f622c70d687a27f2b7eef52a7.tar.gz busybox-w32-e1886edd0ca3ea6f622c70d687a27f2b7eef52a7.tar.bz2 busybox-w32-e1886edd0ca3ea6f622c70d687a27f2b7eef52a7.zip | |
cpio applet, and changes to associated code
git-svn-id: svn://busybox.net/trunk/busybox@2887 69ca8d6d-28ef-0310-b511-8ec308f3f277
| -rw-r--r-- | Config.h | 1 | ||||
| -rw-r--r-- | applets.h | 3 | ||||
| -rw-r--r-- | applets/usage.h | 12 | ||||
| -rw-r--r-- | ar.c | 2 | ||||
| -rw-r--r-- | archival/ar.c | 2 | ||||
| -rw-r--r-- | archival/cpio.c | 93 | ||||
| -rw-r--r-- | archival/dpkg_deb.c | 3 | ||||
| -rw-r--r-- | cpio.c | 93 | ||||
| -rw-r--r-- | dpkg_deb.c | 3 | ||||
| -rw-r--r-- | include/applets.h | 3 | ||||
| -rw-r--r-- | include/usage.h | 12 | ||||
| -rw-r--r-- | libbb/unarchive.c | 85 | ||||
| -rw-r--r-- | usage.h | 12 |
13 files changed, 305 insertions, 19 deletions
| @@ -19,6 +19,7 @@ | |||
| 19 | #define BB_CLEAR | 19 | #define BB_CLEAR |
| 20 | //#define BB_CMP | 20 | //#define BB_CMP |
| 21 | #define BB_CP | 21 | #define BB_CP |
| 22 | //#define BB_CPIO | ||
| 22 | #define BB_CUT | 23 | #define BB_CUT |
| 23 | #define BB_DATE | 24 | #define BB_DATE |
| 24 | //#define BB_DC | 25 | //#define BB_DC |
| @@ -83,6 +83,9 @@ | |||
| 83 | #ifdef BB_CP | 83 | #ifdef BB_CP |
| 84 | APPLET(cp, cp_main, _BB_DIR_BIN) | 84 | APPLET(cp, cp_main, _BB_DIR_BIN) |
| 85 | #endif | 85 | #endif |
| 86 | #ifdef BB_CPIO | ||
| 87 | APPLET(cpio, cpio_main, _BB_DIR_BIN) | ||
| 88 | #endif | ||
| 86 | #ifdef BB_CUT | 89 | #ifdef BB_CUT |
| 87 | APPLET(cut, cut_main, _BB_DIR_USR_BIN) | 90 | APPLET(cut, cut_main, _BB_DIR_USR_BIN) |
| 88 | #endif | 91 | #endif |
diff --git a/applets/usage.h b/applets/usage.h index 9fd3a2e1c..51a06b977 100644 --- a/applets/usage.h +++ b/applets/usage.h | |||
| @@ -129,6 +129,18 @@ | |||
| 129 | "\t-f\tforce (implied; ignored) - always set\n" \ | 129 | "\t-f\tforce (implied; ignored) - always set\n" \ |
| 130 | "\t-R\tCopies directories recursively" | 130 | "\t-R\tCopies directories recursively" |
| 131 | 131 | ||
| 132 | #define cpio_trivial_usage \ | ||
| 133 | "-[dimtuv][F cpiofile]" | ||
| 134 | #define cpio_full_usage \ | ||
| 135 | "Extract or list files from a cpio archive\n" \ | ||
| 136 | "Main operation mode:\n" \ | ||
| 137 | "\td\t\tmake directories (assumed)\n" \ | ||
| 138 | "\ti\t\textract\n" \ | ||
| 139 | "\tm\t\tpreserve time\n" \ | ||
| 140 | "\tt\t\tlist\n" \ | ||
| 141 | "\tu\t\tunconditional (assumed)\t" \ | ||
| 142 | "\tF\t\tinput from file\t" | ||
| 143 | |||
| 132 | #define cut_trivial_usage \ | 144 | #define cut_trivial_usage \ |
| 133 | "[OPTION]... [FILE]..." | 145 | "[OPTION]... [FILE]..." |
| 134 | #define cut_full_usage \ | 146 | #define cut_full_usage \ |
| @@ -34,7 +34,7 @@ extern int ar_main(int argc, char **argv) | |||
| 34 | FILE *src_stream = NULL; | 34 | FILE *src_stream = NULL; |
| 35 | char **extract_names = NULL; | 35 | char **extract_names = NULL; |
| 36 | char ar_magic[8]; | 36 | char ar_magic[8]; |
| 37 | int extract_function = 0; | 37 | int extract_function = extract_unconditional; |
| 38 | int opt; | 38 | int opt; |
| 39 | int num_of_entries = 0; | 39 | int num_of_entries = 0; |
| 40 | extern off_t archive_offset; | 40 | extern off_t archive_offset; |
diff --git a/archival/ar.c b/archival/ar.c index fd98d86f5..09a4a8894 100644 --- a/archival/ar.c +++ b/archival/ar.c | |||
| @@ -34,7 +34,7 @@ extern int ar_main(int argc, char **argv) | |||
| 34 | FILE *src_stream = NULL; | 34 | FILE *src_stream = NULL; |
| 35 | char **extract_names = NULL; | 35 | char **extract_names = NULL; |
| 36 | char ar_magic[8]; | 36 | char ar_magic[8]; |
| 37 | int extract_function = 0; | 37 | int extract_function = extract_unconditional; |
| 38 | int opt; | 38 | int opt; |
| 39 | int num_of_entries = 0; | 39 | int num_of_entries = 0; |
| 40 | extern off_t archive_offset; | 40 | extern off_t archive_offset; |
diff --git a/archival/cpio.c b/archival/cpio.c new file mode 100644 index 000000000..ecd6f534a --- /dev/null +++ b/archival/cpio.c | |||
| @@ -0,0 +1,93 @@ | |||
| 1 | /* vi: set sw=4 ts=4: */ | ||
| 2 | /* | ||
| 3 | * Mini cpio implementation for busybox | ||
| 4 | * | ||
| 5 | * Copyright (C) 2001 by Glenn McGrath | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License as published by | ||
| 9 | * the Free Software Foundation; either version 2 of the License, or | ||
| 10 | * (at your option) any later version. | ||
| 11 | * | ||
| 12 | * This program is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 15 | * General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU General Public License | ||
| 18 | * along with this program; if not, write to the Free Software | ||
| 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 20 | * | ||
| 21 | * Limitations: | ||
| 22 | * Doesn't check CRC's | ||
| 23 | * Only supports new ASCII and CRC formats | ||
| 24 | * Doesnt support hard links | ||
| 25 | * | ||
| 26 | */ | ||
| 27 | #include <fcntl.h> | ||
| 28 | #include <getopt.h> | ||
| 29 | #include <stdlib.h> | ||
| 30 | #include <string.h> | ||
| 31 | #include <unistd.h> | ||
| 32 | #include "busybox.h" | ||
| 33 | |||
| 34 | extern int cpio_main(int argc, char **argv) | ||
| 35 | { | ||
| 36 | FILE *src_stream = stdin; | ||
| 37 | char **extract_names = NULL; | ||
| 38 | int extract_function = 0; | ||
| 39 | int num_of_entries = 0; | ||
| 40 | int opt = 0; | ||
| 41 | mode_t oldmask = 0; | ||
| 42 | |||
| 43 | while ((opt = getopt(argc, argv, "idmuvtF:")) != -1) { | ||
| 44 | switch (opt) { | ||
| 45 | case 'i': // extract | ||
| 46 | extract_function |= extract_all_to_fs; | ||
| 47 | break; | ||
| 48 | case 'd': // create directories | ||
| 49 | extract_function |= extract_create_dirs; | ||
| 50 | oldmask = umask(077); /* Make create_path act like GNU cpio */ | ||
| 51 | break; | ||
| 52 | case 'm': // preserve modification time | ||
| 53 | extract_function |= extract_preserve_date; | ||
| 54 | break; | ||
| 55 | case 'v': // verbosly list files | ||
| 56 | extract_function |= extract_verbose_list; | ||
| 57 | break; | ||
| 58 | case 'u': // unconditional | ||
| 59 | extract_function |= extract_unconditional; | ||
| 60 | break; | ||
| 61 | case 't': // list files | ||
| 62 | extract_function |= extract_list; | ||
| 63 | break; | ||
| 64 | case 'F': | ||
| 65 | src_stream = xfopen(optarg, "r"); | ||
| 66 | break; | ||
| 67 | default: | ||
| 68 | show_usage(); | ||
| 69 | } | ||
| 70 | } | ||
| 71 | |||
| 72 | if (extract_function & extract_all_to_fs && extract_function & extract_list) { | ||
| 73 | extract_function ^= extract_all_to_fs; /* If specify t, don't extract*/ | ||
| 74 | } | ||
| 75 | |||
| 76 | if (extract_function & extract_all_to_fs && extract_function & extract_verbose_list) { /* The meaning of v changes on extract */ | ||
| 77 | extract_function ^= extract_verbose_list; | ||
| 78 | extract_function |= extract_list; | ||
| 79 | } | ||
| 80 | |||
| 81 | extract_names = malloc(4); | ||
| 82 | while (optind < argc) { | ||
| 83 | num_of_entries++; | ||
| 84 | *extract_names = realloc(*extract_names, num_of_entries); | ||
| 85 | extract_names[num_of_entries - 1] = xstrdup(argv[optind]); | ||
| 86 | optind++; | ||
| 87 | } | ||
| 88 | |||
| 89 | unarchive(src_stream, &get_header_cpio, extract_function, "./", extract_names); | ||
| 90 | if (oldmask) umask(oldmask); /* Restore umask if we changed it */ | ||
| 91 | return EXIT_SUCCESS; | ||
| 92 | } | ||
| 93 | |||
diff --git a/archival/dpkg_deb.c b/archival/dpkg_deb.c index 77172b0f6..b1cbb1bbc 100644 --- a/archival/dpkg_deb.c +++ b/archival/dpkg_deb.c | |||
| @@ -26,7 +26,7 @@ extern int dpkg_deb_main(int argc, char **argv) | |||
| 26 | char *output_buffer = NULL; | 26 | char *output_buffer = NULL; |
| 27 | int opt = 0; | 27 | int opt = 0; |
| 28 | int arg_type = 0; | 28 | int arg_type = 0; |
| 29 | int deb_extract_funct = extract_create_dirs; | 29 | int deb_extract_funct = extract_create_dirs | extract_unconditional; |
| 30 | 30 | ||
| 31 | const int arg_type_prefix = 1; | 31 | const int arg_type_prefix = 1; |
| 32 | const int arg_type_field = 2; | 32 | const int arg_type_field = 2; |
| @@ -92,6 +92,7 @@ extern int dpkg_deb_main(int argc, char **argv) | |||
| 92 | strcat(prefix, "/"); | 92 | strcat(prefix, "/"); |
| 93 | } | 93 | } |
| 94 | } | 94 | } |
| 95 | mkdir(prefix, 0777); | ||
| 95 | } | 96 | } |
| 96 | 97 | ||
| 97 | if (arg_type == arg_type_filename) { | 98 | if (arg_type == arg_type_filename) { |
| @@ -0,0 +1,93 @@ | |||
| 1 | /* vi: set sw=4 ts=4: */ | ||
| 2 | /* | ||
| 3 | * Mini cpio implementation for busybox | ||
| 4 | * | ||
| 5 | * Copyright (C) 2001 by Glenn McGrath | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License as published by | ||
| 9 | * the Free Software Foundation; either version 2 of the License, or | ||
| 10 | * (at your option) any later version. | ||
| 11 | * | ||
| 12 | * This program is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 15 | * General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU General Public License | ||
| 18 | * along with this program; if not, write to the Free Software | ||
| 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 20 | * | ||
| 21 | * Limitations: | ||
| 22 | * Doesn't check CRC's | ||
| 23 | * Only supports new ASCII and CRC formats | ||
| 24 | * Doesnt support hard links | ||
| 25 | * | ||
| 26 | */ | ||
| 27 | #include <fcntl.h> | ||
| 28 | #include <getopt.h> | ||
| 29 | #include <stdlib.h> | ||
| 30 | #include <string.h> | ||
| 31 | #include <unistd.h> | ||
| 32 | #include "busybox.h" | ||
| 33 | |||
| 34 | extern int cpio_main(int argc, char **argv) | ||
| 35 | { | ||
| 36 | FILE *src_stream = stdin; | ||
| 37 | char **extract_names = NULL; | ||
| 38 | int extract_function = 0; | ||
| 39 | int num_of_entries = 0; | ||
| 40 | int opt = 0; | ||
| 41 | mode_t oldmask = 0; | ||
| 42 | |||
| 43 | while ((opt = getopt(argc, argv, "idmuvtF:")) != -1) { | ||
| 44 | switch (opt) { | ||
| 45 | case 'i': // extract | ||
| 46 | extract_function |= extract_all_to_fs; | ||
| 47 | break; | ||
| 48 | case 'd': // create directories | ||
| 49 | extract_function |= extract_create_dirs; | ||
| 50 | oldmask = umask(077); /* Make create_path act like GNU cpio */ | ||
| 51 | break; | ||
| 52 | case 'm': // preserve modification time | ||
| 53 | extract_function |= extract_preserve_date; | ||
| 54 | break; | ||
| 55 | case 'v': // verbosly list files | ||
| 56 | extract_function |= extract_verbose_list; | ||
| 57 | break; | ||
| 58 | case 'u': // unconditional | ||
| 59 | extract_function |= extract_unconditional; | ||
| 60 | break; | ||
| 61 | case 't': // list files | ||
| 62 | extract_function |= extract_list; | ||
| 63 | break; | ||
| 64 | case 'F': | ||
| 65 | src_stream = xfopen(optarg, "r"); | ||
| 66 | break; | ||
| 67 | default: | ||
| 68 | show_usage(); | ||
| 69 | } | ||
| 70 | } | ||
| 71 | |||
| 72 | if (extract_function & extract_all_to_fs && extract_function & extract_list) { | ||
| 73 | extract_function ^= extract_all_to_fs; /* If specify t, don't extract*/ | ||
| 74 | } | ||
| 75 | |||
| 76 | if (extract_function & extract_all_to_fs && extract_function & extract_verbose_list) { /* The meaning of v changes on extract */ | ||
| 77 | extract_function ^= extract_verbose_list; | ||
| 78 | extract_function |= extract_list; | ||
| 79 | } | ||
| 80 | |||
| 81 | extract_names = malloc(4); | ||
| 82 | while (optind < argc) { | ||
| 83 | num_of_entries++; | ||
| 84 | *extract_names = realloc(*extract_names, num_of_entries); | ||
| 85 | extract_names[num_of_entries - 1] = xstrdup(argv[optind]); | ||
| 86 | optind++; | ||
| 87 | } | ||
| 88 | |||
| 89 | unarchive(src_stream, &get_header_cpio, extract_function, "./", extract_names); | ||
| 90 | if (oldmask) umask(oldmask); /* Restore umask if we changed it */ | ||
| 91 | return EXIT_SUCCESS; | ||
| 92 | } | ||
| 93 | |||
diff --git a/dpkg_deb.c b/dpkg_deb.c index 77172b0f6..b1cbb1bbc 100644 --- a/dpkg_deb.c +++ b/dpkg_deb.c | |||
| @@ -26,7 +26,7 @@ extern int dpkg_deb_main(int argc, char **argv) | |||
| 26 | char *output_buffer = NULL; | 26 | char *output_buffer = NULL; |
| 27 | int opt = 0; | 27 | int opt = 0; |
| 28 | int arg_type = 0; | 28 | int arg_type = 0; |
| 29 | int deb_extract_funct = extract_create_dirs; | 29 | int deb_extract_funct = extract_create_dirs | extract_unconditional; |
| 30 | 30 | ||
| 31 | const int arg_type_prefix = 1; | 31 | const int arg_type_prefix = 1; |
| 32 | const int arg_type_field = 2; | 32 | const int arg_type_field = 2; |
| @@ -92,6 +92,7 @@ extern int dpkg_deb_main(int argc, char **argv) | |||
| 92 | strcat(prefix, "/"); | 92 | strcat(prefix, "/"); |
| 93 | } | 93 | } |
| 94 | } | 94 | } |
| 95 | mkdir(prefix, 0777); | ||
| 95 | } | 96 | } |
| 96 | 97 | ||
| 97 | if (arg_type == arg_type_filename) { | 98 | if (arg_type == arg_type_filename) { |
diff --git a/include/applets.h b/include/applets.h index 0fd89c71a..88aec8ad1 100644 --- a/include/applets.h +++ b/include/applets.h | |||
| @@ -83,6 +83,9 @@ | |||
| 83 | #ifdef BB_CP | 83 | #ifdef BB_CP |
| 84 | APPLET(cp, cp_main, _BB_DIR_BIN) | 84 | APPLET(cp, cp_main, _BB_DIR_BIN) |
| 85 | #endif | 85 | #endif |
| 86 | #ifdef BB_CPIO | ||
| 87 | APPLET(cpio, cpio_main, _BB_DIR_BIN) | ||
| 88 | #endif | ||
| 86 | #ifdef BB_CUT | 89 | #ifdef BB_CUT |
| 87 | APPLET(cut, cut_main, _BB_DIR_USR_BIN) | 90 | APPLET(cut, cut_main, _BB_DIR_USR_BIN) |
| 88 | #endif | 91 | #endif |
diff --git a/include/usage.h b/include/usage.h index 9fd3a2e1c..51a06b977 100644 --- a/include/usage.h +++ b/include/usage.h | |||
| @@ -129,6 +129,18 @@ | |||
| 129 | "\t-f\tforce (implied; ignored) - always set\n" \ | 129 | "\t-f\tforce (implied; ignored) - always set\n" \ |
| 130 | "\t-R\tCopies directories recursively" | 130 | "\t-R\tCopies directories recursively" |
| 131 | 131 | ||
| 132 | #define cpio_trivial_usage \ | ||
| 133 | "-[dimtuv][F cpiofile]" | ||
| 134 | #define cpio_full_usage \ | ||
| 135 | "Extract or list files from a cpio archive\n" \ | ||
| 136 | "Main operation mode:\n" \ | ||
| 137 | "\td\t\tmake directories (assumed)\n" \ | ||
| 138 | "\ti\t\textract\n" \ | ||
| 139 | "\tm\t\tpreserve time\n" \ | ||
| 140 | "\tt\t\tlist\n" \ | ||
| 141 | "\tu\t\tunconditional (assumed)\t" \ | ||
| 142 | "\tF\t\tinput from file\t" | ||
| 143 | |||
| 132 | #define cut_trivial_usage \ | 144 | #define cut_trivial_usage \ |
| 133 | "[OPTION]... [FILE]..." | 145 | "[OPTION]... [FILE]..." |
| 134 | #define cut_full_usage \ | 146 | #define cut_full_usage \ |
diff --git a/libbb/unarchive.c b/libbb/unarchive.c index 635dcae35..20609ded7 100644 --- a/libbb/unarchive.c +++ b/libbb/unarchive.c | |||
| @@ -119,10 +119,11 @@ char *extract_archive(FILE *src_stream, FILE *out_stream, const file_header_t *f | |||
| 119 | } | 119 | } |
| 120 | } | 120 | } |
| 121 | else if (function & extract_all_to_fs) { | 121 | else if (function & extract_all_to_fs) { |
| 122 | #if 0 | ||
| 123 | struct stat oldfile; | 122 | struct stat oldfile; |
| 124 | if ( (S_ISLNK(file_entry->mode) ? lstat (full_name, &oldfile) : stat (full_name, &oldfile)) == 0) { /* The file already exists */ | 123 | int stat_res; |
| 125 | if (function & extract_unconditional || oldfile.st_mtime < file_entry->mtime) { | 124 | stat_res = lstat (full_name, &oldfile); |
| 125 | if (stat_res == 0) { /* The file already exists */ | ||
| 126 | if ((function & extract_unconditional) || (oldfile.st_mtime < file_entry->mtime)) { | ||
| 126 | if (!S_ISDIR(oldfile.st_mode)) { | 127 | if (!S_ISDIR(oldfile.st_mode)) { |
| 127 | unlink(full_name); /* Directories might not be empty etc */ | 128 | unlink(full_name); /* Directories might not be empty etc */ |
| 128 | } | 129 | } |
| @@ -134,7 +135,6 @@ char *extract_archive(FILE *src_stream, FILE *out_stream, const file_header_t *f | |||
| 134 | return (NULL); | 135 | return (NULL); |
| 135 | } | 136 | } |
| 136 | } | 137 | } |
| 137 | #endif | ||
| 138 | switch(file_entry->mode & S_IFMT) { | 138 | switch(file_entry->mode & S_IFMT) { |
| 139 | case S_IFREG: | 139 | case S_IFREG: |
| 140 | if (file_entry->link_name) { /* Found a cpio hard link */ | 140 | if (file_entry->link_name) { /* Found a cpio hard link */ |
| @@ -153,10 +153,11 @@ char *extract_archive(FILE *src_stream, FILE *out_stream, const file_header_t *f | |||
| 153 | } | 153 | } |
| 154 | break; | 154 | break; |
| 155 | case S_IFDIR: | 155 | case S_IFDIR: |
| 156 | /* Use make_directory instead of mkdir in case prefix path hasn't been created */ | 156 | if ((function & extract_create_dirs) && (stat_res != 0)) { |
| 157 | if (function & extract_create_dirs) { | 157 | /* Make sure the prefix component of full_name was create |
| 158 | if (make_directory(full_name, file_entry->mode, FILEUTILS_RECUR) < 0) { | 158 | * in applet before getting here*/ |
| 159 | return NULL; | 159 | if (mkdir(full_name, file_entry->mode) < 0) { |
| 160 | perror_msg("extract_archive: "); | ||
| 160 | } | 161 | } |
| 161 | } | 162 | } |
| 162 | break; | 163 | break; |
| @@ -335,14 +336,38 @@ void *get_header_ar(FILE *src_stream) | |||
| 335 | #endif | 336 | #endif |
| 336 | 337 | ||
| 337 | #ifdef L_get_header_cpio | 338 | #ifdef L_get_header_cpio |
| 339 | struct hardlinks { | ||
| 340 | file_header_t *entry; | ||
| 341 | int inode; | ||
| 342 | struct hardlinks *next; | ||
| 343 | }; | ||
| 344 | |||
| 338 | void *get_header_cpio(FILE *src_stream) | 345 | void *get_header_cpio(FILE *src_stream) |
| 339 | { | 346 | { |
| 340 | file_header_t *cpio_entry = NULL; | 347 | file_header_t *cpio_entry = NULL; |
| 341 | char cpio_header[110]; | 348 | char cpio_header[110]; |
| 342 | char dummy[14]; | ||
| 343 | int namesize; | 349 | int namesize; |
| 344 | int major, minor, nlink; | 350 | char dummy[16]; |
| 345 | 351 | int major, minor, nlink, inode; | |
| 352 | static struct hardlinks *saved_hardlinks = NULL; | ||
| 353 | static int pending_hardlinks = 0; | ||
| 354 | |||
| 355 | if (pending_hardlinks) { /* Deal with any pending hardlinks */ | ||
| 356 | struct hardlinks *tmp = saved_hardlinks, *oldtmp = NULL; | ||
| 357 | while (tmp) { | ||
| 358 | if (tmp->entry->link_name) { /* Found a hardlink ready to be extracted */ | ||
| 359 | cpio_entry = tmp->entry; | ||
| 360 | if (oldtmp) oldtmp->next = tmp->next; /* Remove item from linked list */ | ||
| 361 | else saved_hardlinks = tmp->next; | ||
| 362 | free(tmp); | ||
| 363 | return (cpio_entry); | ||
| 364 | } | ||
| 365 | oldtmp = tmp; | ||
| 366 | tmp = tmp->next; | ||
| 367 | } | ||
| 368 | pending_hardlinks = 0; /* No more pending hardlinks, read next file entry */ | ||
| 369 | } | ||
| 370 | |||
| 346 | /* There can be padding before archive header */ | 371 | /* There can be padding before archive header */ |
| 347 | seek_sub_file(src_stream, (4 - (archive_offset % 4)) % 4); | 372 | seek_sub_file(src_stream, (4 - (archive_offset % 4)) % 4); |
| 348 | if (fread(cpio_header, 1, 110, src_stream) == 110) { | 373 | if (fread(cpio_header, 1, 110, src_stream) == 110) { |
| @@ -356,8 +381,8 @@ void *get_header_cpio(FILE *src_stream) | |||
| 356 | /* Doesnt do the crc check yet */ | 381 | /* Doesnt do the crc check yet */ |
| 357 | case '1': /* "newc" header format */ | 382 | case '1': /* "newc" header format */ |
| 358 | cpio_entry = (file_header_t *) xcalloc(1, sizeof(file_header_t)); | 383 | cpio_entry = (file_header_t *) xcalloc(1, sizeof(file_header_t)); |
| 359 | sscanf(cpio_header, "%14c%8x%8x%8x%8x%8lx%8lx%16c%8x%8x%8x%8c", | 384 | sscanf(cpio_header, "%6c%8x%8x%8x%8x%8x%8lx%8lx%16c%8x%8x%8x%8c", |
| 360 | dummy, &cpio_entry->mode, &cpio_entry->uid, &cpio_entry->gid, | 385 | dummy, &inode, &cpio_entry->mode, &cpio_entry->uid, &cpio_entry->gid, |
| 361 | &nlink, &cpio_entry->mtime, &cpio_entry->size, | 386 | &nlink, &cpio_entry->mtime, &cpio_entry->size, |
| 362 | dummy, &major, &minor, &namesize, dummy); | 387 | dummy, &major, &minor, &namesize, dummy); |
| 363 | 388 | ||
| @@ -368,6 +393,19 @@ void *get_header_cpio(FILE *src_stream) | |||
| 368 | seek_sub_file(src_stream, (4 - (archive_offset % 4)) % 4); | 393 | seek_sub_file(src_stream, (4 - (archive_offset % 4)) % 4); |
| 369 | if (strcmp(cpio_entry->name, "TRAILER!!!") == 0) { | 394 | if (strcmp(cpio_entry->name, "TRAILER!!!") == 0) { |
| 370 | printf("%d blocks\n", (int) (archive_offset % 512 ? (archive_offset / 512) + 1 : archive_offset / 512)); /* Always round up */ | 395 | printf("%d blocks\n", (int) (archive_offset % 512 ? (archive_offset / 512) + 1 : archive_offset / 512)); /* Always round up */ |
| 396 | if (saved_hardlinks) { /* Bummer - we still have unresolved hardlinks */ | ||
| 397 | struct hardlinks *tmp = saved_hardlinks, *oldtmp = NULL; | ||
| 398 | while (tmp) { | ||
| 399 | error_msg("%s not created: cannot resolve hardlink", tmp->entry->name); | ||
| 400 | oldtmp = tmp; | ||
| 401 | tmp = tmp->next; | ||
| 402 | free (oldtmp->entry->name); | ||
| 403 | free (oldtmp->entry); | ||
| 404 | free (oldtmp); | ||
| 405 | } | ||
| 406 | saved_hardlinks = NULL; | ||
| 407 | pending_hardlinks = 0; | ||
| 408 | } | ||
| 371 | return(NULL); | 409 | return(NULL); |
| 372 | } | 410 | } |
| 373 | 411 | ||
| @@ -376,9 +414,26 @@ void *get_header_cpio(FILE *src_stream) | |||
| 376 | fread(cpio_entry->link_name, 1, cpio_entry->size, src_stream); | 414 | fread(cpio_entry->link_name, 1, cpio_entry->size, src_stream); |
| 377 | archive_offset += cpio_entry->size; | 415 | archive_offset += cpio_entry->size; |
| 378 | } | 416 | } |
| 379 | if (nlink > 1 && !S_ISDIR(cpio_entry->mode) && cpio_entry->size == 0) { | 417 | if (nlink > 1 && !S_ISDIR(cpio_entry->mode)) { |
| 380 | error_msg("%s not extracted: Cannot handle hard links yet", cpio_entry->name); | 418 | if (cpio_entry->size == 0) { /* Put file on a linked list for later */ |
| 419 | struct hardlinks *new = xmalloc(sizeof(struct hardlinks)); | ||
| 420 | new->next = saved_hardlinks; | ||
| 421 | new->inode = inode; | ||
| 422 | new->entry = cpio_entry; | ||
| 423 | saved_hardlinks = new; | ||
| 381 | return(get_header_cpio(src_stream)); /* Recurse to next file */ | 424 | return(get_header_cpio(src_stream)); /* Recurse to next file */ |
| 425 | } else { /* Found the file with data in */ | ||
| 426 | struct hardlinks *tmp = saved_hardlinks; | ||
| 427 | pending_hardlinks = 1; | ||
| 428 | while (tmp) { | ||
| 429 | if (tmp->inode == inode) { | ||
| 430 | tmp->entry->link_name = xstrdup(cpio_entry->name); | ||
| 431 | nlink--; | ||
| 432 | } | ||
| 433 | tmp = tmp->next; | ||
| 434 | } | ||
| 435 | if (nlink > 1) error_msg("error resolving hardlink: did you create the archive with GNU cpio 2.0-2.2?"); | ||
| 436 | } | ||
| 382 | } | 437 | } |
| 383 | cpio_entry->device = (major << 8) | minor; | 438 | cpio_entry->device = (major << 8) | minor; |
| 384 | break; | 439 | break; |
| @@ -129,6 +129,18 @@ | |||
| 129 | "\t-f\tforce (implied; ignored) - always set\n" \ | 129 | "\t-f\tforce (implied; ignored) - always set\n" \ |
| 130 | "\t-R\tCopies directories recursively" | 130 | "\t-R\tCopies directories recursively" |
| 131 | 131 | ||
| 132 | #define cpio_trivial_usage \ | ||
| 133 | "-[dimtuv][F cpiofile]" | ||
| 134 | #define cpio_full_usage \ | ||
| 135 | "Extract or list files from a cpio archive\n" \ | ||
| 136 | "Main operation mode:\n" \ | ||
| 137 | "\td\t\tmake directories (assumed)\n" \ | ||
| 138 | "\ti\t\textract\n" \ | ||
| 139 | "\tm\t\tpreserve time\n" \ | ||
| 140 | "\tt\t\tlist\n" \ | ||
| 141 | "\tu\t\tunconditional (assumed)\t" \ | ||
| 142 | "\tF\t\tinput from file\t" | ||
| 143 | |||
| 132 | #define cut_trivial_usage \ | 144 | #define cut_trivial_usage \ |
| 133 | "[OPTION]... [FILE]..." | 145 | "[OPTION]... [FILE]..." |
| 134 | #define cut_full_usage \ | 146 | #define cut_full_usage \ |
