diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2008-04-05 00:07:46 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2008-04-05 00:07:46 +0000 |
commit | 261f237024d9881e110f271fb575728f666b25b4 (patch) | |
tree | c643d8289cc1bf5e98a245d3857d23c4403050d5 | |
parent | 7f8f0fafdbe59a2c32894f729955c1ad65e5a4ce (diff) | |
download | busybox-w32-261f237024d9881e110f271fb575728f666b25b4.tar.gz busybox-w32-261f237024d9881e110f271fb575728f666b25b4.tar.bz2 busybox-w32-261f237024d9881e110f271fb575728f666b25b4.zip |
cpio: optional support for writing cpio files in newc format.
by pascal.bellard AT ads-lu.com.
function old new delta
cpio_main 247 1122 +875
cpio_pad4 - 58 +58
gnu_dev_major 66 99 +33
gnu_dev_minor 38 57 +19
packed_usage 23964 23978 +14
------------------------------------------------------------------------------
(add/remove: 1/0 grow/shrink: 4/0 up/down: 999/0) Total: 999 bytes
-rw-r--r-- | archival/Config.in | 8 | ||||
-rw-r--r-- | archival/cpio.c | 225 | ||||
-rw-r--r-- | include/usage.h | 11 |
3 files changed, 225 insertions, 19 deletions
diff --git a/archival/Config.in b/archival/Config.in index 60c3ed2d5..28450612e 100644 --- a/archival/Config.in +++ b/archival/Config.in | |||
@@ -78,6 +78,14 @@ config CPIO | |||
78 | Unless you have a specific application which requires cpio, you should | 78 | Unless you have a specific application which requires cpio, you should |
79 | probably say N here. | 79 | probably say N here. |
80 | 80 | ||
81 | config FEATURE_CPIO_O | ||
82 | bool "Support for archive creation" | ||
83 | default n | ||
84 | depends on CPIO | ||
85 | help | ||
86 | This implementation of cpio can create cpio archives in the "newc" | ||
87 | format only. | ||
88 | |||
81 | config DPKG | 89 | config DPKG |
82 | bool "dpkg" | 90 | bool "dpkg" |
83 | default n | 91 | default n |
diff --git a/archival/cpio.c b/archival/cpio.c index 59ae60c77..c17219832 100644 --- a/archival/cpio.c +++ b/archival/cpio.c | |||
@@ -7,35 +7,225 @@ | |||
7 | * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. | 7 | * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. |
8 | * | 8 | * |
9 | * Limitations: | 9 | * Limitations: |
10 | * Doesn't check CRC's | 10 | * Doesn't check CRC's |
11 | * Only supports new ASCII and CRC formats | 11 | * Only supports new ASCII and CRC formats |
12 | * | 12 | * |
13 | */ | 13 | */ |
14 | #include "libbb.h" | 14 | #include "libbb.h" |
15 | #include "unarchive.h" | 15 | #include "unarchive.h" |
16 | 16 | ||
17 | #define CPIO_OPT_EXTRACT 0x01 | 17 | enum { |
18 | #define CPIO_OPT_TEST 0x02 | 18 | CPIO_OPT_EXTRACT = (1 << 0), |
19 | #define CPIO_OPT_UNCONDITIONAL 0x04 | 19 | CPIO_OPT_TEST = (1 << 1), |
20 | #define CPIO_OPT_VERBOSE 0x08 | 20 | CPIO_OPT_UNCONDITIONAL = (1 << 2), |
21 | #define CPIO_OPT_FILE 0x10 | 21 | CPIO_OPT_VERBOSE = (1 << 3), |
22 | #define CPIO_OPT_CREATE_LEADING_DIR 0x20 | 22 | CPIO_OPT_FILE = (1 << 4), |
23 | #define CPIO_OPT_PRESERVE_MTIME 0x40 | 23 | CPIO_OPT_CREATE_LEADING_DIR = (1 << 5), |
24 | CPIO_OPT_PRESERVE_MTIME = (1 << 6), | ||
25 | CPIO_OPT_CREATE = (1 << 7), | ||
26 | CPIO_OPT_FORMAT = (1 << 8), | ||
27 | }; | ||
28 | |||
29 | #if ENABLE_FEATURE_CPIO_O | ||
30 | static off_t cpio_pad4(off_t size) | ||
31 | { | ||
32 | int i; | ||
33 | |||
34 | i = (- size) & 3; | ||
35 | size += i; | ||
36 | while (--i >= 0) | ||
37 | bb_putchar('\0'); | ||
38 | return size; | ||
39 | } | ||
40 | |||
41 | /* Return value will become exit code. | ||
42 | * It's ok to exit instead of return. */ | ||
43 | static int cpio_o(void) | ||
44 | { | ||
45 | struct name_s { | ||
46 | struct name_s *next; | ||
47 | char name[1]; | ||
48 | }; | ||
49 | struct inodes_s { | ||
50 | struct inodes_s *next; | ||
51 | struct name_s *names; | ||
52 | struct stat st; | ||
53 | }; | ||
54 | |||
55 | struct inodes_s *links = NULL; | ||
56 | off_t bytes = 0; /* output bytes count */ | ||
57 | |||
58 | while (1) { | ||
59 | const char *name; | ||
60 | char *line; | ||
61 | struct stat st; | ||
62 | |||
63 | line = xmalloc_fgetline(stdin); | ||
64 | |||
65 | if (line) { | ||
66 | /* Strip leading "./[./]..." from the filename */ | ||
67 | name = line; | ||
68 | while (name[0] == '.' && name[1] == '/') { | ||
69 | while (*++name == '/') | ||
70 | continue; | ||
71 | } | ||
72 | if (!*name) { /* line is empty */ | ||
73 | free(line); | ||
74 | continue; | ||
75 | } | ||
76 | if (lstat(name, &st)) { | ||
77 | abort_cpio_o: | ||
78 | bb_simple_perror_msg_and_die(name); | ||
79 | } | ||
80 | |||
81 | if (!(S_ISLNK(st.st_mode) || S_ISREG(st.st_mode))) | ||
82 | st.st_size = 0; /* paranoia */ | ||
83 | |||
84 | /* Store hardlinks for later processing, dont output them */ | ||
85 | if (!S_ISDIR(st.st_mode) && st.st_nlink > 1) { | ||
86 | struct name_s *n; | ||
87 | struct inodes_s *l; | ||
88 | |||
89 | /* Do we have this hardlink remembered? */ | ||
90 | l = links; | ||
91 | while (1) { | ||
92 | if (l == NULL) { | ||
93 | /* Not found: add new item to "links" list */ | ||
94 | l = xzalloc(sizeof(*l)); | ||
95 | l->st = st; | ||
96 | l->next = links; | ||
97 | links = l; | ||
98 | break; | ||
99 | } | ||
100 | if (l->st.st_ino == st.st_ino) { | ||
101 | /* found */ | ||
102 | break; | ||
103 | } | ||
104 | l = l->next; | ||
105 | } | ||
106 | /* Add new name to "l->names" list */ | ||
107 | n = xmalloc(sizeof(*n) + strlen(name)); | ||
108 | strcpy(n->name, name); | ||
109 | n->next = l->names; | ||
110 | l->names = n; | ||
111 | |||
112 | free(line); | ||
113 | continue; | ||
114 | } | ||
115 | |||
116 | } else { /* line == NULL: EOF */ | ||
117 | next_link: | ||
118 | if (links) { | ||
119 | /* Output hardlink's data */ | ||
120 | st = links->st; | ||
121 | name = links->names->name; | ||
122 | links->names = links->names->next; | ||
123 | /* GNU cpio is reported to emit file data | ||
124 | * only for the last instance. Mimic that. */ | ||
125 | if (links->names == NULL) | ||
126 | links = links->next; | ||
127 | else | ||
128 | st.st_size = 0; | ||
129 | /* NB: we leak links->names and/or links, | ||
130 | * this is intended (we exit soon anyway) */ | ||
131 | } else { | ||
132 | /* If no (more) hardlinks to output, | ||
133 | * output "trailer" entry */ | ||
134 | name = "TRAILER!!!"; | ||
135 | /* st.st_size == 0 is a must, but for uniformity | ||
136 | * in the output, we zero out everything */ | ||
137 | memset(&st, 0, sizeof(st)); | ||
138 | /* st.st_nlink = 1; - GNU cpio does this */ | ||
139 | } | ||
140 | } | ||
141 | |||
142 | bytes += printf("070701" | ||
143 | "%08X%08X%08X%08X%08X%08X%08X" | ||
144 | "%08X%08X%08X%08X" /* GNU cpio uses uppercase hex */ | ||
145 | /* strlen+1: */ "%08X" | ||
146 | /* chksum: */ "00000000" /* (only for "070702" files) */ | ||
147 | /* name,NUL: */ "%s%c", | ||
148 | (unsigned)(uint32_t) st.st_ino, | ||
149 | (unsigned)(uint32_t) st.st_mode, | ||
150 | (unsigned)(uint32_t) st.st_uid, | ||
151 | (unsigned)(uint32_t) st.st_gid, | ||
152 | (unsigned)(uint32_t) st.st_nlink, | ||
153 | (unsigned)(uint32_t) st.st_mtime, | ||
154 | (unsigned)(uint32_t) st.st_size, | ||
155 | (unsigned)(uint32_t) major(st.st_dev), | ||
156 | (unsigned)(uint32_t) minor(st.st_dev), | ||
157 | (unsigned)(uint32_t) major(st.st_rdev), | ||
158 | (unsigned)(uint32_t) minor(st.st_rdev), | ||
159 | (unsigned)(strlen(name) + 1), | ||
160 | name, '\0'); | ||
161 | bytes = cpio_pad4(bytes); | ||
162 | |||
163 | if (st.st_size) { | ||
164 | if (S_ISLNK(st.st_mode)) { | ||
165 | char *lpath = xmalloc_readlink_or_warn(name); | ||
166 | if (!lpath) | ||
167 | goto abort_cpio_o; | ||
168 | bytes += printf("%s", lpath); | ||
169 | free(lpath); | ||
170 | } else { /* S_ISREG */ | ||
171 | int fd = xopen(name, O_RDONLY); | ||
172 | fflush(stdout); | ||
173 | /* We must abort if file got shorter too! */ | ||
174 | if (bb_copyfd_size(fd, STDOUT_FILENO, st.st_size) != st.st_size) { | ||
175 | bb_error_msg_and_die("I/O error, of file '%s' was truncated", name); | ||
176 | } | ||
177 | bytes += st.st_size; | ||
178 | close(fd); | ||
179 | } | ||
180 | bytes = cpio_pad4(bytes); | ||
181 | } | ||
182 | |||
183 | if (!line) { | ||
184 | if (links) | ||
185 | goto next_link; | ||
186 | /* TODO: GNU cpio pads trailer to 512 bytes, do we want that? */ | ||
187 | return EXIT_SUCCESS; | ||
188 | } | ||
189 | |||
190 | free(line); | ||
191 | } /* end of "while (1)" */ | ||
192 | } | ||
193 | #endif | ||
24 | 194 | ||
25 | int cpio_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 195 | int cpio_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
26 | int cpio_main(int argc, char **argv) | 196 | int cpio_main(int argc ATTRIBUTE_UNUSED, char **argv) |
27 | { | 197 | { |
28 | archive_handle_t *archive_handle; | 198 | archive_handle_t *archive_handle; |
29 | char *cpio_filename = NULL; | 199 | char *cpio_filename; |
200 | #if ENABLE_FEATURE_CPIO_O | ||
201 | const char *cpio_fmt = ""; | ||
202 | #endif | ||
30 | unsigned opt; | 203 | unsigned opt; |
31 | 204 | ||
32 | /* Initialise */ | 205 | /* Initialize */ |
33 | archive_handle = init_handle(); | 206 | archive_handle = init_handle(); |
34 | archive_handle->src_fd = STDIN_FILENO; | 207 | archive_handle->src_fd = STDIN_FILENO; |
35 | archive_handle->seek = seek_by_read; | 208 | archive_handle->seek = seek_by_read; |
36 | archive_handle->flags = ARCHIVE_EXTRACT_NEWER | ARCHIVE_PRESERVE_DATE; | 209 | archive_handle->flags = ARCHIVE_EXTRACT_NEWER | ARCHIVE_PRESERVE_DATE; |
37 | 210 | ||
211 | #if ENABLE_FEATURE_CPIO_O | ||
212 | opt = getopt32(argv, "ituvF:dmoH:", &cpio_filename, &cpio_fmt); | ||
213 | |||
214 | if (opt & CPIO_OPT_CREATE) { | ||
215 | if (*cpio_fmt != 'n') | ||
216 | bb_show_usage(); | ||
217 | if (opt & CPIO_OPT_FILE) { | ||
218 | fclose(stdout); | ||
219 | stdout = fopen(cpio_filename, "w"); | ||
220 | /* Paranoia: I don't trust libc that much */ | ||
221 | xdup2(fileno(stdout), STDOUT_FILENO); | ||
222 | } | ||
223 | return cpio_o(); | ||
224 | } | ||
225 | #else | ||
38 | opt = getopt32(argv, "ituvF:dm", &cpio_filename); | 226 | opt = getopt32(argv, "ituvF:dm", &cpio_filename); |
227 | #endif | ||
228 | argv += optind; | ||
39 | 229 | ||
40 | /* One of either extract or test options must be given */ | 230 | /* One of either extract or test options must be given */ |
41 | if ((opt & (CPIO_OPT_TEST | CPIO_OPT_EXTRACT)) == 0) { | 231 | if ((opt & (CPIO_OPT_TEST | CPIO_OPT_EXTRACT)) == 0) { |
@@ -63,7 +253,7 @@ int cpio_main(int argc, char **argv) | |||
63 | archive_handle->action_header = header_list; | 253 | archive_handle->action_header = header_list; |
64 | } | 254 | } |
65 | } | 255 | } |
66 | if (cpio_filename) { /* CPIO_OPT_FILE */ | 256 | if (opt & CPIO_OPT_FILE) { /* -F */ |
67 | archive_handle->src_fd = xopen(cpio_filename, O_RDONLY); | 257 | archive_handle->src_fd = xopen(cpio_filename, O_RDONLY); |
68 | archive_handle->seek = seek_by_jump; | 258 | archive_handle->seek = seek_by_jump; |
69 | } | 259 | } |
@@ -71,13 +261,14 @@ int cpio_main(int argc, char **argv) | |||
71 | archive_handle->flags |= ARCHIVE_CREATE_LEADING_DIRS; | 261 | archive_handle->flags |= ARCHIVE_CREATE_LEADING_DIRS; |
72 | } | 262 | } |
73 | 263 | ||
74 | while (optind < argc) { | 264 | while (*argv) { |
75 | archive_handle->filter = filter_accept_list; | 265 | archive_handle->filter = filter_accept_list; |
76 | llist_add_to(&(archive_handle->accept), argv[optind]); | 266 | llist_add_to(&(archive_handle->accept), *argv); |
77 | optind++; | 267 | argv++; |
78 | } | 268 | } |
79 | 269 | ||
80 | while (get_header_cpio(archive_handle) == EXIT_SUCCESS); | 270 | while (get_header_cpio(archive_handle) == EXIT_SUCCESS) |
271 | continue; | ||
81 | 272 | ||
82 | return EXIT_SUCCESS; | 273 | return EXIT_SUCCESS; |
83 | } | 274 | } |
diff --git a/include/usage.h b/include/usage.h index 529a228ec..0849c6831 100644 --- a/include/usage.h +++ b/include/usage.h | |||
@@ -509,13 +509,20 @@ | |||
509 | "\n -l,-s Create (sym)links" \ | 509 | "\n -l,-s Create (sym)links" \ |
510 | 510 | ||
511 | #define cpio_trivial_usage \ | 511 | #define cpio_trivial_usage \ |
512 | "-[dimtuv][F cpiofile]" | 512 | "-[dim" USE_FEATURE_CPIO_O("o") "tuv][F cpiofile]" \ |
513 | USE_FEATURE_CPIO_O( "[H newc]" ) | ||
513 | #define cpio_full_usage \ | 514 | #define cpio_full_usage \ |
514 | "Extract or list files from a cpio archive\n" \ | 515 | "Extract or list files from a cpio archive" \ |
516 | USE_FEATURE_CPIO_O( ", or create a cpio archive" ) \ | ||
517 | "\n" \ | ||
515 | "Main operation mode:" \ | 518 | "Main operation mode:" \ |
516 | "\n d Make leading directories" \ | 519 | "\n d Make leading directories" \ |
517 | "\n i Extract" \ | 520 | "\n i Extract" \ |
518 | "\n m Preserve mtime" \ | 521 | "\n m Preserve mtime" \ |
522 | USE_FEATURE_CPIO_O( \ | ||
523 | "\n o Create" \ | ||
524 | "\n H newc Define format" \ | ||
525 | ) \ | ||
519 | "\n t List" \ | 526 | "\n t List" \ |
520 | "\n v Verbose" \ | 527 | "\n v Verbose" \ |
521 | "\n u Unconditional overwrite" \ | 528 | "\n u Unconditional overwrite" \ |