aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2004-09-06 14:04:53 +0000
committerSergey Poznyakoff <gray@gnu.org.ua>2004-09-06 14:04:53 +0000
commit73636cd24d6c3c5d6b9e41ac9ea75de4b73ce4c9 (patch)
tree9ace8aff250c2be68bdd4d66652c0f6e6aff02b5
parente8818871ebdc0b85272d32a32b8cbfb41cbe11ce (diff)
downloadcpio-73636cd24d6c3c5d6b9e41ac9ea75de4b73ce4c9.tar.gz
cpio-73636cd24d6c3c5d6b9e41ac9ea75de4b73ce4c9.tar.bz2
Switched to ANSI C (sigh)
-rw-r--r--src/copyin.c1645
-rw-r--r--src/copyout.c559
-rw-r--r--src/copypass.c25
-rw-r--r--src/defer.c14
-rw-r--r--src/defer.h2
-rw-r--r--src/dstring.c23
-rw-r--r--src/dstring.h12
-rw-r--r--src/extern.h23
-rw-r--r--src/filemode.c133
-rw-r--r--src/global.c125
-rw-r--r--src/idcache.c14
-rw-r--r--src/main.c67
-rw-r--r--src/makepath.c17
-rw-r--r--src/mt.c156
-rw-r--r--src/tar.c190
-rw-r--r--src/userspec.c18
-rw-r--r--src/util.c252
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 (&current_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 (&times, 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, &times) < 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