Compatibility fixes:
[oweals/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 #if ENABLE_FEATURE_CPIO_O
18 static off_t cpio_pad4(off_t size)
19 {
20         int i;
21
22         i = (- size) & 3;
23         size += i;
24         while (--i >= 0)
25                 bb_putchar('\0');
26         return size;
27 }
28
29 /* Return value will become exit code.
30  * It's ok to exit instead of return. */
31 static int cpio_o(void)
32 {
33         static const char trailer[] ALIGN1 = "TRAILER!!!";
34         struct name_s {
35                 struct name_s *next;
36                 char name[1];
37         };
38         struct inodes_s {
39                 struct inodes_s *next;
40                 struct name_s *names;
41                 struct stat st;
42         };
43
44         struct inodes_s *links = NULL;
45         off_t bytes = 0; /* output bytes count */
46
47         while (1) {
48                 const char *name;
49                 char *line;
50                 struct stat st;
51
52                 line = xmalloc_fgetline(stdin);
53
54                 if (line) {
55                         /* Strip leading "./[./]..." from the filename */
56                         name = line;
57                         while (name[0] == '.' && name[1] == '/') {
58                                 while (*++name == '/')
59                                         continue;
60                         }
61                         if (!*name) { /* line is empty */
62                                 free(line);
63                                 continue;
64                         }
65                         if (lstat(name, &st)) {
66  abort_cpio_o:
67                                 bb_simple_perror_msg_and_die(name);
68                         }
69
70                         if (!(S_ISLNK(st.st_mode) || S_ISREG(st.st_mode)))
71                                 st.st_size = 0; /* paranoia */
72
73                         /* Store hardlinks for later processing, dont output them */
74                         if (!S_ISDIR(st.st_mode) && st.st_nlink > 1) {
75                                 struct name_s *n;
76                                 struct inodes_s *l;
77
78                                 /* Do we have this hardlink remembered? */
79                                 l = links;
80                                 while (1) {
81                                         if (l == NULL) {
82                                                 /* Not found: add new item to "links" list */
83                                                 l = xzalloc(sizeof(*l));
84                                                 l->st = st;
85                                                 l->next = links;
86                                                 links = l;
87                                                 break;
88                                         }
89                                         if (l->st.st_ino == st.st_ino) {
90                                                 /* found */
91                                                 break;
92                                         }
93                                         l = l->next;
94                                 }
95                                 /* Add new name to "l->names" list */
96                                 n = xmalloc(sizeof(*n) + strlen(name));
97                                 strcpy(n->name, name);
98                                 n->next = l->names;
99                                 l->names = n;
100
101                                 free(line);
102                                 continue;
103                         }
104
105                 } else { /* line == NULL: EOF */
106  next_link:
107                         if (links) {
108                                 /* Output hardlink's data */
109                                 st = links->st;
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)
115                                         links = links->next;
116                                 else
117                                         st.st_size = 0;
118                                 /* NB: we leak links->names and/or links,
119                                  * this is intended (we exit soon anyway) */
120                         } else {
121                                 /* If no (more) hardlinks to output,
122                                  * output "trailer" entry */
123                                 name = trailer;
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 */
128                         }
129                 }
130
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),
149                                 name, '\0');
150                 bytes = cpio_pad4(bytes);
151
152                 if (st.st_size) {
153                         if (S_ISLNK(st.st_mode)) {
154                                 char *lpath = xmalloc_readlink_or_warn(name);
155                                 if (!lpath)
156                                         goto abort_cpio_o;
157                                 bytes += printf("%s", lpath);
158                                 free(lpath);
159                         } else { /* S_ISREG */
160                                 int fd = xopen(name, O_RDONLY);
161                                 fflush(stdout);
162                                 /* We must abort if file got shorter too! */
163                                 bb_copyfd_exact_size(fd, STDOUT_FILENO, st.st_size);
164                                 bytes += st.st_size;
165                                 close(fd);
166                         }
167                         bytes = cpio_pad4(bytes);
168                 }
169
170                 if (!line) {
171                         if (name != trailer)
172                                 goto next_link;
173                         /* TODO: GNU cpio pads trailer to 512 bytes, do we want that? */
174                         return EXIT_SUCCESS;
175                 }
176
177                 free(line);
178         } /* end of "while (1)" */
179 }
180 #endif
181
182 /* GNU cpio 2.9 --help (abridged):
183
184  Modes:
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
189
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
207
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
218
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
222
223  Options valid only in --pass-through mode:
224   -l, --link                 Link files instead of copying them, when possible
225
226  Options valid in --extract and --create modes:
227       --absolute-filenames   Do not strip file system prefix components from
228                              the file names
229       --no-absolute-filenames Create all files relative to the current dir
230
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
238
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
245  */
246
247 int cpio_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
248 int cpio_main(int argc UNUSED_PARAM, char **argv)
249 {
250         archive_handle_t *archive_handle;
251         char *cpio_filename;
252         USE_FEATURE_CPIO_O(const char *cpio_fmt = "";)
253         unsigned opt;
254         enum {
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) * ENABLE_FEATURE_CPIO_O,
263                 CPIO_OPT_FORMAT             = (1 << 8) * ENABLE_FEATURE_CPIO_O,
264                 CPIO_OPT_PASSTHROUGH        = (1 << 9) * ENABLE_FEATURE_CPIO_P,
265         };
266
267 #if ENABLE_GETOPT_LONG
268         applet_long_options =
269                 "extract\0"      No_argument       "i"
270                 "list\0"         No_argument       "t"
271 #if ENABLE_FEATURE_CPIO_O
272                 "create\0"       No_argument       "o"
273                 "format\0"       Required_argument "H"
274 #if ENABLE_FEATURE_CPIO_P
275                 "pass-through\0" No_argument       "p"
276 #endif
277 #endif
278                 ;
279 #endif
280
281         /* As of now we do not enforce this: */
282         /* -i,-t,-o,-p are mutually exclusive */
283         /* -u,-d,-m make sense only with -i or -p */
284         /* -F makes sense only with -o */
285 #if !ENABLE_FEATURE_CPIO_O
286         opt = getopt32(argv, "ituvF:dm", &cpio_filename);
287 #else
288         opt = getopt32(argv, "ituvF:dmoH:" USE_FEATURE_CPIO_P("p"), &cpio_filename, &cpio_fmt);
289         if (opt & CPIO_OPT_PASSTHROUGH) {
290                 pid_t pid;
291                 struct fd_pair pp;
292
293                 if (argv[optind] == NULL)
294                         bb_show_usage();
295                 if (opt & CPIO_OPT_CREATE_LEADING_DIR)
296                         mkdir(argv[optind], 0777);
297                 /* Crude existence check:
298                  * close(xopen(argv[optind], O_RDONLY | O_DIRECTORY));
299                  * We can also xopen, fstat, IS_DIR, later fchdir.
300                  * This would check for existence earlier and cleaner.
301                  * As it stands now, if we fail xchdir later,
302                  * child dies on EPIPE, unless it caught
303                  * a diffrerent problem earlier.
304                  * This is good enough for now.
305                  */
306 #if !BB_MMU
307                 pp.rd = 3;
308                 pp.wr = 4;
309                 if (!re_execed) {
310                         close(3);
311                         close(4);
312                         xpiped_pair(pp);
313                 }
314 #else
315                 xpiped_pair(pp);
316 #endif
317                 pid = fork_or_rexec(argv);
318                 if (pid == 0) { /* child */
319                         close(pp.rd);
320                         xmove_fd(pp.wr, STDOUT_FILENO);
321                         goto dump;
322                 }
323                 /* parent */
324                 xchdir(argv[optind++]);
325                 close(pp.wr);
326                 xmove_fd(pp.rd, STDIN_FILENO);
327                 opt &= ~CPIO_OPT_PASSTHROUGH;
328                 opt |= CPIO_OPT_EXTRACT;
329                 goto skip;
330         }
331         /* -o */
332         if (opt & CPIO_OPT_CREATE) {
333                 if (*cpio_fmt != 'n') /* we _require_ "-H newc" */
334                         bb_show_usage();
335                 if (opt & CPIO_OPT_FILE) {
336                         fclose(stdout);
337                         stdout = fopen_for_write(cpio_filename);
338                         /* Paranoia: I don't trust libc that much */
339                         xdup2(fileno(stdout), STDOUT_FILENO);
340                 }
341  dump:
342                 return cpio_o();
343         }
344  skip:
345 #endif
346         argv += optind;
347
348         archive_handle = init_handle();
349         archive_handle->src_fd = STDIN_FILENO;
350         archive_handle->seek = seek_by_read;
351         archive_handle->ah_flags = ARCHIVE_EXTRACT_NEWER;
352
353         /* One of either extract or test options must be given */
354         if ((opt & (CPIO_OPT_TEST | CPIO_OPT_EXTRACT)) == 0) {
355                 bb_show_usage();
356         }
357
358         if (opt & CPIO_OPT_TEST) {
359                 /* if both extract and test options are given, ignore extract option */
360                 opt &= ~CPIO_OPT_EXTRACT;
361                 archive_handle->action_header = header_list;
362         }
363         if (opt & CPIO_OPT_EXTRACT) {
364                 archive_handle->action_data = data_extract_all;
365         }
366         if (opt & CPIO_OPT_UNCONDITIONAL) {
367                 archive_handle->ah_flags |= ARCHIVE_EXTRACT_UNCONDITIONAL;
368                 archive_handle->ah_flags &= ~ARCHIVE_EXTRACT_NEWER;
369         }
370         if (opt & CPIO_OPT_VERBOSE) {
371                 if (archive_handle->action_header == header_list) {
372                         archive_handle->action_header = header_verbose_list;
373                 } else {
374                         archive_handle->action_header = header_list;
375                 }
376         }
377         if (opt & CPIO_OPT_FILE) { /* -F */
378                 archive_handle->src_fd = xopen(cpio_filename, O_RDONLY);
379                 archive_handle->seek = seek_by_jump;
380         }
381         if (opt & CPIO_OPT_CREATE_LEADING_DIR) {
382                 archive_handle->ah_flags |= ARCHIVE_CREATE_LEADING_DIRS;
383         }
384         if (opt & CPIO_OPT_PRESERVE_MTIME) {
385                 archive_handle->ah_flags |= ARCHIVE_PRESERVE_DATE;
386         }
387
388         while (*argv) {
389                 archive_handle->filter = filter_accept_list;
390                 llist_add_to(&(archive_handle->accept), *argv);
391                 argv++;
392         }
393
394         /* see get_header_cpio */
395         archive_handle->ah_priv[2] = (void*) ~(ptrdiff_t)0;
396         while (get_header_cpio(archive_handle) == EXIT_SUCCESS)
397                 continue;
398
399         if (archive_handle->ah_priv[2] != (void*) ~(ptrdiff_t)0)
400                 printf("%lu blocks\n", (unsigned long)(ptrdiff_t)(archive_handle->ah_priv[2]));
401
402         return EXIT_SUCCESS;
403 }