whitespace fixes, no code changed
[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         struct name_s {
34                 struct name_s *next;
35                 char name[1];
36         };
37         struct inodes_s {
38                 struct inodes_s *next;
39                 struct name_s *names;
40                 struct stat st;
41         };
42
43         struct inodes_s *links = NULL;
44         off_t bytes = 0; /* output bytes count */
45
46         while (1) {
47                 const char *name;
48                 char *line;
49                 struct stat st;
50
51                 line = xmalloc_fgetline(stdin);
52
53                 if (line) {
54                         /* Strip leading "./[./]..." from the filename */
55                         name = line;
56                         while (name[0] == '.' && name[1] == '/') {
57                                 while (*++name == '/')
58                                         continue;
59                         }
60                         if (!*name) { /* line is empty */
61                                 free(line);
62                                 continue;
63                         }
64                         if (lstat(name, &st)) {
65  abort_cpio_o:
66                                 bb_simple_perror_msg_and_die(name);
67                         }
68
69                         if (!(S_ISLNK(st.st_mode) || S_ISREG(st.st_mode)))
70                                 st.st_size = 0; /* paranoia */
71
72                         /* Store hardlinks for later processing, dont output them */
73                         if (!S_ISDIR(st.st_mode) && st.st_nlink > 1) {
74                                 struct name_s *n;
75                                 struct inodes_s *l;
76
77                                 /* Do we have this hardlink remembered? */
78                                 l = links;
79                                 while (1) {
80                                         if (l == NULL) {
81                                                 /* Not found: add new item to "links" list */
82                                                 l = xzalloc(sizeof(*l));
83                                                 l->st = st;
84                                                 l->next = links;
85                                                 links = l;
86                                                 break;
87                                         }
88                                         if (l->st.st_ino == st.st_ino) {
89                                                 /* found */
90                                                 break;
91                                         }
92                                         l = l->next;
93                                 }
94                                 /* Add new name to "l->names" list */
95                                 n = xmalloc(sizeof(*n) + strlen(name));
96                                 strcpy(n->name, name);
97                                 n->next = l->names;
98                                 l->names = n;
99
100                                 free(line);
101                                 continue;
102                         }
103
104                 } else { /* line == NULL: EOF */
105  next_link:
106                         if (links) {
107                                 /* Output hardlink's data */
108                                 st = links->st;
109                                 name = links->names->name;
110                                 links->names = links->names->next;
111                                 /* GNU cpio is reported to emit file data
112                                  * only for the last instance. Mimic that. */
113                                 if (links->names == NULL)
114                                         links = links->next;
115                                 else
116                                         st.st_size = 0;
117                                 /* NB: we leak links->names and/or links,
118                                  * this is intended (we exit soon anyway) */
119                         } else {
120                                 /* If no (more) hardlinks to output,
121                                  * output "trailer" entry */
122                                 name = "TRAILER!!!";
123                                 /* st.st_size == 0 is a must, but for uniformity
124                                  * in the output, we zero out everything */
125                                 memset(&st, 0, sizeof(st));
126                                 /* st.st_nlink = 1; - GNU cpio does this */
127                         }
128                 }
129
130                 bytes += printf("070701"
131                                 "%08X%08X%08X%08X%08X%08X%08X"
132                                 "%08X%08X%08X%08X" /* GNU cpio uses uppercase hex */
133                                 /* strlen+1: */ "%08X"
134                                 /* chksum: */   "00000000" /* (only for "070702" files) */
135                                 /* name,NUL: */ "%s%c",
136                                 (unsigned)(uint32_t) st.st_ino,
137                                 (unsigned)(uint32_t) st.st_mode,
138                                 (unsigned)(uint32_t) st.st_uid,
139                                 (unsigned)(uint32_t) st.st_gid,
140                                 (unsigned)(uint32_t) st.st_nlink,
141                                 (unsigned)(uint32_t) st.st_mtime,
142                                 (unsigned)(uint32_t) st.st_size,
143                                 (unsigned)(uint32_t) major(st.st_dev),
144                                 (unsigned)(uint32_t) minor(st.st_dev),
145                                 (unsigned)(uint32_t) major(st.st_rdev),
146                                 (unsigned)(uint32_t) minor(st.st_rdev),
147                                 (unsigned)(strlen(name) + 1),
148                                 name, '\0');
149                 bytes = cpio_pad4(bytes);
150
151                 if (st.st_size) {
152                         if (S_ISLNK(st.st_mode)) {
153                                 char *lpath = xmalloc_readlink_or_warn(name);
154                                 if (!lpath)
155                                         goto abort_cpio_o;
156                                 bytes += printf("%s", lpath);
157                                 free(lpath);
158                         } else { /* S_ISREG */
159                                 int fd = xopen(name, O_RDONLY);
160                                 fflush(stdout);
161                                 /* We must abort if file got shorter too! */
162                                 bb_copyfd_exact_size(fd, STDOUT_FILENO, st.st_size);
163                                 bytes += st.st_size;
164                                 close(fd);
165                         }
166                         bytes = cpio_pad4(bytes);
167                 }
168
169                 if (!line) {
170                         if (links)
171                                 goto next_link;
172                         /* TODO: GNU cpio pads trailer to 512 bytes, do we want that? */
173                         return EXIT_SUCCESS;
174                 }
175
176                 free(line);
177         } /* end of "while (1)" */
178 }
179 #endif
180
181 /* GNU cpio 2.9 --help (abridged):
182
183  Modes:
184   -i, --extract              Extract files from an archive
185   -o, --create               Create the archive
186   -p, --pass-through         Copy-pass mode [was ist das?!]
187   -t, --list                 List the archive
188
189  Options valid in any mode:
190       --block-size=SIZE      I/O block size = SIZE * 512 bytes
191   -B                         I/O block size = 5120 bytes
192   -c                         Use the old portable (ASCII) archive format
193   -C, --io-size=NUMBER       I/O block size in bytes
194   -f, --nonmatching          Only copy files that do not match given pattern
195   -F, --file=FILE            Use FILE instead of standard input or output
196   -H, --format=FORMAT        Use given archive FORMAT
197   -M, --message=STRING       Print STRING when the end of a volume of the
198                              backup media is reached
199   -n, --numeric-uid-gid      If -v, show numeric UID and GID
200       --quiet                Do not print the number of blocks copied
201       --rsh-command=COMMAND  Use remote COMMAND instead of rsh
202   -v, --verbose              Verbosely list the files processed
203   -V, --dot                  Print a "." for each file processed
204   -W, --warning=FLAG         Control warning display: 'none','truncate','all';
205                              multiple options accumulate
206
207  Options valid only in --extract mode:
208   -b, --swap                 Swap both halfwords of words and bytes of
209                              halfwords in the data (equivalent to -sS)
210   -r, --rename               Interactively rename files
211   -s, --swap-bytes           Swap the bytes of each halfword in the files
212   -S, --swap-halfwords       Swap the halfwords of each word (4 bytes)
213       --to-stdout            Extract files to standard output
214   -E, --pattern-file=FILE    Read additional patterns specifying filenames to
215                              extract or list from FILE
216       --only-verify-crc      Verify CRC's, don't actually extract the files
217
218  Options valid only in --create mode:
219   -A, --append               Append to an existing archive
220   -O FILE                    File to use instead of standard output
221
222  Options valid only in --pass-through mode:
223   -l, --link                 Link files instead of copying them, when possible
224
225  Options valid in --extract and --create modes:
226       --absolute-filenames   Do not strip file system prefix components from
227                              the file names
228       --no-absolute-filenames Create all files relative to the current dir
229
230  Options valid in --create and --pass-through modes:
231   -0, --null                 A list of filenames is terminated by a NUL
232   -a, --reset-access-time    Reset the access times of files after reading them
233   -I FILE                    File to use instead of standard input
234   -L, --dereference          Dereference symbolic links (copy the files
235                              that they point to instead of copying the links)
236   -R, --owner=[USER][:.][GROUP] Set owner of created files
237
238  Options valid in --extract and --pass-through modes:
239   -d, --make-directories     Create leading directories where needed
240   -m, --preserve-modification-time  Retain mtime when creating files
241       --no-preserve-owner    Do not change the ownership of the files
242       --sparse               Write files with blocks of zeros as sparse files
243   -u, --unconditional        Replace all files unconditionally
244  */
245
246 int cpio_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
247 int cpio_main(int argc UNUSED_PARAM, char **argv)
248 {
249         archive_handle_t *archive_handle;
250         char *cpio_filename;
251         USE_FEATURE_CPIO_O(const char *cpio_fmt = "";)
252         unsigned opt;
253         enum {
254                 CPIO_OPT_EXTRACT            = (1 << 0),
255                 CPIO_OPT_TEST               = (1 << 1),
256                 CPIO_OPT_UNCONDITIONAL      = (1 << 2),
257                 CPIO_OPT_VERBOSE            = (1 << 3),
258                 CPIO_OPT_FILE               = (1 << 4),
259                 CPIO_OPT_CREATE_LEADING_DIR = (1 << 5),
260                 CPIO_OPT_PRESERVE_MTIME     = (1 << 6),
261                 CPIO_OPT_CREATE             = (1 << 7),
262                 CPIO_OPT_FORMAT             = (1 << 8),
263         };
264
265 #if ENABLE_GETOPT_LONG
266         applet_long_options =
267                 "extract\0"      No_argument       "i"
268                 "list\0"         No_argument       "t"
269 #if ENABLE_FEATURE_CPIO_O
270                 "create\0"       No_argument       "o"
271                 "format\0"       Required_argument "H"
272 #endif
273                 ;
274 #endif
275
276         /* Initialize */
277         archive_handle = init_handle();
278         archive_handle->src_fd = STDIN_FILENO;
279         archive_handle->seek = seek_by_read;
280         archive_handle->ah_flags = ARCHIVE_EXTRACT_NEWER;
281
282 #if ENABLE_FEATURE_CPIO_O
283         opt = getopt32(argv, "ituvF:dmoH:", &cpio_filename, &cpio_fmt);
284
285         if (opt & CPIO_OPT_CREATE) {
286                 if (*cpio_fmt != 'n')
287                         bb_show_usage();
288                 if (opt & CPIO_OPT_FILE) {
289                         fclose(stdout);
290                         stdout = fopen(cpio_filename, "w");
291                         /* Paranoia: I don't trust libc that much */
292                         xdup2(fileno(stdout), STDOUT_FILENO);
293                 }
294                 return cpio_o();
295         }
296 #else
297         opt = getopt32(argv, "ituvF:dm", &cpio_filename);
298 #endif
299         argv += optind;
300
301         /* One of either extract or test options must be given */
302         if ((opt & (CPIO_OPT_TEST | CPIO_OPT_EXTRACT)) == 0) {
303                 bb_show_usage();
304         }
305
306         if (opt & CPIO_OPT_TEST) {
307                 /* if both extract and test options are given, ignore extract option */
308                 if (opt & CPIO_OPT_EXTRACT) {
309                         opt &= ~CPIO_OPT_EXTRACT;
310                 }
311                 archive_handle->action_header = header_list;
312         }
313         if (opt & CPIO_OPT_EXTRACT) {
314                 archive_handle->action_data = data_extract_all;
315         }
316         if (opt & CPIO_OPT_UNCONDITIONAL) {
317                 archive_handle->ah_flags |= ARCHIVE_EXTRACT_UNCONDITIONAL;
318                 archive_handle->ah_flags &= ~ARCHIVE_EXTRACT_NEWER;
319         }
320         if (opt & CPIO_OPT_VERBOSE) {
321                 if (archive_handle->action_header == header_list) {
322                         archive_handle->action_header = header_verbose_list;
323                 } else {
324                         archive_handle->action_header = header_list;
325                 }
326         }
327         if (opt & CPIO_OPT_FILE) { /* -F */
328                 archive_handle->src_fd = xopen(cpio_filename, O_RDONLY);
329                 archive_handle->seek = seek_by_jump;
330         }
331         if (opt & CPIO_OPT_CREATE_LEADING_DIR) {
332                 archive_handle->ah_flags |= ARCHIVE_CREATE_LEADING_DIRS;
333         }
334         if (opt & CPIO_OPT_PRESERVE_MTIME) {
335                 archive_handle->ah_flags |= ARCHIVE_PRESERVE_DATE;
336         }
337
338         while (*argv) {
339                 archive_handle->filter = filter_accept_list;
340                 llist_add_to(&(archive_handle->accept), *argv);
341                 argv++;
342         }
343
344         while (get_header_cpio(archive_handle) == EXIT_SUCCESS)
345                 continue;
346
347         return EXIT_SUCCESS;
348 }