1 /* vi: set sw=4 ts=4: */
3 * Mini cpio implementation for busybox
5 * Copyright (C) 2001 by Glenn McGrath
7 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
11 * Only supports new ASCII and CRC formats
15 #include "unarchive.h"
17 #if ENABLE_FEATURE_CPIO_O
18 static off_t
cpio_pad4(off_t size
)
29 /* Return value will become exit code.
30 * It's ok to exit instead of return. */
31 static int cpio_o(void)
33 static const char trailer
[] ALIGN1
= "TRAILER!!!";
39 struct inodes_s
*next
;
44 struct inodes_s
*links
= NULL
;
45 off_t bytes
= 0; /* output bytes count */
52 line
= xmalloc_fgetline(stdin
);
55 /* Strip leading "./[./]..." from the filename */
57 while (name
[0] == '.' && name
[1] == '/') {
58 while (*++name
== '/')
61 if (!*name
) { /* line is empty */
65 if (lstat(name
, &st
)) {
67 bb_simple_perror_msg_and_die(name
);
70 if (!(S_ISLNK(st
.st_mode
) || S_ISREG(st
.st_mode
)))
71 st
.st_size
= 0; /* paranoia */
73 /* Store hardlinks for later processing, dont output them */
74 if (!S_ISDIR(st
.st_mode
) && st
.st_nlink
> 1) {
78 /* Do we have this hardlink remembered? */
82 /* Not found: add new item to "links" list */
83 l
= xzalloc(sizeof(*l
));
89 if (l
->st
.st_ino
== st
.st_ino
) {
95 /* Add new name to "l->names" list */
96 n
= xmalloc(sizeof(*n
) + strlen(name
));
97 strcpy(n
->name
, name
);
105 } else { /* line == NULL: EOF */
108 /* Output hardlink's data */
110 name
= links
->names
->name
;
111 links
->names
= links
->names
->next
;
112 /* GNU cpio is reported to emit file data
113 * only for the last instance. Mimic that. */
114 if (links
->names
== NULL
)
118 /* NB: we leak links->names and/or links,
119 * this is intended (we exit soon anyway) */
121 /* If no (more) hardlinks to output,
122 * output "trailer" entry */
124 /* st.st_size == 0 is a must, but for uniformity
125 * in the output, we zero out everything */
126 memset(&st
, 0, sizeof(st
));
127 /* st.st_nlink = 1; - GNU cpio does this */
131 bytes
+= printf("070701"
132 "%08X%08X%08X%08X%08X%08X%08X"
133 "%08X%08X%08X%08X" /* GNU cpio uses uppercase hex */
134 /* strlen+1: */ "%08X"
135 /* chksum: */ "00000000" /* (only for "070702" files) */
136 /* name,NUL: */ "%s%c",
137 (unsigned)(uint32_t) st
.st_ino
,
138 (unsigned)(uint32_t) st
.st_mode
,
139 (unsigned)(uint32_t) st
.st_uid
,
140 (unsigned)(uint32_t) st
.st_gid
,
141 (unsigned)(uint32_t) st
.st_nlink
,
142 (unsigned)(uint32_t) st
.st_mtime
,
143 (unsigned)(uint32_t) st
.st_size
,
144 (unsigned)(uint32_t) major(st
.st_dev
),
145 (unsigned)(uint32_t) minor(st
.st_dev
),
146 (unsigned)(uint32_t) major(st
.st_rdev
),
147 (unsigned)(uint32_t) minor(st
.st_rdev
),
148 (unsigned)(strlen(name
) + 1),
150 bytes
= cpio_pad4(bytes
);
153 if (S_ISLNK(st
.st_mode
)) {
154 char *lpath
= xmalloc_readlink_or_warn(name
);
157 bytes
+= printf("%s", lpath
);
159 } else { /* S_ISREG */
160 int fd
= xopen(name
, O_RDONLY
);
162 /* We must abort if file got shorter too! */
163 bb_copyfd_exact_size(fd
, STDOUT_FILENO
, st
.st_size
);
167 bytes
= cpio_pad4(bytes
);
173 /* TODO: GNU cpio pads trailer to 512 bytes, do we want that? */
178 } /* end of "while (1)" */
182 /* GNU cpio 2.9 --help (abridged):
185 -i, --extract Extract files from an archive
186 -o, --create Create the archive
187 -p, --pass-through Copy-pass mode [was ist das?!]
188 -t, --list List the archive
190 Options valid in any mode:
191 --block-size=SIZE I/O block size = SIZE * 512 bytes
192 -B I/O block size = 5120 bytes
193 -c Use the old portable (ASCII) archive format
194 -C, --io-size=NUMBER I/O block size in bytes
195 -f, --nonmatching Only copy files that do not match given pattern
196 -F, --file=FILE Use FILE instead of standard input or output
197 -H, --format=FORMAT Use given archive FORMAT
198 -M, --message=STRING Print STRING when the end of a volume of the
199 backup media is reached
200 -n, --numeric-uid-gid If -v, show numeric UID and GID
201 --quiet Do not print the number of blocks copied
202 --rsh-command=COMMAND Use remote COMMAND instead of rsh
203 -v, --verbose Verbosely list the files processed
204 -V, --dot Print a "." for each file processed
205 -W, --warning=FLAG Control warning display: 'none','truncate','all';
206 multiple options accumulate
208 Options valid only in --extract mode:
209 -b, --swap Swap both halfwords of words and bytes of
210 halfwords in the data (equivalent to -sS)
211 -r, --rename Interactively rename files
212 -s, --swap-bytes Swap the bytes of each halfword in the files
213 -S, --swap-halfwords Swap the halfwords of each word (4 bytes)
214 --to-stdout Extract files to standard output
215 -E, --pattern-file=FILE Read additional patterns specifying filenames to
216 extract or list from FILE
217 --only-verify-crc Verify CRC's, don't actually extract the files
219 Options valid only in --create mode:
220 -A, --append Append to an existing archive
221 -O FILE File to use instead of standard output
223 Options valid only in --pass-through mode:
224 -l, --link Link files instead of copying them, when possible
226 Options valid in --extract and --create modes:
227 --absolute-filenames Do not strip file system prefix components from
229 --no-absolute-filenames Create all files relative to the current dir
231 Options valid in --create and --pass-through modes:
232 -0, --null A list of filenames is terminated by a NUL
233 -a, --reset-access-time Reset the access times of files after reading them
234 -I FILE File to use instead of standard input
235 -L, --dereference Dereference symbolic links (copy the files
236 that they point to instead of copying the links)
237 -R, --owner=[USER][:.][GROUP] Set owner of created files
239 Options valid in --extract and --pass-through modes:
240 -d, --make-directories Create leading directories where needed
241 -m, --preserve-modification-time Retain mtime when creating files
242 --no-preserve-owner Do not change the ownership of the files
243 --sparse Write files with blocks of zeros as sparse files
244 -u, --unconditional Replace all files unconditionally
247 int cpio_main(int argc
, char **argv
) MAIN_EXTERNALLY_VISIBLE
;
248 int cpio_main(int argc UNUSED_PARAM
, char **argv
)
250 archive_handle_t
*archive_handle
;
252 USE_FEATURE_CPIO_O(const char *cpio_fmt
= "";)
255 CPIO_OPT_EXTRACT
= (1 << 0),
256 CPIO_OPT_TEST
= (1 << 1),
257 CPIO_OPT_UNCONDITIONAL
= (1 << 2),
258 CPIO_OPT_VERBOSE
= (1 << 3),
259 CPIO_OPT_FILE
= (1 << 4),
260 CPIO_OPT_CREATE_LEADING_DIR
= (1 << 5),
261 CPIO_OPT_PRESERVE_MTIME
= (1 << 6),
262 CPIO_OPT_CREATE
= (1 << 7),
263 CPIO_OPT_FORMAT
= (1 << 8),
266 #if ENABLE_GETOPT_LONG
267 applet_long_options
=
268 "extract\0" No_argument
"i"
269 "list\0" No_argument
"t"
270 #if ENABLE_FEATURE_CPIO_O
271 "create\0" No_argument
"o"
272 "format\0" Required_argument
"H"
278 archive_handle
= init_handle();
279 archive_handle
->src_fd
= STDIN_FILENO
;
280 archive_handle
->seek
= seek_by_read
;
281 archive_handle
->ah_flags
= ARCHIVE_EXTRACT_NEWER
;
283 #if ENABLE_FEATURE_CPIO_O
284 opt
= getopt32(argv
, "ituvF:dmoH:", &cpio_filename
, &cpio_fmt
);
286 if (opt
& CPIO_OPT_CREATE
) {
287 if (*cpio_fmt
!= 'n')
289 if (opt
& CPIO_OPT_FILE
) {
291 stdout
= fopen_for_write(cpio_filename
);
292 /* Paranoia: I don't trust libc that much */
293 xdup2(fileno(stdout
), STDOUT_FILENO
);
298 opt
= getopt32(argv
, "ituvF:dm", &cpio_filename
);
302 /* One of either extract or test options must be given */
303 if ((opt
& (CPIO_OPT_TEST
| CPIO_OPT_EXTRACT
)) == 0) {
307 if (opt
& CPIO_OPT_TEST
) {
308 /* if both extract and test options are given, ignore extract option */
309 if (opt
& CPIO_OPT_EXTRACT
) {
310 opt
&= ~CPIO_OPT_EXTRACT
;
312 archive_handle
->action_header
= header_list
;
314 if (opt
& CPIO_OPT_EXTRACT
) {
315 archive_handle
->action_data
= data_extract_all
;
317 if (opt
& CPIO_OPT_UNCONDITIONAL
) {
318 archive_handle
->ah_flags
|= ARCHIVE_EXTRACT_UNCONDITIONAL
;
319 archive_handle
->ah_flags
&= ~ARCHIVE_EXTRACT_NEWER
;
321 if (opt
& CPIO_OPT_VERBOSE
) {
322 if (archive_handle
->action_header
== header_list
) {
323 archive_handle
->action_header
= header_verbose_list
;
325 archive_handle
->action_header
= header_list
;
328 if (opt
& CPIO_OPT_FILE
) { /* -F */
329 archive_handle
->src_fd
= xopen(cpio_filename
, O_RDONLY
);
330 archive_handle
->seek
= seek_by_jump
;
332 if (opt
& CPIO_OPT_CREATE_LEADING_DIR
) {
333 archive_handle
->ah_flags
|= ARCHIVE_CREATE_LEADING_DIRS
;
335 if (opt
& CPIO_OPT_PRESERVE_MTIME
) {
336 archive_handle
->ah_flags
|= ARCHIVE_PRESERVE_DATE
;
340 archive_handle
->filter
= filter_accept_list
;
341 llist_add_to(&(archive_handle
->accept
), *argv
);
345 /* see get_header_cpio */
346 archive_handle
->ah_priv
[2] = (void*) ~(ptrdiff_t)0;
347 while (get_header_cpio(archive_handle
) == EXIT_SUCCESS
)
350 if (archive_handle
->ah_priv
[2] != (void*) ~(ptrdiff_t)0)
351 printf("%lu blocks\n", (unsigned long)(ptrdiff_t)(archive_handle
->ah_priv
[2]));