diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2004-09-06 14:04:53 +0000 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2004-09-06 14:04:53 +0000 |
commit | 73636cd24d6c3c5d6b9e41ac9ea75de4b73ce4c9 (patch) | |
tree | 9ace8aff250c2be68bdd4d66652c0f6e6aff02b5 | |
parent | e8818871ebdc0b85272d32a32b8cbfb41cbe11ce (diff) | |
download | cpio-73636cd24d6c3c5d6b9e41ac9ea75de4b73ce4c9.tar.gz cpio-73636cd24d6c3c5d6b9e41ac9ea75de4b73ce4c9.tar.bz2 |
Switched to ANSI C (sigh)
-rw-r--r-- | src/copyin.c | 1645 | ||||
-rw-r--r-- | src/copyout.c | 559 | ||||
-rw-r--r-- | src/copypass.c | 25 | ||||
-rw-r--r-- | src/defer.c | 14 | ||||
-rw-r--r-- | src/defer.h | 2 | ||||
-rw-r--r-- | src/dstring.c | 23 | ||||
-rw-r--r-- | src/dstring.h | 12 | ||||
-rw-r--r-- | src/extern.h | 23 | ||||
-rw-r--r-- | src/filemode.c | 133 | ||||
-rw-r--r-- | src/global.c | 125 | ||||
-rw-r--r-- | src/idcache.c | 14 | ||||
-rw-r--r-- | src/main.c | 67 | ||||
-rw-r--r-- | src/makepath.c | 17 | ||||
-rw-r--r-- | src/mt.c | 156 | ||||
-rw-r--r-- | src/tar.c | 190 | ||||
-rw-r--r-- | src/userspec.c | 18 | ||||
-rw-r--r-- | src/util.c | 252 |
17 files changed, 1514 insertions, 1761 deletions
diff --git a/src/copyin.c b/src/copyin.c index 7c7f759..83d3087 100644 --- a/src/copyin.c +++ b/src/copyin.c @@ -1,5 +1,5 @@ /* copyin.c - extract or list a cpio archive - Copyright (C) 1990,1991,1992,2001,2002,2003 Free Software Foundation, Inc. + Copyright (C) 1990,1991,1992,2001,2002,2003,2004 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,19 +15,17 @@ with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#if defined(HAVE_CONFIG_H) -# include <config.h> -#endif +#include <system.h> + #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include "filetypes.h" -#include "system.h" #include "cpiohdr.h" #include "dstring.h" #include "extern.h" #include "defer.h" -#include "rmt.h" +#include <rmt.h> #ifndef FNM_PATHNAME #include <fnmatch.h> #endif @@ -36,607 +34,21 @@ #define lchown chown #endif -static void read_pattern_file (); -static void tape_skip_padding (); -static void defer_copyin (); -static void create_defered_links (); -static void create_final_defers (); -static int create_defered_links_to_skipped (); -static int query_rename(); -static void list_file(); -static void copyin_file(); -static int try_existing_file(); -static void copyin_regular_file(); -static void copyin_directory(); -static void copyin_device(); -static void copyin_link(); - -/* Return 16-bit integer I with the bytes swapped. */ -#define swab_short(i) ((((i) << 8) & 0xff00) | (((i) >> 8) & 0x00ff)) - -/* Read the header, including the name of the file, from file - descriptor IN_DES into FILE_HDR. */ - -void -read_in_header (file_hdr, in_des) - struct new_cpio_header *file_hdr; - int in_des; -{ - long bytes_skipped = 0; /* Bytes of junk found before magic number. */ - - /* Search for a valid magic number. */ - - if (archive_format == arf_unknown) - { - char tmpbuf[512]; - int check_tar; - int peeked_bytes; - - while (archive_format == arf_unknown) - { - peeked_bytes = tape_buffered_peek (tmpbuf, in_des, 512); - if (peeked_bytes < 6) - error (1, 0, _("premature end of archive")); - - if (!strncmp (tmpbuf, "070701", 6)) - archive_format = arf_newascii; - else if (!strncmp (tmpbuf, "070707", 6)) - archive_format = arf_oldascii; - else if (!strncmp (tmpbuf, "070702", 6)) - { - archive_format = arf_crcascii; - crc_i_flag = TRUE; - } - else if ((*((unsigned short *) tmpbuf) == 070707) || - (*((unsigned short *) tmpbuf) == swab_short ((unsigned short) 070707))) - archive_format = arf_binary; - else if (peeked_bytes >= 512 - && (check_tar = is_tar_header (tmpbuf))) - { - if (check_tar == 2) - archive_format = arf_ustar; - else - archive_format = arf_tar; - } - else - { - tape_buffered_read ((char *) tmpbuf, in_des, 1L); - ++bytes_skipped; - } - } - } - - if (archive_format == arf_tar || archive_format == arf_ustar) - { - if (append_flag) - last_header_start = input_bytes - io_block_size + - (in_buff - input_buffer); - if (bytes_skipped > 0) - error (0, 0, _("warning: skipped %ld bytes of junk"), bytes_skipped); - read_in_tar_header (file_hdr, in_des); - return; - } - - file_hdr->c_tar_linkname = NULL; - - tape_buffered_read ((char *) file_hdr, in_des, 6L); - while (1) - { - if (append_flag) - last_header_start = input_bytes - io_block_size - + (in_buff - input_buffer) - 6; - if (archive_format == arf_newascii - && !strncmp ((char *) file_hdr, "070701", 6)) - { - if (bytes_skipped > 0) - error (0, 0, _("warning: skipped %ld bytes of junk"), bytes_skipped); - read_in_new_ascii (file_hdr, in_des); - break; - } - if (archive_format == arf_crcascii - && !strncmp ((char *) file_hdr, "070702", 6)) - { - if (bytes_skipped > 0) - error (0, 0, _("warning: skipped %ld bytes of junk"), bytes_skipped); - read_in_new_ascii (file_hdr, in_des); - break; - } - if ( (archive_format == arf_oldascii || archive_format == arf_hpoldascii) - && !strncmp ((char *) file_hdr, "070707", 6)) - { - if (bytes_skipped > 0) - error (0, 0, _("warning: skipped %ld bytes of junk"), bytes_skipped); - read_in_old_ascii (file_hdr, in_des); - break; - } - if ( (archive_format == arf_binary || archive_format == arf_hpbinary) - && (file_hdr->c_magic == 070707 - || file_hdr->c_magic == swab_short ((unsigned short) 070707))) - { - /* Having to skip 1 byte because of word alignment is normal. */ - if (bytes_skipped > 0) - error (0, 0, _("warning: skipped %ld bytes of junk"), bytes_skipped); - read_in_binary (file_hdr, in_des); - break; - } - bytes_skipped++; - bcopy ((char *) file_hdr + 1, (char *) file_hdr, 5); - tape_buffered_read ((char *) file_hdr + 5, in_des, 1L); - } -} - -/* Fill in FILE_HDR by reading an old-format ASCII format cpio header from - file descriptor IN_DES, except for the magic number, which is - already filled in. */ - -void -read_in_old_ascii (file_hdr, in_des) - struct new_cpio_header *file_hdr; - int in_des; -{ - char ascii_header[78]; - unsigned long dev; - unsigned long rdev; - - tape_buffered_read (ascii_header, in_des, 70L); - ascii_header[70] = '\0'; - sscanf (ascii_header, - "%6lo%6lo%6lo%6lo%6lo%6lo%6lo%11lo%6lo%11lo", - &dev, &file_hdr->c_ino, - &file_hdr->c_mode, &file_hdr->c_uid, &file_hdr->c_gid, - &file_hdr->c_nlink, &rdev, &file_hdr->c_mtime, - &file_hdr->c_namesize, &file_hdr->c_filesize); - file_hdr->c_dev_maj = major (dev); - file_hdr->c_dev_min = minor (dev); - file_hdr->c_rdev_maj = major (rdev); - file_hdr->c_rdev_min = minor (rdev); - - /* Read file name from input. */ - if (file_hdr->c_name != NULL) - free (file_hdr->c_name); - file_hdr->c_name = (char *) xmalloc (file_hdr->c_namesize + 1); - tape_buffered_read (file_hdr->c_name, in_des, (long) file_hdr->c_namesize); - - /* HP/UX cpio creates archives that look just like ordinary archives, - but for devices it sets major = 0, minor = 1, and puts the - actual major/minor number in the filesize field. See if this - is an HP/UX cpio archive, and if so fix it. We have to do this - here because process_copy_in() assumes filesize is always 0 - for devices. */ - switch (file_hdr->c_mode & CP_IFMT) - { - case CP_IFCHR: - case CP_IFBLK: -#ifdef CP_IFSOCK - case CP_IFSOCK: -#endif -#ifdef CP_IFIFO - case CP_IFIFO: -#endif - if (file_hdr->c_filesize != 0 - && file_hdr->c_rdev_maj == 0 - && file_hdr->c_rdev_min == 1) - { - file_hdr->c_rdev_maj = major (file_hdr->c_filesize); - file_hdr->c_rdev_min = minor (file_hdr->c_filesize); - file_hdr->c_filesize = 0; - } - break; - default: - break; - } -} - -/* Fill in FILE_HDR by reading a new-format ASCII format cpio header from - file descriptor IN_DES, except for the magic number, which is - already filled in. */ - -void -read_in_new_ascii (file_hdr, in_des) - struct new_cpio_header *file_hdr; - int in_des; -{ - char ascii_header[112]; - - tape_buffered_read (ascii_header, in_des, 104L); - ascii_header[104] = '\0'; - sscanf (ascii_header, - "%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx%8lx", - &file_hdr->c_ino, &file_hdr->c_mode, &file_hdr->c_uid, - &file_hdr->c_gid, &file_hdr->c_nlink, &file_hdr->c_mtime, - &file_hdr->c_filesize, &file_hdr->c_dev_maj, &file_hdr->c_dev_min, - &file_hdr->c_rdev_maj, &file_hdr->c_rdev_min, &file_hdr->c_namesize, - &file_hdr->c_chksum); - /* Read file name from input. */ - if (file_hdr->c_name != NULL) - free (file_hdr->c_name); - file_hdr->c_name = (char *) xmalloc (file_hdr->c_namesize); - tape_buffered_read (file_hdr->c_name, in_des, (long) file_hdr->c_namesize); - - /* In SVR4 ASCII format, the amount of space allocated for the header - is rounded up to the next long-word, so we might need to drop - 1-3 bytes. */ - tape_skip_padding (in_des, file_hdr->c_namesize + 110); -} - -/* Fill in FILE_HDR by reading a binary format cpio header from - file descriptor IN_DES, except for the first 6 bytes (the magic - number, device, and inode number), which are already filled in. */ - -void -read_in_binary (file_hdr, in_des) - struct new_cpio_header *file_hdr; - int in_des; -{ - struct old_cpio_header short_hdr; - - /* Copy the data into the short header, then later transfer - it into the argument long header. */ - short_hdr.c_dev = ((struct old_cpio_header *) file_hdr)->c_dev; - short_hdr.c_ino = ((struct old_cpio_header *) file_hdr)->c_ino; - tape_buffered_read (((char *) &short_hdr) + 6, in_des, 20L); - - /* If the magic number is byte swapped, fix the header. */ - if (file_hdr->c_magic == swab_short ((unsigned short) 070707)) - { - static int warned = 0; - - /* Alert the user that they might have to do byte swapping on - the file contents. */ - if (warned == 0) - { - error (0, 0, _("warning: archive header has reverse byte-order")); - warned = 1; - } - swab_array ((char *) &short_hdr, 13); - } - - file_hdr->c_dev_maj = major (short_hdr.c_dev); - file_hdr->c_dev_min = minor (short_hdr.c_dev); - file_hdr->c_ino = short_hdr.c_ino; - file_hdr->c_mode = short_hdr.c_mode; - file_hdr->c_uid = short_hdr.c_uid; - file_hdr->c_gid = short_hdr.c_gid; - file_hdr->c_nlink = short_hdr.c_nlink; - file_hdr->c_rdev_maj = major (short_hdr.c_rdev); - file_hdr->c_rdev_min = minor (short_hdr.c_rdev); - file_hdr->c_mtime = (unsigned long) short_hdr.c_mtimes[0] << 16 - | short_hdr.c_mtimes[1]; - - file_hdr->c_namesize = short_hdr.c_namesize; - file_hdr->c_filesize = (unsigned long) short_hdr.c_filesizes[0] << 16 - | short_hdr.c_filesizes[1]; - - /* Read file name from input. */ - if (file_hdr->c_name != NULL) - free (file_hdr->c_name); - file_hdr->c_name = (char *) xmalloc (file_hdr->c_namesize); - tape_buffered_read (file_hdr->c_name, in_des, (long) file_hdr->c_namesize); - - /* In binary mode, the amount of space allocated in the header for - the filename is `c_namesize' rounded up to the next short-word, - so we might need to drop a byte. */ - if (file_hdr->c_namesize % 2) - tape_toss_input (in_des, 1L); - - /* HP/UX cpio creates archives that look just like ordinary archives, - but for devices it sets major = 0, minor = 1, and puts the - actual major/minor number in the filesize field. See if this - is an HP/UX cpio archive, and if so fix it. We have to do this - here because process_copy_in() assumes filesize is always 0 - for devices. */ - switch (file_hdr->c_mode & CP_IFMT) - { - case CP_IFCHR: - case CP_IFBLK: -#ifdef CP_IFSOCK - case CP_IFSOCK: -#endif -#ifdef CP_IFIFO - case CP_IFIFO: -#endif - if (file_hdr->c_filesize != 0 - && file_hdr->c_rdev_maj == 0 - && file_hdr->c_rdev_min == 1) - { - file_hdr->c_rdev_maj = major (file_hdr->c_filesize); - file_hdr->c_rdev_min = minor (file_hdr->c_filesize); - file_hdr->c_filesize = 0; - } - break; - default: - break; - } -} - -/* Exchange the bytes of each element of the array of COUNT shorts - starting at PTR. */ - -void -swab_array (ptr, count) - char *ptr; - int count; -{ - char tmp; - - while (count-- > 0) - { - tmp = *ptr; - *ptr = *(ptr + 1); - ++ptr; - *ptr = tmp; - ++ptr; - } -} - -/* Current time for verbose table. */ -static time_t current_time; - -/* Read the collection from standard input and create files - in the file system. */ - -void -process_copy_in () -{ - char done = FALSE; /* True if trailer reached. */ - FILE *tty_in; /* Interactive file for rename option. */ - FILE *tty_out; /* Interactive file for rename option. */ - FILE *rename_in; /* Batch file for rename option. */ - struct stat file_stat; /* Output file stat record. */ - struct new_cpio_header file_hdr; /* Output header information. */ - int in_file_des; /* Input file descriptor. */ - char skip_file; /* Flag for use with patterns. */ - int i; /* Loop index variable. */ - - /* Initialize the copy in. */ - if (pattern_file_name) - { - read_pattern_file (); - } - file_hdr.c_name = NULL; - - if (rename_batch_file) - { - rename_in = fopen (rename_batch_file, "r"); - if (rename_in == NULL) - { - error (2, errno, CONSOLE); - } - } - else if (rename_flag) - { - /* Open interactive file pair for rename operation. */ - tty_in = fopen (CONSOLE, "r"); - if (tty_in == NULL) - { - error (2, errno, CONSOLE); - } - tty_out = fopen (CONSOLE, "w"); - if (tty_out == NULL) - { - error (2, errno, CONSOLE); - } - } - - /* Get date and time if needed for processing the table option. */ - if (table_flag && verbose_flag) - { - time (¤t_time); - } +static void copyin_regular_file(struct new_cpio_header* file_hdr, + int in_file_des); - /* Check whether the input file might be a tape. */ - in_file_des = archive_des; - if (_isrmt (in_file_des)) - { - input_is_special = 1; - input_is_seekable = 0; - } - else - { - if (fstat (in_file_des, &file_stat)) - error (1, errno, _("standard input is closed")); - input_is_special = -#ifdef S_ISBLK - S_ISBLK (file_stat.st_mode) || -#endif - S_ISCHR (file_stat.st_mode); - input_is_seekable = S_ISREG (file_stat.st_mode); - } - output_is_seekable = TRUE; - - /* While there is more input in the collection, process the input. */ - while (!done) - { - swapping_halfwords = swapping_bytes = FALSE; - - /* Start processing the next file by reading the header. */ - read_in_header (&file_hdr, in_file_des); - -#ifdef DEBUG_CPIO - if (debug_flag) - { - struct new_cpio_header *h; - h = &file_hdr; - fprintf (stderr, - "magic = 0%o, ino = %d, mode = 0%o, uid = %d, gid = %d\n", - h->c_magic, h->c_ino, h->c_mode, h->c_uid, h->c_gid); - fprintf (stderr, - "nlink = %d, mtime = %d, filesize = %d, dev_maj = 0x%x\n", - h->c_nlink, h->c_mtime, h->c_filesize, h->c_dev_maj); - fprintf (stderr, - "dev_min = 0x%x, rdev_maj = 0x%x, rdev_min = 0x%x, namesize = %d\n", - h->c_dev_min, h->c_rdev_maj, h->c_rdev_min, h->c_namesize); - fprintf (stderr, - "chksum = %d, name = \"%s\", tar_linkname = \"%s\"\n", - h->c_chksum, h->c_name, - h->c_tar_linkname ? h->c_tar_linkname : "(null)" ); - - } -#endif - /* Is this the header for the TRAILER file? */ - if (strcmp ("TRAILER!!!", file_hdr.c_name) == 0) - { - done = TRUE; - break; - } - - /* Do we have to ignore absolute paths, and if so, does the filename - have an absolute path? */ - if (no_abs_paths_flag && file_hdr.c_name && file_hdr.c_name [0] == '/') - { - char *p; - - p = file_hdr.c_name; - while (*p == '/') - ++p; - if (*p == '\0') - { - strcpy (file_hdr.c_name, "."); - } - else - { - /* Debian hack: file_hrd.c_name is sometimes set to - point to static memory by code in tar.c. This - causes a segfault. Therefore, memmove is used - instead of freeing and reallocating. (Reported by - Horst Knobloch.) This bug has been reported to - "bug-gnu-utils@prep.ai.mit.edu". (99/1/6) -BEM */ - (void)memmove (file_hdr.c_name, p, (size_t)(strlen (p) + 1)); - } - } - - /* Does the file name match one of the given patterns? */ - if (num_patterns <= 0) - skip_file = FALSE; - else - { - skip_file = copy_matching_files; - for (i = 0; i < num_patterns - && skip_file == copy_matching_files; i++) - { - if (fnmatch (save_patterns[i], file_hdr.c_name, 0) == 0) - skip_file = !copy_matching_files; - } - } - - if (skip_file) - { - /* If we're skipping a file with links, there might be other - links that we didn't skip, and this file might have the - data for the links. If it does, we'll copy in the data - to the links, but not to this file. */ - if (file_hdr.c_nlink > 1 && (archive_format == arf_newascii - || archive_format == arf_crcascii) ) - { - if (create_defered_links_to_skipped(&file_hdr, in_file_des) < 0) - { - tape_toss_input (in_file_des, file_hdr.c_filesize); - tape_skip_padding (in_file_des, file_hdr.c_filesize); - } - } - else - { - tape_toss_input (in_file_des, file_hdr.c_filesize); - tape_skip_padding (in_file_des, file_hdr.c_filesize); - } - } - else if (table_flag) - { - list_file(&file_hdr, in_file_des); - } - else if (append_flag) - { - tape_toss_input (in_file_des, file_hdr.c_filesize); - tape_skip_padding (in_file_des, file_hdr.c_filesize); - } - else if (only_verify_crc_flag) - { -#ifdef CP_IFLNK - if ((file_hdr.c_mode & CP_IFMT) == CP_IFLNK) - { - if (archive_format != arf_tar && archive_format != arf_ustar) - { - tape_toss_input (in_file_des, file_hdr.c_filesize); - tape_skip_padding (in_file_des, file_hdr.c_filesize); - continue; - } - } -#endif - crc = 0; - tape_toss_input (in_file_des, file_hdr.c_filesize); - tape_skip_padding (in_file_des, file_hdr.c_filesize); - if (crc != file_hdr.c_chksum) - { - error (0, 0, _("%s: checksum error (0x%x, should be 0x%x)"), - file_hdr.c_name, crc, file_hdr.c_chksum); - } - /* Debian hack: -v and -V now work with --only-verify-crc. - (99/11/10) -BEM */ - if (verbose_flag) - { - fprintf (stderr, "%s\n", file_hdr.c_name); - } - if (dot_flag) - { - fputc ('.', stderr); - } - } - else - { - /* Copy the input file into the directory structure. */ - - /* Do we need to rename the file? */ - if (rename_flag || rename_batch_file) - { - if (query_rename(&file_hdr, tty_in, tty_out, rename_in) < 0) - { - tape_toss_input (in_file_des, file_hdr.c_filesize); - tape_skip_padding (in_file_des, file_hdr.c_filesize); - continue; - } - } - - copyin_file(&file_hdr, in_file_des); - - if (verbose_flag) - fprintf (stderr, "%s\n", file_hdr.c_name); - if (dot_flag) - fputc ('.', stderr); - } - } - - if (dot_flag) - fputc ('\n', stderr); - - if (append_flag) - return; - - if (archive_format == arf_newascii || archive_format == arf_crcascii) - { - create_final_defers (); - } - if (!quiet_flag) - { - int blocks; - blocks = (input_bytes + io_block_size - 1) / io_block_size; - fprintf (stderr, ngettext ("%d block\n", "%d blocks\n", blocks), blocks); - } -} static int -query_rename(file_hdr, tty_in, tty_out, rename_in) - struct new_cpio_header* file_hdr; - FILE *tty_in; - FILE *tty_out; - FILE *rename_in; +query_rename(struct new_cpio_header* file_hdr, FILE *tty_in, FILE *tty_out, + FILE *rename_in) { char *str_res; /* Result for string function. */ static dynamic_string new_name; /* New file name for rename option. */ - static int initialized_new_name = FALSE; + static int initialized_new_name = false; if (!initialized_new_name) { ds_init (&new_name, 128); - initialized_new_name = TRUE; + initialized_new_name = true; } if (rename_flag) @@ -679,10 +91,33 @@ query_rename(file_hdr, tty_in, tty_out, rename_in) return 0; } +/* Skip the padding on IN_FILE_DES after a header or file, + up to the next header. + The number of bytes skipped is based on OFFSET -- the current offset + from the last start of a header (or file) -- and the current + header type. */ + static void -list_file(file_hdr, in_file_des) - struct new_cpio_header* file_hdr; - int in_file_des; +tape_skip_padding (int in_file_des, int offset) +{ + int pad; + + if (archive_format == arf_crcascii || archive_format == arf_newascii) + pad = (4 - (offset % 4)) % 4; + else if (archive_format == arf_binary || archive_format == arf_hpbinary) + pad = (2 - (offset % 2)) % 2; + else if (archive_format == arf_tar || archive_format == arf_ustar) + pad = (512 - (offset % 512)) % 512; + else + pad = 0; + + if (pad != 0) + tape_toss_input (in_file_des, pad); +} + + +static void +list_file(struct new_cpio_header* file_hdr, int in_file_des) { if (verbose_flag) { @@ -739,62 +174,13 @@ list_file(file_hdr, in_file_des) } } -static void -copyin_file(file_hdr, in_file_des) - struct new_cpio_header* file_hdr; - int in_file_des; -{ - int existing_dir; - - if (try_existing_file(file_hdr, in_file_des, &existing_dir) < 0) - { - return; - } - - /* Do the real copy or link. */ - switch (file_hdr->c_mode & CP_IFMT) - { - case CP_IFREG: - copyin_regular_file(file_hdr, in_file_des); - break; - - case CP_IFDIR: - copyin_directory(file_hdr, existing_dir); - break; - - case CP_IFCHR: - case CP_IFBLK: -#ifdef CP_IFSOCK - case CP_IFSOCK: -#endif -#ifdef CP_IFIFO - case CP_IFIFO: -#endif - copyin_device(file_hdr); - break; - -#ifdef CP_IFLNK - case CP_IFLNK: - copyin_link(file_hdr, in_file_des); - break; -#endif - - default: - error (0, 0, _("%s: unknown file type"), file_hdr->c_name); - tape_toss_input (in_file_des, file_hdr->c_filesize); - tape_skip_padding (in_file_des, file_hdr->c_filesize); - } -} - static int -try_existing_file(file_hdr, in_file_des, existing_dir) - struct new_cpio_header* file_hdr; - int in_file_des; - int* existing_dir; +try_existing_file(struct new_cpio_header* file_hdr, int in_file_des, + int *existing_dir) { struct stat file_stat; - *existing_dir = FALSE; + *existing_dir = false; if (lstat (file_hdr->c_name, &file_stat) == 0) { if (S_ISDIR (file_stat.st_mode) @@ -803,7 +189,7 @@ try_existing_file(file_hdr, in_file_des, existing_dir) /* If there is already a directory there that we are trying to create, don't complain about it. */ - *existing_dir = TRUE; + *existing_dir = true; return 0; } else if (!unconditional_flag @@ -829,10 +215,196 @@ try_existing_file(file_hdr, in_file_des, existing_dir) return 0; } +/* The newc and crc formats store multiply linked copies of the same file + in the archive only once. The actual data is attached to the last link + in the archive, and the other links all have a filesize of 0. When a + file in the archive has multiple links and a filesize of 0, its data is + probably "attatched" to another file in the archive, so we can't create + it right away. We have to "defer" creating it until we have created + the file that has the data "attatched" to it. We keep a list of the + "defered" links on deferments. */ + +struct deferment *deferments = NULL; + +/* Add a file header to the deferments list. For now they all just + go on one list, although we could optimize this if necessary. */ + +static void +defer_copyin (struct new_cpio_header *file_hdr) +{ + struct deferment *d; + d = create_deferment (file_hdr); + d->next = deferments; + deferments = d; + return; +} + +/* We just created a file that (probably) has some other links to it + which have been defered. Go through all of the links on the deferments + list and create any which are links to this file. */ + +static void +create_defered_links (struct new_cpio_header *file_hdr) +{ + struct deferment *d; + struct deferment *d_prev; + int ino; + int maj; + int min; + int link_res; + ino = file_hdr->c_ino; + maj = file_hdr->c_dev_maj; + min = file_hdr->c_dev_min; + d = deferments; + d_prev = NULL; + while (d != NULL) + { + if ( (d->header.c_ino == ino) && (d->header.c_dev_maj == maj) + && (d->header.c_dev_min == min) ) + { + struct deferment *d_free; + link_res = link_to_name (d->header.c_name, file_hdr->c_name); + if (link_res < 0) + { + error (0, errno, _("cannot link %s to %s"), + d->header.c_name, file_hdr->c_name); + } + if (d_prev != NULL) + d_prev->next = d->next; + else + deferments = d->next; + d_free = d; + d = d->next; + free_deferment (d_free); + } + else + { + d_prev = d; + d = d->next; + } + } +} + +/* We are skipping a file but there might be other links to it that we + did not skip, so we have to copy its data for the other links. Find + the first link that we didn't skip and try to create that. That will + then create the other deferred links. */ + +static int +create_defered_links_to_skipped (struct new_cpio_header *file_hdr, + int in_file_des) +{ + struct deferment *d; + struct deferment *d_prev; + int ino; + int maj; + int min; + int link_res; + if (file_hdr->c_filesize == 0) + { + /* The file doesn't have any data attached to it so we don't have + to bother. */ + return -1; + } + ino = file_hdr->c_ino; + maj = file_hdr->c_dev_maj; + min = file_hdr->c_dev_min; + d = deferments; + d_prev = NULL; + while (d != NULL) + { + if ( (d->header.c_ino == ino) && (d->header.c_dev_maj == maj) + && (d->header.c_dev_min == min) ) + { + if (d_prev != NULL) + d_prev->next = d->next; + else + deferments = d->next; + free (file_hdr->c_name); + file_hdr->c_name = xstrdup(d->header.c_name); + free_deferment (d); + copyin_regular_file(file_hdr, in_file_des); + return 0; + } + else + { + d_prev = d; + d = d->next; + } + } + return -1; +} + +/* If we had a multiply linked file that really was empty then we would + have defered all of its links, since we never found any with data + "attached", and they will still be on the deferment list even when + we are done reading the whole archive. Write out all of these + empty links that are still on the deferments list. */ + +static void +create_final_defers () +{ + struct deferment *d; + int link_res; + int out_file_des; + struct utimbuf times; /* For setting file times. */ + /* Initialize this in case it has members we don't know to set. */ + bzero (×, sizeof (struct utimbuf)); + + for (d = deferments; d != NULL; d = d->next) + { + /* Debian hack: A line, which could cause an endless loop, was + removed (97/1/2). It was reported by Ronald F. Guilmette to + the upstream maintainers. -BEM */ + /* Debian hack: This was reported by Horst Knobloch. This bug has + been reported to "bug-gnu-utils@prep.ai.mit.edu". (99/1/6) -BEM + */ + link_res = link_to_maj_min_ino (d->header.c_name, + d->header.c_dev_maj, d->header.c_dev_min, + d->header.c_ino); + if (link_res == 0) + { + continue; + } + out_file_des = open (d->header.c_name, + O_CREAT | O_WRONLY | O_BINARY, 0600); + if (out_file_des < 0 && create_dir_flag) + { + create_all_directories (d->header.c_name); + out_file_des = open (d->header.c_name, + O_CREAT | O_WRONLY | O_BINARY, + 0600); + } + if (out_file_des < 0) + { + error (0, errno, "%s", d->header.c_name); + continue; + } + + if (close (out_file_des) < 0) + error (0, errno, "%s", d->header.c_name); + + /* File is now copied; set attributes. */ + if (!no_chown_flag) + if ((chown (d->header.c_name, + set_owner_flag ? set_owner : d->header.c_uid, + set_group_flag ? set_group : d->header.c_gid) < 0) + && errno != EPERM) + error (0, errno, "%s", d->header.c_name); + /* chown may have turned off some permissions we wanted. */ + if (chmod (d->header.c_name, (int) d->header.c_mode) < 0) + error (0, errno, "%s", d->header.c_name); + if (retain_time_flag) + { + times.actime = times.modtime = d->header.c_mtime; + if (utime (d->header.c_name, ×) < 0) + error (0, errno, "%s", d->header.c_name); + } + } +} + static void -copyin_regular_file(file_hdr, in_file_des) - struct new_cpio_header* file_hdr; - int in_file_des; +copyin_regular_file(struct new_cpio_header* file_hdr, int in_file_des) { int out_file_des; /* Output file descriptor. */ @@ -931,7 +503,7 @@ copyin_regular_file(file_hdr, in_file_des) if (swap_halfwords_flag) { if ((file_hdr->c_filesize % 4) == 0) - swapping_halfwords = TRUE; + swapping_halfwords = true; else error (0, 0, _("cannot swap halfwords of %s: odd number of halfwords"), file_hdr->c_name); @@ -939,7 +511,7 @@ copyin_regular_file(file_hdr, in_file_des) if (swap_bytes_flag) { if ((file_hdr->c_filesize % 2) == 0) - swapping_bytes = TRUE; + swapping_bytes = true; else error (0, 0, _("cannot swap bytes of %s: odd number of bytes"), file_hdr->c_name); @@ -997,9 +569,7 @@ copyin_regular_file(file_hdr, in_file_des) } static void -copyin_directory(file_hdr, existing_dir) - struct new_cpio_header* file_hdr; - int existing_dir; +copyin_directory(struct new_cpio_header* file_hdr, int existing_dir) { int res; /* Result of various function calls. */ #ifdef HPUX_CDF @@ -1092,8 +662,7 @@ copyin_directory(file_hdr, existing_dir) } static void -copyin_device(file_hdr) - struct new_cpio_header* file_hdr; +copyin_device(struct new_cpio_header* file_hdr) { int res; /* Result of various function calls. */ @@ -1168,9 +737,7 @@ copyin_device(file_hdr) } static void -copyin_link(file_hdr, in_file_des) - struct new_cpio_header* file_hdr; - int in_file_des; +copyin_link(struct new_cpio_header *file_hdr, int in_file_des) { char *link_name = NULL; /* Name of hard and symbolic links. */ int res; /* Result of various function calls. */ @@ -1212,14 +779,62 @@ copyin_link(file_hdr, in_file_des) free (link_name); } +stat |