aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2008-04-05 00:07:46 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2008-04-05 00:07:46 +0000
commit261f237024d9881e110f271fb575728f666b25b4 (patch)
treec643d8289cc1bf5e98a245d3857d23c4403050d5
parent7f8f0fafdbe59a2c32894f729955c1ad65e5a4ce (diff)
downloadbusybox-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.in8
-rw-r--r--archival/cpio.c225
-rw-r--r--include/usage.h11
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
81config 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
81config DPKG 89config 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 17enum {
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
30static 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. */
43static 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
25int cpio_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 195int cpio_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
26int cpio_main(int argc, char **argv) 196int 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" \