cpio: more compat: -0 and -L options
[platform/upstream/busybox.git] / archival / cpio.c
1 /* vi: set sw=4 ts=4: */
2 /*
3  * Mini cpio implementation for busybox
4  *
5  * Copyright (C) 2001 by Glenn McGrath
6  *
7  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8  *
9  * Limitations:
10  * Doesn't check CRC's
11  * Only supports new ASCII and CRC formats
12  *
13  */
14 #include "libbb.h"
15 #include "unarchive.h"
16
17 /* GNU cpio 2.9 --help (abridged):
18
19  Modes:
20   -t, --list                 List the archive
21   -i, --extract              Extract files from an archive
22   -o, --create               Create the archive
23   -p, --pass-through         Copy-pass mode [was ist das?!]
24
25  Options valid in any mode:
26       --block-size=SIZE      I/O block size = SIZE * 512 bytes
27   -B                         I/O block size = 5120 bytes
28   -c                         Use the old portable (ASCII) archive format
29   -C, --io-size=NUMBER       I/O block size in bytes
30   -f, --nonmatching          Only copy files that do not match given pattern
31   -F, --file=FILE            Use FILE instead of standard input or output
32   -H, --format=FORMAT        Use given archive FORMAT
33   -M, --message=STRING       Print STRING when the end of a volume of the
34                              backup media is reached
35   -n, --numeric-uid-gid      If -v, show numeric UID and GID
36       --quiet                Do not print the number of blocks copied
37       --rsh-command=COMMAND  Use remote COMMAND instead of rsh
38   -v, --verbose              Verbosely list the files processed
39   -V, --dot                  Print a "." for each file processed
40   -W, --warning=FLAG         Control warning display: 'none','truncate','all';
41                              multiple options accumulate
42
43  Options valid only in --extract mode:
44   -b, --swap                 Swap both halfwords of words and bytes of
45                              halfwords in the data (equivalent to -sS)
46   -r, --rename               Interactively rename files
47   -s, --swap-bytes           Swap the bytes of each halfword in the files
48   -S, --swap-halfwords       Swap the halfwords of each word (4 bytes)
49       --to-stdout            Extract files to standard output
50   -E, --pattern-file=FILE    Read additional patterns specifying filenames to
51                              extract or list from FILE
52       --only-verify-crc      Verify CRC's, don't actually extract the files
53
54  Options valid only in --create mode:
55   -A, --append               Append to an existing archive
56   -O FILE                    File to use instead of standard output
57
58  Options valid only in --pass-through mode:
59   -l, --link                 Link files instead of copying them, when possible
60
61  Options valid in --extract and --create modes:
62       --absolute-filenames   Do not strip file system prefix components from
63                              the file names
64       --no-absolute-filenames Create all files relative to the current dir
65
66  Options valid in --create and --pass-through modes:
67   -0, --null                 A list of filenames is terminated by a NUL
68   -a, --reset-access-time    Reset the access times of files after reading them
69   -I FILE                    File to use instead of standard input
70   -L, --dereference          Dereference symbolic links (copy the files
71                              that they point to instead of copying the links)
72   -R, --owner=[USER][:.][GROUP] Set owner of created files
73
74  Options valid in --extract and --pass-through modes:
75   -d, --make-directories     Create leading directories where needed
76   -m, --preserve-modification-time  Retain mtime when creating files
77       --no-preserve-owner    Do not change the ownership of the files
78       --sparse               Write files with blocks of zeros as sparse files
79   -u, --unconditional        Replace all files unconditionally
80  */
81 enum {
82         CPIO_OPT_EXTRACT            = (1 << 0),
83         CPIO_OPT_TEST               = (1 << 1),
84         CPIO_OPT_NUL_TERMINATED     = (1 << 2),
85         CPIO_OPT_UNCONDITIONAL      = (1 << 3),
86         CPIO_OPT_VERBOSE            = (1 << 4),
87         CPIO_OPT_CREATE_LEADING_DIR = (1 << 5),
88         CPIO_OPT_PRESERVE_MTIME     = (1 << 6),
89         CPIO_OPT_DEREF              = (1 << 7),
90         CPIO_OPT_FILE               = (1 << 8),
91         CPIO_OPT_CREATE             = (1 << 9) * ENABLE_FEATURE_CPIO_O,
92         CPIO_OPT_FORMAT             = (1 << 10) * ENABLE_FEATURE_CPIO_O,
93         CPIO_OPT_PASSTHROUGH        = (1 << 11) * ENABLE_FEATURE_CPIO_P,
94 };
95
96 #define OPTION_STR "it0uvdmLF:"
97
98 #if ENABLE_FEATURE_CPIO_O
99 static off_t cpio_pad4(off_t size)
100 {
101         int i;
102
103         i = (- size) & 3;
104         size += i;
105         while (--i >= 0)
106                 bb_putchar('\0');
107         return size;
108 }
109
110 /* Return value will become exit code.
111  * It's ok to exit instead of return. */
112 static int cpio_o(void)
113 {
114         static const char trailer[] ALIGN1 = "TRAILER!!!";
115         struct name_s {
116                 struct name_s *next;
117                 char name[1];
118         };
119         struct inodes_s {
120                 struct inodes_s *next;
121                 struct name_s *names;
122                 struct stat st;
123         };
124
125         struct inodes_s *links = NULL;
126         off_t bytes = 0; /* output bytes count */
127
128         while (1) {
129                 const char *name;
130                 char *line;
131                 struct stat st;
132
133                 line = (option_mask32 & CPIO_OPT_NUL_TERMINATED)
134                                 ? bb_get_chunk_from_file(stdin, NULL)
135                                 : xmalloc_fgetline(stdin);
136
137                 if (line) {
138                         /* Strip leading "./[./]..." from the filename */
139                         name = line;
140                         while (name[0] == '.' && name[1] == '/') {
141                                 while (*++name == '/')
142                                         continue;
143                         }
144                         if (!*name) { /* line is empty */
145                                 free(line);
146                                 continue;
147                         }
148                         if ((option_mask32 & CPIO_OPT_DEREF)
149                                         ? stat(name, &st)
150                                         : lstat(name, &st)
151                         ) {
152  abort_cpio_o:
153                                 bb_simple_perror_msg_and_die(name);
154                         }
155
156                         if (!(S_ISLNK(st.st_mode) || S_ISREG(st.st_mode)))
157                                 st.st_size = 0; /* paranoia */
158
159                         /* Store hardlinks for later processing, dont output them */
160                         if (!S_ISDIR(st.st_mode) && st.st_nlink > 1) {
161                                 struct name_s *n;
162                                 struct inodes_s *l;
163
164                                 /* Do we have this hardlink remembered? */
165                                 l = links;
166                                 while (1) {
167                                         if (l == NULL) {
168                                                 /* Not found: add new item to "links" list */
169                                                 l = xzalloc(sizeof(*l));
170                                                 l->st = st;
171                                                 l->next = links;
172                                                 links = l;
173                                                 break;
174                                         }
175                                         if (l->st.st_ino == st.st_ino) {
176                                                 /* found */
177                                                 break;
178                                         }
179                                         l = l->next;
180                                 }
181                                 /* Add new name to "l->names" list */
182                                 n = xmalloc(sizeof(*n) + strlen(name));
183                                 strcpy(n->name, name);
184                                 n->next = l->names;
185                                 l->names = n;
186
187                                 free(line);
188                                 continue;
189                         }
190
191                 } else { /* line == NULL: EOF */
192  next_link:
193                         if (links) {
194                                 /* Output hardlink's data */
195                                 st = links->st;
196                                 name = links->names->name;
197                                 links->names = links->names->next;
198                                 /* GNU cpio is reported to emit file data
199                                  * only for the last instance. Mimic that. */
200                                 if (links->names == NULL)
201                                         links = links->next;
202                                 else
203                                         st.st_size = 0;
204                                 /* NB: we leak links->names and/or links,
205                                  * this is intended (we exit soon anyway) */
206                         } else {
207                                 /* If no (more) hardlinks to output,
208                                  * output "trailer" entry */
209                                 name = trailer;
210                                 /* st.st_size == 0 is a must, but for uniformity
211                                  * in the output, we zero out everything */
212                                 memset(&st, 0, sizeof(st));
213                                 /* st.st_nlink = 1; - GNU cpio does this */
214                         }
215                 }
216
217                 bytes += printf("070701"
218                                 "%08X%08X%08X%08X%08X%08X%08X"
219                                 "%08X%08X%08X%08X" /* GNU cpio uses uppercase hex */
220                                 /* strlen+1: */ "%08X"
221                                 /* chksum: */   "00000000" /* (only for "070702" files) */
222                                 /* name,NUL: */ "%s%c",
223                                 (unsigned)(uint32_t) st.st_ino,
224                                 (unsigned)(uint32_t) st.st_mode,
225                                 (unsigned)(uint32_t) st.st_uid,
226                                 (unsigned)(uint32_t) st.st_gid,
227                                 (unsigned)(uint32_t) st.st_nlink,
228                                 (unsigned)(uint32_t) st.st_mtime,
229                                 (unsigned)(uint32_t) st.st_size,
230                                 (unsigned)(uint32_t) major(st.st_dev),
231                                 (unsigned)(uint32_t) minor(st.st_dev),
232                                 (unsigned)(uint32_t) major(st.st_rdev),
233                                 (unsigned)(uint32_t) minor(st.st_rdev),
234                                 (unsigned)(strlen(name) + 1),
235                                 name, '\0');
236                 bytes = cpio_pad4(bytes);
237
238                 if (st.st_size) {
239                         if (S_ISLNK(st.st_mode)) {
240                                 char *lpath = xmalloc_readlink_or_warn(name);
241                                 if (!lpath)
242                                         goto abort_cpio_o;
243                                 bytes += printf("%s", lpath);
244                                 free(lpath);
245                         } else { /* S_ISREG */
246                                 int fd = xopen(name, O_RDONLY);
247                                 fflush(stdout);
248                                 /* We must abort if file got shorter too! */
249                                 bb_copyfd_exact_size(fd, STDOUT_FILENO, st.st_size);
250                                 bytes += st.st_size;
251                                 close(fd);
252                         }
253                         bytes = cpio_pad4(bytes);
254                 }
255
256                 if (!line) {
257                         if (name != trailer)
258                                 goto next_link;
259                         /* TODO: GNU cpio pads trailer to 512 bytes, do we want that? */
260                         return EXIT_SUCCESS;
261                 }
262
263                 free(line);
264         } /* end of "while (1)" */
265 }
266 #endif
267
268 int cpio_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
269 int cpio_main(int argc UNUSED_PARAM, char **argv)
270 {
271         archive_handle_t *archive_handle;
272         char *cpio_filename;
273         USE_FEATURE_CPIO_O(const char *cpio_fmt = "";)
274         unsigned opt;
275
276 #if ENABLE_GETOPT_LONG
277         applet_long_options =
278                 "extract\0"      No_argument       "i"
279                 "list\0"         No_argument       "t"
280 #if ENABLE_FEATURE_CPIO_O
281                 "create\0"       No_argument       "o"
282                 "format\0"       Required_argument "H"
283 #if ENABLE_FEATURE_CPIO_P
284                 "pass-through\0" No_argument       "p"
285 #endif
286 #endif
287                 ;
288 #endif
289
290         /* As of now we do not enforce this: */
291         /* -i,-t,-o,-p are mutually exclusive */
292         /* -u,-d,-m make sense only with -i or -p */
293         /* -L makes sense only with -o or -p */
294
295 #if !ENABLE_FEATURE_CPIO_O
296         opt = getopt32(argv, OPTION_STR, &cpio_filename);
297 #else
298         opt = getopt32(argv, OPTION_STR "oH:" USE_FEATURE_CPIO_P("p"), &cpio_filename, &cpio_fmt);
299         if (opt & CPIO_OPT_PASSTHROUGH) {
300                 pid_t pid;
301                 struct fd_pair pp;
302
303                 if (argv[optind] == NULL)
304                         bb_show_usage();
305                 if (opt & CPIO_OPT_CREATE_LEADING_DIR)
306                         mkdir(argv[optind], 0777);
307                 /* Crude existence check:
308                  * close(xopen(argv[optind], O_RDONLY | O_DIRECTORY));
309                  * We can also xopen, fstat, IS_DIR, later fchdir.
310                  * This would check for existence earlier and cleaner.
311                  * As it stands now, if we fail xchdir later,
312                  * child dies on EPIPE, unless it caught
313                  * a diffrerent problem earlier.
314                  * This is good enough for now.
315                  */
316 #if !BB_MMU
317                 pp.rd = 3;
318                 pp.wr = 4;
319                 if (!re_execed) {
320                         close(3);
321                         close(4);
322                         xpiped_pair(pp);
323                 }
324 #else
325                 xpiped_pair(pp);
326 #endif
327                 pid = fork_or_rexec(argv);
328                 if (pid == 0) { /* child */
329                         close(pp.rd);
330                         xmove_fd(pp.wr, STDOUT_FILENO);
331                         goto dump;
332                 }
333                 /* parent */
334                 xchdir(argv[optind++]);
335                 close(pp.wr);
336                 xmove_fd(pp.rd, STDIN_FILENO);
337                 opt &= ~CPIO_OPT_PASSTHROUGH;
338                 opt |= CPIO_OPT_EXTRACT;
339                 goto skip;
340         }
341         /* -o */
342         if (opt & CPIO_OPT_CREATE) {
343                 if (*cpio_fmt != 'n') /* we _require_ "-H newc" */
344                         bb_show_usage();
345                 if (opt & CPIO_OPT_FILE) {
346                         fclose(stdout);
347                         stdout = fopen_for_write(cpio_filename);
348                         /* Paranoia: I don't trust libc that much */
349                         xdup2(fileno(stdout), STDOUT_FILENO);
350                 }
351  dump:
352                 return cpio_o();
353         }
354  skip:
355 #endif
356         argv += optind;
357
358         archive_handle = init_handle();
359         archive_handle->src_fd = STDIN_FILENO;
360         archive_handle->seek = seek_by_read;
361         archive_handle->ah_flags = ARCHIVE_EXTRACT_NEWER;
362
363         /* One of either extract or test options must be given */
364         if ((opt & (CPIO_OPT_TEST | CPIO_OPT_EXTRACT)) == 0) {
365                 bb_show_usage();
366         }
367
368         if (opt & CPIO_OPT_TEST) {
369                 /* if both extract and test options are given, ignore extract option */
370                 opt &= ~CPIO_OPT_EXTRACT;
371                 archive_handle->action_header = header_list;
372         }
373         if (opt & CPIO_OPT_EXTRACT) {
374                 archive_handle->action_data = data_extract_all;
375         }
376         if (opt & CPIO_OPT_UNCONDITIONAL) {
377                 archive_handle->ah_flags |= ARCHIVE_EXTRACT_UNCONDITIONAL;
378                 archive_handle->ah_flags &= ~ARCHIVE_EXTRACT_NEWER;
379         }
380         if (opt & CPIO_OPT_VERBOSE) {
381                 if (archive_handle->action_header == header_list) {
382                         archive_handle->action_header = header_verbose_list;
383                 } else {
384                         archive_handle->action_header = header_list;
385                 }
386         }
387         if (opt & CPIO_OPT_FILE) { /* -F */
388                 archive_handle->src_fd = xopen(cpio_filename, O_RDONLY);
389                 archive_handle->seek = seek_by_jump;
390         }
391         if (opt & CPIO_OPT_CREATE_LEADING_DIR) {
392                 archive_handle->ah_flags |= ARCHIVE_CREATE_LEADING_DIRS;
393         }
394         if (opt & CPIO_OPT_PRESERVE_MTIME) {
395                 archive_handle->ah_flags |= ARCHIVE_PRESERVE_DATE;
396         }
397
398         while (*argv) {
399                 archive_handle->filter = filter_accept_list;
400                 llist_add_to(&(archive_handle->accept), *argv);
401                 argv++;
402         }
403
404         /* see get_header_cpio */
405         archive_handle->ah_priv[2] = (void*) ~(ptrdiff_t)0;
406         while (get_header_cpio(archive_handle) == EXIT_SUCCESS)
407                 continue;
408
409         if (archive_handle->ah_priv[2] != (void*) ~(ptrdiff_t)0)
410                 printf("%lu blocks\n", (unsigned long)(ptrdiff_t)(archive_handle->ah_priv[2]));
411
412         return EXIT_SUCCESS;
413 }