Magellan Linux

Annotation of /trunk/mkinitrd-magellan/klibc/usr/utils/cpio.c

Parent Directory Parent Directory | Revision Log 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)
-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(&times, 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     }