Annotation of /trunk/mkinitrd-magellan/klibc/usr/utils/cpio.c
Parent Directory | Revision Log
Revision 532 -
(hide annotations)
(download)
Sat Sep 1 22:45:15 2007 UTC (16 years, 8 months ago) by niro
File MIME type: text/plain
File size: 32979 byte(s)
Sat Sep 1 22:45:15 2007 UTC (16 years, 8 months ago) by niro
File MIME type: text/plain
File size: 32979 byte(s)
-import if magellan mkinitrd; it is a fork of redhats mkinitrd-5.0.8 with all magellan patches and features; deprecates magellan-src/mkinitrd
1 | niro | 532 | /* copyin.c - extract or list a cpio archive |
2 | Copyright (C) 1990,1991,1992,2001,2002,2003,2004 Free Software Foundation, Inc. | ||
3 | |||
4 | This program is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 2, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License along | ||
15 | with this program; if not, write to the Free Software Foundation, Inc., | ||
16 | 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ | ||
17 | |||
18 | #include <errno.h> | ||
19 | #include <fcntl.h> | ||
20 | #include <malloc.h> | ||
21 | #include <stdbool.h> | ||
22 | #include <stdio.h> | ||
23 | #include <stdlib.h> | ||
24 | #include <string.h> | ||
25 | #include <sys/types.h> | ||
26 | #include <sys/stat.h> | ||
27 | #include <time.h> | ||
28 | #include <unistd.h> | ||
29 | #include <utime.h> | ||
30 | #ifndef FNM_PATHNAME | ||
31 | #include <fnmatch.h> | ||
32 | #endif | ||
33 | |||
34 | #ifndef O_BINARY | ||
35 | # define O_BINARY 0 | ||
36 | #endif | ||
37 | |||
38 | # ifndef DIRECTORY_SEPARATOR | ||
39 | # define DIRECTORY_SEPARATOR '/' | ||
40 | # endif | ||
41 | |||
42 | # ifndef ISSLASH | ||
43 | # define ISSLASH(C) ((C) == DIRECTORY_SEPARATOR) | ||
44 | # endif | ||
45 | |||
46 | # ifndef FILE_SYSTEM_PREFIX_LEN | ||
47 | # define FILE_SYSTEM_PREFIX_LEN(Filename) 0 | ||
48 | # endif | ||
49 | |||
50 | #ifndef SYMLINK_USES_UMASK | ||
51 | # define UMASKED_SYMLINK(name1,name2,mode) symlink(name1,name2) | ||
52 | #else | ||
53 | # define UMASKED_SYMLINK(name1,name2,mode) umasked_symlink(name1,name2,mode) | ||
54 | #endif /* SYMLINK_USES_UMASK */ | ||
55 | |||
56 | /* Return 1 if an array of N objects, each of size S, cannot exist due | ||
57 | to size arithmetic overflow. S must be positive and N must be | ||
58 | nonnegative. This is a macro, not an inline function, so that it | ||
59 | works correctly even when SIZE_MAX < N. | ||
60 | |||
61 | By gnulib convention, SIZE_MAX represents overflow in size | ||
62 | calculations, so the conservative dividend to use here is | ||
63 | SIZE_MAX - 1, since SIZE_MAX might represent an overflowed value. | ||
64 | However, malloc (SIZE_MAX) fails on all known hosts where | ||
65 | sizeof (ptrdiff_t) <= sizeof (size_t), so do not bother to test for | ||
66 | exactly-SIZE_MAX allocations on such hosts; this avoids a test and | ||
67 | branch when S is known to be 1. */ | ||
68 | # define xalloc_oversized(n, s) \ | ||
69 | ((size_t) (sizeof (ptrdiff_t) <= sizeof (size_t) ? -1 : -2) / (s) < (n)) | ||
70 | |||
71 | #define DISK_IO_BLOCK_SIZE (512) | ||
72 | |||
73 | char *progname = NULL; | ||
74 | |||
75 | /* If true, print a . for each file processed. (-V) */ | ||
76 | char dot_flag = false; | ||
77 | |||
78 | /* Input and output buffers. */ | ||
79 | char *input_buffer, *output_buffer; | ||
80 | |||
81 | /* The size of the input buffer. */ | ||
82 | long input_buffer_size; | ||
83 | |||
84 | /* Current locations in `input_buffer' and `output_buffer'. */ | ||
85 | char *in_buff, *out_buff; | ||
86 | |||
87 | /* Current number of bytes stored at `input_buff' and `output_buff'. */ | ||
88 | long input_size, output_size; | ||
89 | |||
90 | /* Block size value, initially 512. -B sets to 5120. */ | ||
91 | int io_block_size = 512; | ||
92 | |||
93 | struct new_cpio_header { | ||
94 | unsigned short c_magic; | ||
95 | unsigned long c_ino; | ||
96 | unsigned long c_mode; | ||
97 | unsigned long c_uid; | ||
98 | unsigned long c_gid; | ||
99 | unsigned long c_nlink; | ||
100 | unsigned long c_mtime; | ||
101 | unsigned long c_filesize; | ||
102 | long c_dev_maj; | ||
103 | long c_dev_min; | ||
104 | long c_rdev_maj; | ||
105 | long c_rdev_min; | ||
106 | unsigned long c_namesize; | ||
107 | unsigned long c_chksum; | ||
108 | char *c_name; | ||
109 | char *c_tar_linkname; | ||
110 | }; | ||
111 | |||
112 | /* Total number of bytes read and written for all files. | ||
113 | Now that many tape drives hold more than 4Gb we need more than 32 | ||
114 | bits to hold input_bytes and output_bytes. But it's not worth | ||
115 | the trouble of adding special multi-precision arithmetic if the | ||
116 | compiler doesn't support 64 bit ints since input_bytes and | ||
117 | output_bytes are only used to print the number of blocks copied. */ | ||
118 | #ifdef __GNUC__ | ||
119 | long long input_bytes, output_bytes; | ||
120 | #else | ||
121 | long input_bytes, output_bytes; | ||
122 | #endif | ||
123 | |||
124 | /* Allocate N bytes of memory dynamically, with error checking. */ | ||
125 | |||
126 | void *xmalloc(size_t n) | ||
127 | { | ||
128 | void *p; | ||
129 | if (xalloc_oversized(n, 1) || (!(p = malloc(n)) && n != 0)) { | ||
130 | fprintf(stderr, "%s: memory exhausted\n", progname); | ||
131 | exit(1); | ||
132 | } | ||
133 | return p; | ||
134 | /* return xnmalloc_inline (n, 1); */ | ||
135 | } | ||
136 | |||
137 | /* Change the size of an allocated block of memory P to N bytes, | ||
138 | with error checking. */ | ||
139 | |||
140 | void *xrealloc(void *p, size_t n) | ||
141 | { | ||
142 | if (xalloc_oversized(n, 1) || (!(p = realloc(p, n)) && n != 0)) { | ||
143 | fprintf(stderr, "%s: memory exhausted\n", progname); | ||
144 | exit(1); | ||
145 | } | ||
146 | return p; | ||
147 | /* return xnrealloc_inline (p, n, 1); */ | ||
148 | } | ||
149 | |||
150 | /* Clone STRING. */ | ||
151 | |||
152 | char *xstrdup(char const *string) | ||
153 | { | ||
154 | size_t s = strlen(string) + 1; | ||
155 | return memcpy(xmalloc(s), string, s); | ||
156 | /* return xmemdup_inline (string, strlen (string) + 1); */ | ||
157 | } | ||
158 | |||
159 | /* Copy NUM_BYTES of buffer `in_buff' into IN_BUF. | ||
160 | `in_buff' may be partly full. | ||
161 | When `in_buff' is exhausted, refill it from file descriptor IN_DES. */ | ||
162 | |||
163 | static void tape_fill_input_buffer(int in_des, int num_bytes) | ||
164 | { | ||
165 | in_buff = input_buffer; | ||
166 | num_bytes = (num_bytes < io_block_size) ? num_bytes : io_block_size; | ||
167 | input_size = read(in_des, input_buffer, num_bytes); | ||
168 | if (input_size < 0) { | ||
169 | fprintf(stderr, "%s: read error: %s\n", progname, | ||
170 | strerror(errno)); | ||
171 | exit(1); | ||
172 | } | ||
173 | if (input_size == 0) { | ||
174 | fprintf(stderr, "%s: premature end of file\n", progname); | ||
175 | exit(1); | ||
176 | } | ||
177 | input_bytes += input_size; | ||
178 | } | ||
179 | |||
180 | /* Write `output_size' bytes of `output_buffer' to file | ||
181 | descriptor OUT_DES and reset `output_size' and `out_buff'. | ||
182 | If `swapping_halfwords' or `swapping_bytes' is set, | ||
183 | do the appropriate swapping first. Our callers have | ||
184 | to make sure to only set these flags if `output_size' | ||
185 | is appropriate (a multiple of 4 for `swapping_halfwords', | ||
186 | 2 for `swapping_bytes'). The fact that DISK_IO_BLOCK_SIZE | ||
187 | must always be a multiple of 4 helps us (and our callers) | ||
188 | insure this. */ | ||
189 | |||
190 | void disk_empty_output_buffer(int out_des) | ||
191 | { | ||
192 | int bytes_written; | ||
193 | |||
194 | bytes_written = write(out_des, output_buffer, output_size); | ||
195 | |||
196 | if (bytes_written != output_size) { | ||
197 | fprintf(stderr, "%s: write error: %s\n", | ||
198 | progname, strerror(errno)); | ||
199 | exit(1); | ||
200 | } | ||
201 | output_bytes += output_size; | ||
202 | out_buff = output_buffer; | ||
203 | output_size = 0; | ||
204 | } | ||
205 | |||
206 | /* Copy NUM_BYTES of buffer IN_BUF to `out_buff', which may be partly full. | ||
207 | When `out_buff' fills up, flush it to file descriptor OUT_DES. */ | ||
208 | |||
209 | void disk_buffered_write(char *in_buf, int out_des, long num_bytes) | ||
210 | { | ||
211 | register long bytes_left = num_bytes; /* Bytes needing to be copied. */ | ||
212 | register long space_left; /* Room left in output buffer. */ | ||
213 | |||
214 | while (bytes_left > 0) { | ||
215 | space_left = DISK_IO_BLOCK_SIZE - output_size; | ||
216 | if (space_left == 0) | ||
217 | disk_empty_output_buffer(out_des); | ||
218 | else { | ||
219 | if (bytes_left < space_left) | ||
220 | space_left = bytes_left; | ||
221 | memmove(out_buff, in_buf, (unsigned)space_left); | ||
222 | out_buff += space_left; | ||
223 | output_size += space_left; | ||
224 | in_buf += space_left; | ||
225 | bytes_left -= space_left; | ||
226 | } | ||
227 | } | ||
228 | } | ||
229 | |||
230 | /* Copy a file using the input and output buffers, which may start out | ||
231 | partly full. After the copy, the files are not closed nor the last | ||
232 | block flushed to output, and the input buffer may still be partly | ||
233 | full. If `crc_i_flag' is set, add each byte to `crc'. | ||
234 | IN_DES is the file descriptor for input; | ||
235 | OUT_DES is the file descriptor for output; | ||
236 | NUM_BYTES is the number of bytes to copy. */ | ||
237 | |||
238 | void copy_files_tape_to_disk(int in_des, int out_des, long num_bytes) | ||
239 | { | ||
240 | long size; | ||
241 | |||
242 | while (num_bytes > 0) { | ||
243 | if (input_size == 0) | ||
244 | tape_fill_input_buffer(in_des, io_block_size); | ||
245 | size = (input_size < num_bytes) ? input_size : num_bytes; | ||
246 | disk_buffered_write(in_buff, out_des, size); | ||
247 | num_bytes -= size; | ||
248 | input_size -= size; | ||
249 | in_buff += size; | ||
250 | } | ||
251 | } | ||
252 | |||
253 | /* if IN_BUF is NULL, Skip the next NUM_BYTES bytes of file descriptor IN_DES. */ | ||
254 | void tape_buffered_read(char *in_buf, int in_des, long num_bytes) | ||
255 | { | ||
256 | register long bytes_left = num_bytes; /* Bytes needing to be copied. */ | ||
257 | register long space_left; /* Bytes to copy from input buffer. */ | ||
258 | |||
259 | while (bytes_left > 0) { | ||
260 | if (input_size == 0) | ||
261 | tape_fill_input_buffer(in_des, io_block_size); | ||
262 | if (bytes_left < input_size) | ||
263 | space_left = bytes_left; | ||
264 | else | ||
265 | space_left = input_size; | ||
266 | if (in_buf != NULL) { | ||
267 | memmove(in_buf, in_buff, (unsigned)space_left); | ||
268 | in_buf += space_left; | ||
269 | } | ||
270 | in_buff += space_left; | ||
271 | input_size -= space_left; | ||
272 | bytes_left -= space_left; | ||
273 | } | ||
274 | } | ||
275 | |||
276 | /* Skip the next NUM_BYTES bytes of file descriptor IN_DES. */ | ||
277 | #define tape_toss_input(in_des,num_bytes) \ | ||
278 | (tape_buffered_read(NULL,(in_des),(num_bytes))) | ||
279 | |||
280 | struct deferment { | ||
281 | struct deferment *next; | ||
282 | struct new_cpio_header header; | ||
283 | }; | ||
284 | |||
285 | struct deferment *create_deferment(struct new_cpio_header *file_hdr) | ||
286 | { | ||
287 | struct deferment *d; | ||
288 | d = (struct deferment *)xmalloc(sizeof(struct deferment)); | ||
289 | d->header = *file_hdr; | ||
290 | d->header.c_name = (char *)xmalloc(strlen(file_hdr->c_name) + 1); | ||
291 | strcpy(d->header.c_name, file_hdr->c_name); | ||
292 | return d; | ||
293 | } | ||
294 | |||
295 | void free_deferment(struct deferment *d) | ||
296 | { | ||
297 | free(d->header.c_name); | ||
298 | free(d); | ||
299 | } | ||
300 | |||
301 | int link_to_name(char *link_name, char *link_target) | ||
302 | { | ||
303 | int res = link(link_target, link_name); | ||
304 | return res; | ||
305 | } | ||
306 | |||
307 | struct inode_val { | ||
308 | unsigned long inode; | ||
309 | unsigned long major_num; | ||
310 | unsigned long minor_num; | ||
311 | char *file_name; | ||
312 | }; | ||
313 | |||
314 | /* Inode hash table. Allocated by first call to add_inode. */ | ||
315 | static struct inode_val **hash_table = NULL; | ||
316 | |||
317 | /* Size of current hash table. Initial size is 47. (47 = 2*22 + 3) */ | ||
318 | static int hash_size = 22; | ||
319 | |||
320 | /* Number of elements in current hash table. */ | ||
321 | static int hash_num; | ||
322 | |||
323 | /* Do the hash insert. Used in normal inserts and resizing the hash | ||
324 | table. It is guaranteed that there is room to insert the item. | ||
325 | NEW_VALUE is the pointer to the previously allocated inode, file | ||
326 | name association record. */ | ||
327 | |||
328 | static void hash_insert(struct inode_val *new_value) | ||
329 | { | ||
330 | int start; /* Home position for the value. */ | ||
331 | int temp; /* Used for rehashing. */ | ||
332 | |||
333 | /* Hash function is node number modulo the table size. */ | ||
334 | start = new_value->inode % hash_size; | ||
335 | |||
336 | /* Do the initial look into the table. */ | ||
337 | if (hash_table[start] == NULL) { | ||
338 | hash_table[start] = new_value; | ||
339 | return; | ||
340 | } | ||
341 | |||
342 | /* If we get to here, the home position is full with a different inode | ||
343 | record. Do a linear search for the first NULL pointer and insert | ||
344 | the new item there. */ | ||
345 | temp = (start + 1) % hash_size; | ||
346 | while (hash_table[temp] != NULL) | ||
347 | temp = (temp + 1) % hash_size; | ||
348 | |||
349 | /* Insert at the NULL. */ | ||
350 | hash_table[temp] = new_value; | ||
351 | } | ||
352 | |||
353 | /* Associate FILE_NAME with the inode NODE_NUM. (Insert into hash table.) */ | ||
354 | |||
355 | void | ||
356 | add_inode(unsigned long node_num, char *file_name, unsigned long major_num, | ||
357 | unsigned long minor_num) | ||
358 | { | ||
359 | struct inode_val *temp; | ||
360 | |||
361 | /* Create new inode record. */ | ||
362 | temp = (struct inode_val *)xmalloc(sizeof(struct inode_val)); | ||
363 | temp->inode = node_num; | ||
364 | temp->major_num = major_num; | ||
365 | temp->minor_num = minor_num; | ||
366 | temp->file_name = xstrdup(file_name); | ||
367 | |||
368 | /* Do we have to increase the size of (or initially allocate) | ||
369 | the hash table? */ | ||
370 | if (hash_num == hash_size || hash_table == NULL) { | ||
371 | struct inode_val **old_table; /* Pointer to old table. */ | ||
372 | int i; /* Index for re-insert loop. */ | ||
373 | |||
374 | /* Save old table. */ | ||
375 | old_table = hash_table; | ||
376 | if (old_table == NULL) | ||
377 | hash_num = 0; | ||
378 | |||
379 | /* Calculate new size of table and allocate it. | ||
380 | Sequence of table sizes is 47, 97, 197, 397, 797, 1597, 3197, 6397 ... | ||
381 | where 3197 and most of the sizes after 6397 are not prime. The other | ||
382 | numbers listed are prime. */ | ||
383 | hash_size = 2 * hash_size + 3; | ||
384 | hash_table = (struct inode_val **) | ||
385 | xmalloc(hash_size * sizeof(struct inode_val *)); | ||
386 | memset(hash_table, 0, hash_size * sizeof(struct inode_val *)); | ||
387 | |||
388 | /* Insert the values from the old table into the new table. */ | ||
389 | for (i = 0; i < hash_num; i++) | ||
390 | hash_insert(old_table[i]); | ||
391 | |||
392 | if (old_table != NULL) | ||
393 | free(old_table); | ||
394 | } | ||
395 | |||
396 | /* Insert the new record and increment the count of elements in the | ||
397 | hash table. */ | ||
398 | hash_insert(temp); | ||
399 | hash_num++; | ||
400 | } | ||
401 | |||
402 | char *find_inode_file(unsigned long node_num, unsigned long major_num, | ||
403 | unsigned long minor_num) | ||
404 | { | ||
405 | int start; /* Initial hash location. */ | ||
406 | int temp; /* Rehash search variable. */ | ||
407 | |||
408 | if (hash_table != NULL) { | ||
409 | /* Hash function is node number modulo the table size. */ | ||
410 | start = node_num % hash_size; | ||
411 | |||
412 | /* Initial look into the table. */ | ||
413 | if (hash_table[start] == NULL) | ||
414 | return NULL; | ||
415 | if (hash_table[start]->inode == node_num | ||
416 | && hash_table[start]->major_num == major_num | ||
417 | && hash_table[start]->minor_num == minor_num) | ||
418 | return hash_table[start]->file_name; | ||
419 | |||
420 | /* The home position is full with a different inode record. | ||
421 | Do a linear search terminated by a NULL pointer. */ | ||
422 | for (temp = (start + 1) % hash_size; | ||
423 | hash_table[temp] != NULL && temp != start; | ||
424 | temp = (temp + 1) % hash_size) { | ||
425 | if (hash_table[temp]->inode == node_num | ||
426 | && hash_table[start]->major_num == major_num | ||
427 | && hash_table[start]->minor_num == minor_num) | ||
428 | return hash_table[temp]->file_name; | ||
429 | } | ||
430 | } | ||
431 | return NULL; | ||
432 | } | ||
433 | |||
434 | /* Try and create a hard link from FILE_NAME to another file | ||
435 | with the given major/minor device number and inode. If no other | ||
436 | file with the same major/minor/inode numbers is known, add this file | ||
437 | to the list of known files and associated major/minor/inode numbers | ||
438 | and return -1. If another file with the same major/minor/inode | ||
439 | numbers is found, try and create another link to it using | ||
440 | link_to_name, and return 0 for success and -1 for failure. */ | ||
441 | |||
442 | int | ||
443 | link_to_maj_min_ino(char *file_name, int st_dev_maj, int st_dev_min, int st_ino) | ||
444 | { | ||
445 | int link_res; | ||
446 | char *link_name; | ||
447 | link_res = -1; | ||
448 | /* Is the file a link to a previously copied file? */ | ||
449 | link_name = find_inode_file(st_ino, st_dev_maj, st_dev_min); | ||
450 | if (link_name == NULL) | ||
451 | add_inode(st_ino, file_name, st_dev_maj, st_dev_min); | ||
452 | else | ||
453 | link_res = link_to_name(file_name, link_name); | ||
454 | return link_res; | ||
455 | } | ||
456 | |||
457 | static void copyin_regular_file(struct new_cpio_header *file_hdr, | ||
458 | int in_file_des); | ||
459 | |||
460 | void warn_junk_bytes(long bytes_skipped) | ||
461 | { | ||
462 | fprintf(stderr, "%s: warning: skipped %ld byte(s) of junk\n", | ||
463 | progname, bytes_skipped); | ||
464 | } | ||
465 | |||
466 | /* Skip the padding on IN_FILE_DES after a header or file, | ||
467 | up to the next header. | ||
468 | The number of bytes skipped is based on OFFSET -- the current offset | ||
469 | from the last start of a header (or file) -- and the current | ||
470 | header type. */ | ||
471 | |||
472 | static void tape_skip_padding(int in_file_des, int offset) | ||
473 | { | ||
474 | int pad; | ||
475 | pad = (4 - (offset % 4)) % 4; | ||
476 | |||
477 | if (pad != 0) | ||
478 | tape_toss_input(in_file_des, pad); | ||
479 | } | ||
480 | |||
481 | static int | ||
482 | try_existing_file(struct new_cpio_header *file_hdr, int in_file_des, | ||
483 | int *existing_dir) | ||
484 | { | ||
485 | struct stat file_stat; | ||
486 | |||
487 | *existing_dir = false; | ||
488 | if (lstat(file_hdr->c_name, &file_stat) == 0) { | ||
489 | if (S_ISDIR(file_stat.st_mode) | ||
490 | && ((file_hdr->c_mode & S_IFMT) == S_IFDIR)) { | ||
491 | /* If there is already a directory there that | ||
492 | we are trying to create, don't complain about | ||
493 | it. */ | ||
494 | *existing_dir = true; | ||
495 | return 0; | ||
496 | } else if (S_ISDIR(file_stat.st_mode) | ||
497 | ? rmdir(file_hdr->c_name) | ||
498 | : unlink(file_hdr->c_name)) { | ||
499 | fprintf(stderr, "%s: cannot remove current %s: %s\n", | ||
500 | progname, file_hdr->c_name, strerror(errno)); | ||
501 | tape_toss_input(in_file_des, file_hdr->c_filesize); | ||
502 | tape_skip_padding(in_file_des, file_hdr->c_filesize); | ||
503 | return -1; /* Go to the next file. */ | ||
504 | } | ||
505 | } | ||
506 | return 0; | ||
507 | } | ||
508 | |||
509 | /* The newc and crc formats store multiply linked copies of the same file | ||
510 | in the archive only once. The actual data is attached to the last link | ||
511 | in the archive, and the other links all have a filesize of 0. When a | ||
512 | file in the archive has multiple links and a filesize of 0, its data is | ||
513 | probably "attatched" to another file in the archive, so we can't create | ||
514 | it right away. We have to "defer" creating it until we have created | ||
515 | the file that has the data "attatched" to it. We keep a list of the | ||
516 | "defered" links on deferments. */ | ||
517 | |||
518 | struct deferment *deferments = NULL; | ||
519 | |||
520 | /* Add a file header to the deferments list. For now they all just | ||
521 | go on one list, although we could optimize this if necessary. */ | ||
522 | |||
523 | static void defer_copyin(struct new_cpio_header *file_hdr) | ||
524 | { | ||
525 | struct deferment *d; | ||
526 | d = create_deferment(file_hdr); | ||
527 | d->next = deferments; | ||
528 | deferments = d; | ||
529 | return; | ||
530 | } | ||
531 | |||
532 | /* We just created a file that (probably) has some other links to it | ||
533 | which have been defered. Go through all of the links on the deferments | ||
534 | list and create any which are links to this file. */ | ||
535 | |||
536 | static void create_defered_links(struct new_cpio_header *file_hdr) | ||
537 | { | ||
538 | struct deferment *d; | ||
539 | struct deferment *d_prev; | ||
540 | int ino; | ||
541 | int maj; | ||
542 | int min; | ||
543 | int link_res; | ||
544 | ino = file_hdr->c_ino; | ||
545 | maj = file_hdr->c_dev_maj; | ||
546 | min = file_hdr->c_dev_min; | ||
547 | d = deferments; | ||
548 | d_prev = NULL; | ||
549 | while (d != NULL) { | ||
550 | if ((d->header.c_ino == ino) && (d->header.c_dev_maj == maj) | ||
551 | && (d->header.c_dev_min == min)) { | ||
552 | struct deferment *d_free; | ||
553 | link_res = | ||
554 | link_to_name(d->header.c_name, file_hdr->c_name); | ||
555 | if (link_res < 0) { | ||
556 | fprintf(stderr, | ||
557 | "%s: cannot link %s to %s: %s\n", | ||
558 | progname, d->header.c_name, | ||
559 | file_hdr->c_name, strerror(errno)); | ||
560 | } | ||
561 | if (d_prev != NULL) | ||
562 | d_prev->next = d->next; | ||
563 | else | ||
564 | deferments = d->next; | ||
565 | d_free = d; | ||
566 | d = d->next; | ||
567 | free_deferment(d_free); | ||
568 | } else { | ||
569 | d_prev = d; | ||
570 | d = d->next; | ||
571 | } | ||
572 | } | ||
573 | } | ||
574 | |||
575 | /* If we had a multiply linked file that really was empty then we would | ||
576 | have defered all of its links, since we never found any with data | ||
577 | "attached", and they will still be on the deferment list even when | ||
578 | we are done reading the whole archive. Write out all of these | ||
579 | empty links that are still on the deferments list. */ | ||
580 | |||
581 | static void create_final_defers() | ||
582 | { | ||
583 | struct deferment *d; | ||
584 | int link_res; | ||
585 | int out_file_des; | ||
586 | struct utimbuf times; /* For setting file times. */ | ||
587 | /* Initialize this in case it has members we don't know to set. */ | ||
588 | memset(×, 0, sizeof(struct utimbuf)); | ||
589 | |||
590 | for (d = deferments; d != NULL; d = d->next) { | ||
591 | /* Debian hack: A line, which could cause an endless loop, was | ||
592 | removed (97/1/2). It was reported by Ronald F. Guilmette to | ||
593 | the upstream maintainers. -BEM */ | ||
594 | /* Debian hack: This was reported by Horst Knobloch. This bug has | ||
595 | been reported to "bug-gnu-utils@prep.ai.mit.edu". (99/1/6) -BEM | ||
596 | */ | ||
597 | link_res = link_to_maj_min_ino(d->header.c_name, | ||
598 | d->header.c_dev_maj, | ||
599 | d->header.c_dev_min, | ||
600 | d->header.c_ino); | ||
601 | if (link_res == 0) { | ||
602 | continue; | ||
603 | } | ||
604 | out_file_des = open(d->header.c_name, | ||
605 | O_CREAT | O_WRONLY | O_BINARY, 0600); | ||
606 | if (out_file_des < 0) { | ||
607 | fprintf(stderr, "%s: open %s: %s\n", | ||
608 | progname, d->header.c_name, strerror(errno)); | ||
609 | continue; | ||
610 | } | ||
611 | |||
612 | /* File is now copied; set attributes. */ | ||
613 | if ((fchown(out_file_des, d->header.c_uid, d->header.c_gid) < 0) | ||
614 | && errno != EPERM) | ||
615 | fprintf(stderr, "%s: fchown %s: %s\n", | ||
616 | progname, d->header.c_name, strerror(errno)); | ||
617 | /* chown may have turned off some permissions we wanted. */ | ||
618 | if (fchmod(out_file_des, (int)d->header.c_mode) < 0) | ||
619 | fprintf(stderr, "%s: fchmod %s: %s\n", | ||
620 | progname, d->header.c_name, strerror(errno)); | ||
621 | |||
622 | if (close(out_file_des) < 0) | ||
623 | fprintf(stderr, "%s: close %s: %s\n", | ||
624 | progname, d->header.c_name, strerror(errno)); | ||
625 | |||
626 | } | ||
627 | } | ||
628 | |||
629 | static void | ||
630 | copyin_regular_file(struct new_cpio_header *file_hdr, int in_file_des) | ||
631 | { | ||
632 | int out_file_des; /* Output file descriptor. */ | ||
633 | |||
634 | /* Can the current file be linked to a previously copied file? */ | ||
635 | if (file_hdr->c_nlink > 1) { | ||
636 | int link_res; | ||
637 | if (file_hdr->c_filesize == 0) { | ||
638 | /* The newc and crc formats store multiply linked copies | ||
639 | of the same file in the archive only once. The | ||
640 | actual data is attached to the last link in the | ||
641 | archive, and the other links all have a filesize | ||
642 | of 0. Since this file has multiple links and a | ||
643 | filesize of 0, its data is probably attatched to | ||
644 | another file in the archive. Save the link, and | ||
645 | process it later when we get the actual data. We | ||
646 | can't just create it with length 0 and add the | ||
647 | data later, in case the file is readonly. We still | ||
648 | lose if its parent directory is readonly (and we aren't | ||
649 | running as root), but there's nothing we can do about | ||
650 | that. */ | ||
651 | defer_copyin(file_hdr); | ||
652 | tape_toss_input(in_file_des, file_hdr->c_filesize); | ||
653 | tape_skip_padding(in_file_des, file_hdr->c_filesize); | ||
654 | return; | ||
655 | } | ||
656 | /* If the file has data (filesize != 0), then presumably | ||
657 | any other links have already been defer_copyin'ed(), | ||
658 | but GNU cpio version 2.0-2.2 didn't do that, so we | ||
659 | still have to check for links here (and also in case | ||
660 | the archive was created and later appeneded to). */ | ||
661 | /* Debian hack: (97/1/2) This was reported by Ronald | ||
662 | F. Guilmette to the upstream maintainers. -BEM */ | ||
663 | link_res = link_to_maj_min_ino(file_hdr->c_name, | ||
664 | file_hdr->c_dev_maj, | ||
665 | file_hdr->c_dev_min, | ||
666 | file_hdr->c_ino); | ||
667 | if (link_res == 0) { | ||
668 | tape_toss_input(in_file_des, file_hdr->c_filesize); | ||
669 | tape_skip_padding(in_file_des, file_hdr->c_filesize); | ||
670 | return; | ||
671 | } | ||
672 | } | ||
673 | |||
674 | /* If not linked, copy the contents of the file. */ | ||
675 | out_file_des = open(file_hdr->c_name, | ||
676 | O_CREAT | O_WRONLY | O_BINARY, 0600); | ||
677 | |||
678 | if (out_file_des < 0) { | ||
679 | fprintf(stderr, "%s: open %s: %s\n", | ||
680 | progname, file_hdr->c_name, strerror(errno)); | ||
681 | tape_toss_input(in_file_des, file_hdr->c_filesize); | ||
682 | tape_skip_padding(in_file_des, file_hdr->c_filesize); | ||
683 | return; | ||
684 | } | ||
685 | |||
686 | copy_files_tape_to_disk(in_file_des, out_file_des, | ||
687 | file_hdr->c_filesize); | ||
688 | disk_empty_output_buffer(out_file_des); | ||
689 | |||
690 | if (close(out_file_des) < 0) | ||
691 | fprintf(stderr, "%s: close %s: %s\n", | ||
692 | progname, file_hdr->c_name, strerror(errno)); | ||
693 | |||
694 | /* File is now copied; set attributes. */ | ||
695 | if ((chown(file_hdr->c_name, file_hdr->c_uid, file_hdr->c_gid) < 0) | ||
696 | && errno != EPERM) | ||
697 | fprintf(stderr, "%s: chown %s: %s\n", | ||
698 | progname, file_hdr->c_name, strerror(errno)); | ||
699 | |||
700 | /* chown may have turned off some permissions we wanted. */ | ||
701 | if (chmod(file_hdr->c_name, (int)file_hdr->c_mode) < 0) | ||
702 | fprintf(stderr, "%s: chmod %s: %s\n", | ||
703 | progname, file_hdr->c_name, strerror(errno)); | ||
704 | |||
705 | tape_skip_padding(in_file_des, file_hdr->c_filesize); | ||
706 | if (file_hdr->c_nlink > 1) { | ||
707 | /* (see comment above for how the newc and crc formats | ||
708 | store multiple links). Now that we have the data | ||
709 | for this file, create any other links to it which | ||
710 | we defered. */ | ||
711 | create_defered_links(file_hdr); | ||
712 | } | ||
713 | } | ||
714 | |||
715 | /* In general, we can't use the builtin `basename' function if available, | ||
716 | since it has different meanings in different environments. | ||
717 | In some environments the builtin `basename' modifies its argument. | ||
718 | |||
719 | Return the address of the last file name component of NAME. If | ||
720 | NAME has no file name components because it is all slashes, return | ||
721 | NAME if it is empty, the address of its last slash otherwise. */ | ||
722 | |||
723 | char *base_name(char const *name) | ||
724 | { | ||
725 | char const *base = name + FILE_SYSTEM_PREFIX_LEN(name); | ||
726 | char const *p; | ||
727 | |||
728 | for (p = base; *p; p++) { | ||
729 | if (ISSLASH(*p)) { | ||
730 | /* Treat multiple adjacent slashes like a single slash. */ | ||
731 | do | ||
732 | p++; | ||
733 | while (ISSLASH(*p)); | ||
734 | |||
735 | /* If the file name ends in slash, use the trailing slash as | ||
736 | the basename if no non-slashes have been found. */ | ||
737 | if (!*p) { | ||
738 | if (ISSLASH(*base)) | ||
739 | base = p - 1; | ||
740 | break; | ||
741 | } | ||
742 | |||
743 | /* *P is a non-slash preceded by a slash. */ | ||
744 | base = p; | ||
745 | } | ||
746 | } | ||
747 | |||
748 | return (char *)base; | ||
749 | } | ||
750 | |||
751 | /* Return the length of of the basename NAME. Typically NAME is the | ||
752 | value returned by base_name. Act like strlen (NAME), except omit | ||
753 | redundant trailing slashes. */ | ||
754 | |||
755 | size_t base_len(char const *name) | ||
756 | { | ||
757 | size_t len; | ||
758 | |||
759 | for (len = strlen(name); 1 < len && ISSLASH(name[len - 1]); len--) | ||
760 | continue; | ||
761 | |||
762 | return len; | ||
763 | } | ||
764 | |||
765 | /* Remove trailing slashes from PATH. | ||
766 | Return true if a trailing slash was removed. | ||
767 | This is useful when using filename completion from a shell that | ||
768 | adds a "/" after directory names (such as tcsh and bash), because | ||
769 | the Unix rename and rmdir system calls return an "Invalid argument" error | ||
770 | when given a path that ends in "/" (except for the root directory). */ | ||
771 | |||
772 | bool strip_trailing_slashes(char *path) | ||
773 | { | ||
774 | char *base = base_name(path); | ||
775 | char *base_lim = base + base_len(base); | ||
776 | bool had_slash = (*base_lim != '\0'); | ||
777 | *base_lim = '\0'; | ||
778 | return had_slash; | ||
779 | } | ||
780 | |||
781 | static void copyin_directory(struct new_cpio_header *file_hdr, int existing_dir) | ||
782 | { | ||
783 | int res; /* Result of various function calls. */ | ||
784 | |||
785 | /* Strip any trailing `/'s off the filename; tar puts | ||
786 | them on. We might as well do it here in case anybody | ||
787 | else does too, since they cause strange things to happen. */ | ||
788 | strip_trailing_slashes(file_hdr->c_name); | ||
789 | |||
790 | /* Ignore the current directory. It must already exist, | ||
791 | and we don't want to change its permission, ownership | ||
792 | or time. */ | ||
793 | if (file_hdr->c_name[0] == '.' && file_hdr->c_name[1] == '\0') { | ||
794 | return; | ||
795 | } | ||
796 | |||
797 | if (!existing_dir) | ||
798 | { | ||
799 | res = mkdir(file_hdr->c_name, file_hdr->c_mode); | ||
800 | } else | ||
801 | res = 0; | ||
802 | if (res < 0) { | ||
803 | /* In some odd cases where the file_hdr->c_name includes `.', | ||
804 | the directory may have actually been created by | ||
805 | create_all_directories(), so the mkdir will fail | ||
806 | because the directory exists. If that's the case, | ||
807 | don't complain about it. */ | ||
808 | struct stat file_stat; | ||
809 | if ((errno != EEXIST) || | ||
810 | (lstat(file_hdr->c_name, &file_stat) != 0) || | ||
811 | !(S_ISDIR(file_stat.st_mode))) { | ||
812 | fprintf(stderr, "%s: lstat %s: %s\n", | ||
813 | progname, file_hdr->c_name, strerror(errno)); | ||
814 | return; | ||
815 | } | ||
816 | } | ||
817 | if ((chown(file_hdr->c_name, file_hdr->c_uid, file_hdr->c_gid) < 0) | ||
818 | && errno != EPERM) | ||
819 | fprintf(stderr, "%s: chown %s: %s\n", | ||
820 | progname, file_hdr->c_name, strerror(errno)); | ||
821 | /* chown may have turned off some permissions we wanted. */ | ||
822 | if (chmod(file_hdr->c_name, (int)file_hdr->c_mode) < 0) | ||
823 | fprintf(stderr, "%s: chmod %s: %s\n", | ||
824 | progname, file_hdr->c_name, strerror(errno)); | ||
825 | } | ||
826 | |||
827 | static void copyin_device(struct new_cpio_header *file_hdr) | ||
828 | { | ||
829 | int res; /* Result of various function calls. */ | ||
830 | |||
831 | if (file_hdr->c_nlink > 1) { | ||
832 | int link_res; | ||
833 | /* Debian hack: This was reported by Horst | ||
834 | Knobloch. This bug has been reported to | ||
835 | "bug-gnu-utils@prep.ai.mit.edu". (99/1/6) -BEM */ | ||
836 | link_res = link_to_maj_min_ino(file_hdr->c_name, | ||
837 | file_hdr->c_dev_maj, | ||
838 | file_hdr->c_dev_min, | ||
839 | file_hdr->c_ino); | ||
840 | if (link_res == 0) { | ||
841 | return; | ||
842 | } | ||
843 | } | ||
844 | |||
845 | res = mknod(file_hdr->c_name, file_hdr->c_mode, | ||
846 | makedev(file_hdr->c_rdev_maj, file_hdr->c_rdev_min)); | ||
847 | if (res < 0) { | ||
848 | fprintf(stderr, "%s: mknod %s: %s\n", progname, | ||
849 | file_hdr->c_name, strerror(errno)); | ||
850 | return; | ||
851 | } | ||
852 | if ((chown(file_hdr->c_name, file_hdr->c_uid, file_hdr->c_gid) < 0) | ||
853 | && errno != EPERM) | ||
854 | fprintf(stderr, "%s: chown %s: %s\n", progname, | ||
855 | file_hdr->c_name, strerror(errno)); | ||
856 | /* chown may have turned off some permissions we wanted. */ | ||
857 | if (chmod(file_hdr->c_name, file_hdr->c_mode) < 0) | ||
858 | fprintf(stderr, "%s: chmod %s: %s\n", progname, | ||
859 | file_hdr->c_name, strerror(errno)); | ||
860 | } | ||
861 | |||
862 | static void copyin_link(struct new_cpio_header *file_hdr, int in_file_des) | ||
863 | { | ||
864 | char *link_name = NULL; /* Name of hard and symbolic links. */ | ||
865 | int res; /* Result of various function calls. */ | ||
866 | |||
867 | link_name = (char *)xmalloc((unsigned int)file_hdr->c_filesize + 1); | ||
868 | link_name[file_hdr->c_filesize] = '\0'; | ||
869 | tape_buffered_read(link_name, in_file_des, file_hdr->c_filesize); | ||
870 | tape_skip_padding(in_file_des, file_hdr->c_filesize); | ||
871 | |||
872 | res = UMASKED_SYMLINK(link_name, file_hdr->c_name, file_hdr->c_mode); | ||
873 | if (res < 0) { | ||
874 | fprintf(stderr, "%s: UMASKED_SYMLINK %s: %s\n", | ||
875 | progname, file_hdr->c_name, strerror(errno)); | ||
876 | free(link_name); | ||
877 | return; | ||
878 | } | ||
879 | if ((lchown(file_hdr->c_name, file_hdr->c_uid, file_hdr->c_gid) < 0) | ||
880 | && errno != EPERM) { | ||
881 | fprintf(stderr, "%s: lchown %s: %s\n", | ||
882 | progname, file_hdr->c_name, strerror(errno)); | ||
883 | } | ||
884 | free(link_name); | ||
885 | } | ||
886 | |||
887 | static void copyin_file(struct new_cpio_header *file_hdr, int in_file_des) | ||
888 | { | ||
889 | int existing_dir; | ||
890 | |||
891 | if (try_existing_file(file_hdr, in_file_des, &existing_dir) < 0) | ||
892 | return; | ||
893 | |||
894 | /* Do the real copy or link. */ | ||
895 | switch (file_hdr->c_mode & S_IFMT) { | ||
896 | case S_IFREG: | ||
897 | copyin_regular_file(file_hdr, in_file_des); | ||
898 | break; | ||
899 | |||
900 | case S_IFDIR: | ||
901 | copyin_directory(file_hdr, existing_dir); | ||
902 | break; | ||
903 | |||
904 | case S_IFCHR: | ||
905 | case S_IFBLK: | ||
906 | #ifdef S_IFSOCK | ||
907 | case S_IFSOCK: | ||
908 | #endif | ||
909 | #ifdef S_IFIFO | ||
910 | case S_IFIFO: | ||
911 | #endif | ||
912 | copyin_device(file_hdr); | ||
913 | break; | ||
914 | |||
915 | #ifdef S_IFLNK | ||
916 | case S_IFLNK: | ||
917 | copyin_link(file_hdr, in_file_des); | ||
918 | break; | ||
919 | #endif | ||
920 | |||
921 | default: | ||
922 | fprintf(stderr, "%s: %s: unknown file type\n", | ||
923 | progname, file_hdr->c_name); | ||
924 | tape_toss_input(in_file_des, file_hdr->c_filesize); | ||
925 | tape_skip_padding(in_file_des, file_hdr->c_filesize); | ||
926 | } | ||
927 | } | ||
928 | |||
929 | /* Fill in FILE_HDR by reading a new-format ASCII format cpio header from | ||
930 | file descriptor IN_DES, except for the magic number, which is | ||
931 | already filled in. */ | ||
932 | |||
933 | void read_in_new_ascii(struct new_cpio_header *file_hdr, int in_des) | ||
934 | { | ||
935 | char ascii_header[112]; | ||
936 | |||
937 | tape_buffered_read(ascii_header, in_des, 104L); | ||
938 | ascii_header[104] = '\0'; | ||
939 | sscanf(ascii_header, | ||
940 | "%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx", | ||
941 | &file_hdr->c_ino, &file_hdr->c_mode, &file_hdr->c_uid, | ||
942 | &file_hdr->c_gid, &file_hdr->c_nlink, &file_hdr->c_mtime, | ||
943 | &file_hdr->c_filesize, &file_hdr->c_dev_maj, | ||
944 | &file_hdr->c_dev_min, &file_hdr->c_rdev_maj, | ||
945 | &file_hdr->c_rdev_min, &file_hdr->c_namesize, | ||
946 | &file_hdr->c_chksum); | ||
947 | /* Read file name from input. */ | ||
948 | if (file_hdr->c_name != NULL) | ||
949 | free(file_hdr->c_name); | ||
950 | file_hdr->c_name = (char *)xmalloc(file_hdr->c_namesize); | ||
951 | tape_buffered_read(file_hdr->c_name, in_des, | ||
952 | (long)file_hdr->c_namesize); | ||
953 | |||
954 | /* In SVR4 ASCII format, the amount of space allocated for the header | ||
955 | is rounded up to the next long-word, so we might need to drop | ||
956 | 1-3 bytes. */ | ||
957 | tape_skip_padding(in_des, file_hdr->c_namesize + 110); | ||
958 | } | ||
959 | |||
960 | /* Return 16-bit integer I with the bytes swapped. */ | ||
961 | #define swab_short(i) ((((i) << 8) & 0xff00) | (((i) >> 8) & 0x00ff)) | ||
962 | |||
963 | /* Read the header, including the name of the file, from file | ||
964 | descriptor IN_DES into FILE_HDR. */ | ||
965 | |||
966 | void read_in_header(struct new_cpio_header *file_hdr, int in_des) | ||
967 | { | ||
968 | long bytes_skipped = 0; /* Bytes of junk found before magic number. */ | ||
969 | |||
970 | /* Search for a valid magic number. */ | ||
971 | |||
972 | file_hdr->c_tar_linkname = NULL; | ||
973 | |||
974 | tape_buffered_read((char *)file_hdr, in_des, 6L); | ||
975 | while (1) { | ||
976 | if (!strncmp((char *)file_hdr, "070702", 6) | ||
977 | || !strncmp((char *)file_hdr, "070701", 6)) | ||
978 | { | ||
979 | if (bytes_skipped > 0) | ||
980 | warn_junk_bytes(bytes_skipped); | ||
981 | |||
982 | read_in_new_ascii(file_hdr, in_des); | ||
983 | break; | ||
984 | } | ||
985 | bytes_skipped++; | ||
986 | memmove((char *)file_hdr, (char *)file_hdr + 1, 5); | ||
987 | tape_buffered_read((char *)file_hdr + 5, in_des, 1L); | ||
988 | } | ||
989 | } | ||
990 | |||
991 | /* Read the collection from standard input and create files | ||
992 | in the file system. */ | ||
993 | |||
994 | void process_copy_in() | ||
995 | { | ||
996 | char done = false; /* True if trailer reached. */ | ||
997 | struct new_cpio_header file_hdr; /* Output header information. */ | ||
998 | int in_file_des; /* Input file descriptor. */ | ||
999 | |||
1000 | /* Initialize the copy in. */ | ||
1001 | file_hdr.c_name = NULL; | ||
1002 | |||
1003 | /* only from stdin */ | ||
1004 | in_file_des = 0; | ||
1005 | |||
1006 | /* While there is more input in the collection, process the input. */ | ||
1007 | while (!done) { | ||
1008 | /* Start processing the next file by reading the header. */ | ||
1009 | read_in_header(&file_hdr, in_file_des); | ||
1010 | |||
1011 | /* Is this the header for the TRAILER file? */ | ||
1012 | if (strcmp("TRAILER!!!", file_hdr.c_name) == 0) { | ||
1013 | done = true; | ||
1014 | break; | ||
1015 | } | ||
1016 | |||
1017 | /* Copy the input file into the directory structure. */ | ||
1018 | |||
1019 | copyin_file(&file_hdr, in_file_des); | ||
1020 | |||
1021 | if (dot_flag) | ||
1022 | fputc('.', stderr); | ||
1023 | } | ||
1024 | |||
1025 | if (dot_flag) | ||
1026 | fputc('\n', stderr); | ||
1027 | |||
1028 | create_final_defers(); | ||
1029 | |||
1030 | } | ||
1031 | |||
1032 | /* Initialize the input and output buffers to their proper size and | ||
1033 | initialize all variables associated with the input and output | ||
1034 | buffers. */ | ||
1035 | |||
1036 | void initialize_buffers() | ||
1037 | { | ||
1038 | int in_buf_size, out_buf_size; | ||
1039 | |||
1040 | /* Make sure the input buffer can always hold 2 blocks and that it | ||
1041 | is big enough to hold 1 tar record (512 bytes) even if it | ||
1042 | is not aligned on a block boundary. The extra buffer space | ||
1043 | is needed by process_copyin and peek_in_buf to automatically | ||
1044 | figure out what kind of archive it is reading. */ | ||
1045 | if (io_block_size >= 512) | ||
1046 | in_buf_size = 2 * io_block_size; | ||
1047 | else | ||
1048 | in_buf_size = 1024; | ||
1049 | out_buf_size = DISK_IO_BLOCK_SIZE; | ||
1050 | |||
1051 | input_buffer = (char *)xmalloc(in_buf_size); | ||
1052 | in_buff = input_buffer; | ||
1053 | input_buffer_size = in_buf_size; | ||
1054 | input_size = 0; | ||
1055 | input_bytes = 0; | ||
1056 | |||
1057 | output_buffer = (char *)xmalloc(out_buf_size); | ||
1058 | out_buff = output_buffer; | ||
1059 | output_size = 0; | ||
1060 | output_bytes = 0; | ||
1061 | |||
1062 | } | ||
1063 | |||
1064 | int main(int argc, char *argv[]) | ||
1065 | { | ||
1066 | int c; | ||
1067 | int extract_flag = false; | ||
1068 | |||
1069 | progname = argv[0]; | ||
1070 | |||
1071 | do { | ||
1072 | c = getopt(argc, argv, "iV"); | ||
1073 | if (c == EOF) | ||
1074 | break; | ||
1075 | switch (c) { | ||
1076 | case 'V': | ||
1077 | dot_flag = true; | ||
1078 | break; | ||
1079 | |||
1080 | case 'i': | ||
1081 | extract_flag = true; | ||
1082 | break; | ||
1083 | case '?': | ||
1084 | fprintf(stderr, | ||
1085 | "%s: not implemented or invalid option -%c\n", | ||
1086 | progname, optopt); | ||
1087 | exit(1); | ||
1088 | |||
1089 | } | ||
1090 | } while (1); | ||
1091 | |||
1092 | if (extract_flag) { | ||
1093 | initialize_buffers(); | ||
1094 | |||
1095 | process_copy_in(); | ||
1096 | } else { | ||
1097 | fprintf(stderr, "Usage: %s [-V] -i [< archive]\n", progname); | ||
1098 | exit(1); | ||
1099 | } | ||
1100 | |||
1101 | return 0; | ||
1102 | } |