Magellan Linux

Diff of /trunk/mkinitrd-magellan/busybox/archival/cpio.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 532 by niro, Sat Sep 1 22:45:15 2007 UTC revision 984 by niro, Sun May 30 11:32:42 2010 UTC
# Line 7  Line 7 
7   * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.   * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8   *   *
9   * Limitations:   * Limitations:
10   * Doesn't check CRC's   * Doesn't check CRC's
11   * Only supports new ASCII and CRC formats   * Only supports new ASCII and CRC formats
12   *   *
13   */   */
14  #include <fcntl.h>  #include "libbb.h"
 #include <stdlib.h>  
 #include <string.h>  
 #include <unistd.h>  
15  #include "unarchive.h"  #include "unarchive.h"
 #include "busybox.h"  
16    
17  #define CPIO_OPT_EXTRACT 0x01  /* GNU cpio 2.9 --help (abridged):
 #define CPIO_OPT_TEST 0x02  
 #define CPIO_OPT_UNCONDITIONAL 0x04  
 #define CPIO_OPT_VERBOSE 0x08  
 #define CPIO_OPT_FILE 0x10  
 #define CPIO_OPT_CREATE_LEADING_DIR 0x20  
 #define CPIO_OPT_PRESERVE_MTIME 0x40  
18    
19  int cpio_main(int argc, char **argv)   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     OPTBIT_FILE = 8,
92     IF_FEATURE_CPIO_O(OPTBIT_CREATE     ,)
93     IF_FEATURE_CPIO_O(OPTBIT_FORMAT     ,)
94     IF_FEATURE_CPIO_P(OPTBIT_PASSTHROUGH,)
95     IF_LONG_OPTS(     OPTBIT_QUIET      ,)
96     IF_LONG_OPTS(     OPTBIT_2STDOUT    ,)
97     CPIO_OPT_CREATE             = IF_FEATURE_CPIO_O((1 << OPTBIT_CREATE     )) + 0,
98     CPIO_OPT_FORMAT             = IF_FEATURE_CPIO_O((1 << OPTBIT_FORMAT     )) + 0,
99     CPIO_OPT_PASSTHROUGH        = IF_FEATURE_CPIO_P((1 << OPTBIT_PASSTHROUGH)) + 0,
100     CPIO_OPT_QUIET              = IF_LONG_OPTS(     (1 << OPTBIT_QUIET      )) + 0,
101     CPIO_OPT_2STDOUT            = IF_LONG_OPTS(     (1 << OPTBIT_2STDOUT    )) + 0,
102    };
103    
104    #define OPTION_STR "it0uvdmLF:"
105    
106    #if ENABLE_FEATURE_CPIO_O
107    static off_t cpio_pad4(off_t size)
108    {
109     int i;
110    
111     i = (- size) & 3;
112     size += i;
113     while (--i >= 0)
114     bb_putchar('\0');
115     return size;
116    }
117    
118    /* Return value will become exit code.
119     * It's ok to exit instead of return. */
120    static NOINLINE int cpio_o(void)
121    {
122     static const char trailer[] ALIGN1 = "TRAILER!!!";
123     struct name_s {
124     struct name_s *next;
125     char name[1];
126     };
127     struct inodes_s {
128     struct inodes_s *next;
129     struct name_s *names;
130     struct stat st;
131     };
132    
133     struct inodes_s *links = NULL;
134     off_t bytes = 0; /* output bytes count */
135    
136     while (1) {
137     const char *name;
138     char *line;
139     struct stat st;
140    
141     line = (option_mask32 & CPIO_OPT_NUL_TERMINATED)
142     ? bb_get_chunk_from_file(stdin, NULL)
143     : xmalloc_fgetline(stdin);
144    
145     if (line) {
146     /* Strip leading "./[./]..." from the filename */
147     name = line;
148     while (name[0] == '.' && name[1] == '/') {
149     while (*++name == '/')
150     continue;
151     }
152     if (!*name) { /* line is empty */
153     free(line);
154     continue;
155     }
156     if ((option_mask32 & CPIO_OPT_DEREF)
157     ? stat(name, &st)
158     : lstat(name, &st)
159     ) {
160     abort_cpio_o:
161     bb_simple_perror_msg_and_die(name);
162     }
163    
164     if (!(S_ISLNK(st.st_mode) || S_ISREG(st.st_mode)))
165     st.st_size = 0; /* paranoia */
166    
167     /* Store hardlinks for later processing, dont output them */
168     if (!S_ISDIR(st.st_mode) && st.st_nlink > 1) {
169     struct name_s *n;
170     struct inodes_s *l;
171    
172     /* Do we have this hardlink remembered? */
173     l = links;
174     while (1) {
175     if (l == NULL) {
176     /* Not found: add new item to "links" list */
177     l = xzalloc(sizeof(*l));
178     l->st = st;
179     l->next = links;
180     links = l;
181     break;
182     }
183     if (l->st.st_ino == st.st_ino) {
184     /* found */
185     break;
186     }
187     l = l->next;
188     }
189     /* Add new name to "l->names" list */
190     n = xmalloc(sizeof(*n) + strlen(name));
191     strcpy(n->name, name);
192     n->next = l->names;
193     l->names = n;
194    
195     free(line);
196     continue;
197     }
198    
199     } else { /* line == NULL: EOF */
200     next_link:
201     if (links) {
202     /* Output hardlink's data */
203     st = links->st;
204     name = links->names->name;
205     links->names = links->names->next;
206     /* GNU cpio is reported to emit file data
207     * only for the last instance. Mimic that. */
208     if (links->names == NULL)
209     links = links->next;
210     else
211     st.st_size = 0;
212     /* NB: we leak links->names and/or links,
213     * this is intended (we exit soon anyway) */
214     } else {
215     /* If no (more) hardlinks to output,
216     * output "trailer" entry */
217     name = trailer;
218     /* st.st_size == 0 is a must, but for uniformity
219     * in the output, we zero out everything */
220     memset(&st, 0, sizeof(st));
221     /* st.st_nlink = 1; - GNU cpio does this */
222     }
223     }
224    
225     bytes += printf("070701"
226                    "%08X%08X%08X%08X%08X%08X%08X"
227                    "%08X%08X%08X%08X" /* GNU cpio uses uppercase hex */
228     /* strlen+1: */ "%08X"
229     /* chksum: */   "00000000" /* (only for "070702" files) */
230     /* name,NUL: */ "%s%c",
231                    (unsigned)(uint32_t) st.st_ino,
232                    (unsigned)(uint32_t) st.st_mode,
233                    (unsigned)(uint32_t) st.st_uid,
234                    (unsigned)(uint32_t) st.st_gid,
235                    (unsigned)(uint32_t) st.st_nlink,
236                    (unsigned)(uint32_t) st.st_mtime,
237                    (unsigned)(uint32_t) st.st_size,
238                    (unsigned)(uint32_t) major(st.st_dev),
239                    (unsigned)(uint32_t) minor(st.st_dev),
240                    (unsigned)(uint32_t) major(st.st_rdev),
241                    (unsigned)(uint32_t) minor(st.st_rdev),
242                    (unsigned)(strlen(name) + 1),
243                    name, '\0');
244     bytes = cpio_pad4(bytes);
245    
246     if (st.st_size) {
247     if (S_ISLNK(st.st_mode)) {
248     char *lpath = xmalloc_readlink_or_warn(name);
249     if (!lpath)
250     goto abort_cpio_o;
251     bytes += printf("%s", lpath);
252     free(lpath);
253     } else { /* S_ISREG */
254     int fd = xopen(name, O_RDONLY);
255     fflush_all();
256     /* We must abort if file got shorter too! */
257     bb_copyfd_exact_size(fd, STDOUT_FILENO, st.st_size);
258     bytes += st.st_size;
259     close(fd);
260     }
261     bytes = cpio_pad4(bytes);
262     }
263    
264     if (!line) {
265     if (name != trailer)
266     goto next_link;
267     /* TODO: GNU cpio pads trailer to 512 bytes, do we want that? */
268     return EXIT_SUCCESS;
269     }
270    
271     free(line);
272     } /* end of "while (1)" */
273    }
274    #endif
275    
276    int cpio_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
277    int cpio_main(int argc UNUSED_PARAM, char **argv)
278  {  {
279   archive_handle_t *archive_handle;   archive_handle_t *archive_handle;
280   char *cpio_filename = NULL;   char *cpio_filename;
281     IF_FEATURE_CPIO_O(const char *cpio_fmt = "";)
282   unsigned opt;   unsigned opt;
283    
284   /* Initialise */  #if ENABLE_LONG_OPTS
285     applet_long_options =
286     "extract\0"      No_argument       "i"
287     "list\0"         No_argument       "t"
288    #if ENABLE_FEATURE_CPIO_O
289     "create\0"       No_argument       "o"
290     "format\0"       Required_argument "H"
291    #if ENABLE_FEATURE_CPIO_P
292     "pass-through\0" No_argument       "p"
293    #endif
294    #endif
295     "verbose\0"      No_argument       "v"
296     "quiet\0"        No_argument       "\xff"
297     "to-stdout\0"    No_argument       "\xfe"
298     ;
299    #endif
300    
301   archive_handle = init_handle();   archive_handle = init_handle();
302   archive_handle->src_fd = STDIN_FILENO;   /* archive_handle->src_fd = STDIN_FILENO; - done by init_handle */
303   archive_handle->seek = seek_by_read;   archive_handle->ah_flags = ARCHIVE_EXTRACT_NEWER;
304   archive_handle->flags = ARCHIVE_EXTRACT_NEWER | ARCHIVE_PRESERVE_DATE;  
305     /* As of now we do not enforce this: */
306     /* -i,-t,-o,-p are mutually exclusive */
307     /* -u,-d,-m make sense only with -i or -p */
308     /* -L makes sense only with -o or -p */
309    
310    #if !ENABLE_FEATURE_CPIO_O
311     /* no parameters */
312     opt_complementary = "=0";
313     opt = getopt32(argv, OPTION_STR, &cpio_filename);
314     if (opt & CPIO_OPT_FILE) { /* -F */
315     xmove_fd(xopen(cpio_filename, O_RDONLY), STDIN_FILENO);
316     }
317    #else
318     /* _exactly_ one parameter for -p, thus <= 1 param if -p is allowed */
319     opt_complementary = ENABLE_FEATURE_CPIO_P ? "?1" : "=0";
320     opt = getopt32(argv, OPTION_STR "oH:" IF_FEATURE_CPIO_P("p"), &cpio_filename, &cpio_fmt);
321     argv += optind;
322     if ((opt & (CPIO_OPT_FILE|CPIO_OPT_CREATE)) == CPIO_OPT_FILE) { /* -F without -o */
323     xmove_fd(xopen(cpio_filename, O_RDONLY), STDIN_FILENO);
324     }
325     if (opt & CPIO_OPT_PASSTHROUGH) {
326     pid_t pid;
327     struct fd_pair pp;
328    
329   opt = getopt32(argc, argv, "ituvF:dm", &cpio_filename);   if (argv[0] == NULL)
330     bb_show_usage();
331     if (opt & CPIO_OPT_CREATE_LEADING_DIR)
332     mkdir(argv[0], 0777);
333     /* Crude existence check:
334     * close(xopen(argv[0], O_RDONLY | O_DIRECTORY));
335     * We can also xopen, fstat, IS_DIR, later fchdir.
336     * This would check for existence earlier and cleaner.
337     * As it stands now, if we fail xchdir later,
338     * child dies on EPIPE, unless it caught
339     * a diffrerent problem earlier.
340     * This is good enough for now.
341     */
342    #if !BB_MMU
343     pp.rd = 3;
344     pp.wr = 4;
345     if (!re_execed) {
346     close(3);
347     close(4);
348     xpiped_pair(pp);
349     }
350    #else
351     xpiped_pair(pp);
352    #endif
353     pid = fork_or_rexec(argv - optind);
354     if (pid == 0) { /* child */
355     close(pp.rd);
356     xmove_fd(pp.wr, STDOUT_FILENO);
357     goto dump;
358     }
359     /* parent */
360     xchdir(*argv++);
361     close(pp.wr);
362     xmove_fd(pp.rd, STDIN_FILENO);
363     //opt &= ~CPIO_OPT_PASSTHROUGH;
364     opt |= CPIO_OPT_EXTRACT;
365     goto skip;
366     }
367     /* -o */
368     if (opt & CPIO_OPT_CREATE) {
369     if (cpio_fmt[0] != 'n') /* we _require_ "-H newc" */
370     bb_show_usage();
371     if (opt & CPIO_OPT_FILE) {
372     xmove_fd(xopen3(cpio_filename, O_WRONLY | O_CREAT | O_TRUNC, 0666), STDOUT_FILENO);
373     }
374     dump:
375     return cpio_o();
376     }
377     skip:
378    #endif
379    
380   /* One of either extract or test options must be given */   /* One of either extract or test options must be given */
381   if ((opt & (CPIO_OPT_TEST | CPIO_OPT_EXTRACT)) == 0) {   if ((opt & (CPIO_OPT_TEST | CPIO_OPT_EXTRACT)) == 0) {
# Line 47  int cpio_main(int argc, char **argv) Line 384  int cpio_main(int argc, char **argv)
384    
385   if (opt & CPIO_OPT_TEST) {   if (opt & CPIO_OPT_TEST) {
386   /* if both extract and test options are given, ignore extract option */   /* if both extract and test options are given, ignore extract option */
387   if (opt & CPIO_OPT_EXTRACT) {   opt &= ~CPIO_OPT_EXTRACT;
  opt &= ~CPIO_OPT_EXTRACT;  
  }  
388   archive_handle->action_header = header_list;   archive_handle->action_header = header_list;
389   }   }
390   if (opt & CPIO_OPT_EXTRACT) {   if (opt & CPIO_OPT_EXTRACT) {
391   archive_handle->action_data = data_extract_all;   archive_handle->action_data = data_extract_all;
392     if (opt & CPIO_OPT_2STDOUT)
393     archive_handle->action_data = data_extract_to_stdout;
394   }   }
395   if (opt & CPIO_OPT_UNCONDITIONAL) {   if (opt & CPIO_OPT_UNCONDITIONAL) {
396   archive_handle->flags |= ARCHIVE_EXTRACT_UNCONDITIONAL;   archive_handle->ah_flags |= ARCHIVE_UNLINK_OLD;
397   archive_handle->flags &= ~ARCHIVE_EXTRACT_NEWER;   archive_handle->ah_flags &= ~ARCHIVE_EXTRACT_NEWER;
398   }   }
399   if (opt & CPIO_OPT_VERBOSE) {   if (opt & CPIO_OPT_VERBOSE) {
400   if (archive_handle->action_header == header_list) {   if (archive_handle->action_header == header_list) {
# Line 66  int cpio_main(int argc, char **argv) Line 403  int cpio_main(int argc, char **argv)
403   archive_handle->action_header = header_list;   archive_handle->action_header = header_list;
404   }   }
405   }   }
  if (cpio_filename) { /* CPIO_OPT_FILE */  
  archive_handle->src_fd = xopen(cpio_filename, O_RDONLY);  
  archive_handle->seek = seek_by_jump;  
  }  
406   if (opt & CPIO_OPT_CREATE_LEADING_DIR) {   if (opt & CPIO_OPT_CREATE_LEADING_DIR) {
407   archive_handle->flags |= ARCHIVE_CREATE_LEADING_DIRS;   archive_handle->ah_flags |= ARCHIVE_CREATE_LEADING_DIRS;
408     }
409     if (opt & CPIO_OPT_PRESERVE_MTIME) {
410     archive_handle->ah_flags |= ARCHIVE_RESTORE_DATE;
411   }   }
412    
413   while (optind < argc) {   while (*argv) {
414   archive_handle->filter = filter_accept_list;   archive_handle->filter = filter_accept_list;
415   llist_add_to(&(archive_handle->accept), argv[optind]);   llist_add_to(&archive_handle->accept, *argv);
416   optind++;   argv++;
417   }   }
418    
419   while (get_header_cpio(archive_handle) == EXIT_SUCCESS);   /* see get_header_cpio */
420     archive_handle->cpio__blocks = (off_t)-1;
421     while (get_header_cpio(archive_handle) == EXIT_SUCCESS)
422     continue;
423    
424     if (archive_handle->cpio__blocks != (off_t)-1
425     && !(opt & CPIO_OPT_QUIET)
426     ) {
427     printf("%"OFF_FMT"u blocks\n", archive_handle->cpio__blocks);
428     }
429    
430   return EXIT_SUCCESS;   return EXIT_SUCCESS;
431  }  }

Legend:
Removed from v.532  
changed lines
  Added in v.984