diff options
Diffstat (limited to 'contrib/cpio/src/copyin.c')
-rw-r--r-- | contrib/cpio/src/copyin.c | 1644 |
1 files changed, 0 insertions, 1644 deletions
diff --git a/contrib/cpio/src/copyin.c b/contrib/cpio/src/copyin.c deleted file mode 100644 index 5659136..0000000 --- a/contrib/cpio/src/copyin.c +++ /dev/null @@ -1,1644 +0,0 @@ -/* $FreeBSD$ */ - -/* copyin.c - extract or list a cpio archive - Copyright (C) 1990,1991,1992,2001,2002,2003,2004, - 2005, 2006 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 - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public - License along with this program; if not, write to the Free - Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301 USA. */ - -#include <system.h> - -#include <stdio.h> -#include <sys/types.h> -#include <sys/stat.h> -#include "filetypes.h" -#include "cpiohdr.h" -#include "dstring.h" -#include "extern.h" -#include "defer.h" -#include "dirname.h" -#include <rmt.h> -#ifndef FNM_PATHNAME -# include <fnmatch.h> -#endif -#include <langinfo.h> - -#ifndef HAVE_LCHOWN -# define lchown(f,u,g) 0 -#endif - -static void copyin_regular_file(struct cpio_file_stat* file_hdr, - int in_file_des); - -void -warn_junk_bytes (long bytes_skipped) -{ - error (0, 0, ngettext ("warning: skipped %ld byte of junk", - "warning: skipped %ld bytes of junk", bytes_skipped), - bytes_skipped); -} - - -static int -query_rename(struct cpio_file_stat* 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; - if (!initialized_new_name) - { - ds_init (&new_name, 128); - initialized_new_name = true; - } - - if (rename_flag) - { - fprintf (tty_out, _("rename %s -> "), file_hdr->c_name); - fflush (tty_out); - str_res = ds_fgets (tty_in, &new_name); - } - else - { - str_res = ds_fgetstr (rename_in, &new_name, '\n'); - } - if (str_res == NULL || str_res[0] == 0) - { - return -1; - } - else - /* Debian hack: file_hrd.c_name is sometimes set to - point to static memory by code in tar.c. This - causes a segfault. This has been fixed and an - additional check to ensure that the file name - is not too long has been added. (Reported by - Horst Knobloch.) This bug has been reported to - "bug-gnu-utils@prep.ai.mit.edu". (99/1/6) -BEM */ - { - if (archive_format != arf_tar && archive_format != arf_ustar) - { - free (file_hdr->c_name); - file_hdr->c_name = xstrdup (new_name.ds_string); - } - else - { - if (is_tar_filename_too_long (new_name.ds_string)) - error (0, 0, _("%s: file name too long"), - new_name.ds_string); - else - strcpy (file_hdr->c_name, new_name.ds_string); - } - } - 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 -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 cpio_file_stat* file_hdr, int in_file_des) -{ - if (verbose_flag) - { -#ifdef CP_IFLNK - if ((file_hdr->c_mode & CP_IFMT) == CP_IFLNK) - { - if (archive_format != arf_tar && archive_format != arf_ustar) - { - char *link_name = NULL; /* Name of hard and symbolic links. */ - - link_name = (char *) xmalloc ((unsigned int) file_hdr->c_filesize + 1); - link_name[file_hdr->c_filesize] = '\0'; - tape_buffered_read (link_name, in_file_des, file_hdr->c_filesize); - long_format (file_hdr, link_name); - free (link_name); - tape_skip_padding (in_file_des, file_hdr->c_filesize); - return; - } - else - { - long_format (file_hdr, file_hdr->c_tar_linkname); - return; - } - } - else -#endif - long_format (file_hdr, (char *) 0); - } - else - { - /* Debian hack: Modified to print a list of filenames - terminiated by a null character when the -t and -0 - flags are used. This has been submitted as a - suggestion to "bug-gnu-utils@prep.ai.mit.edu". -BEM */ - printf ("%s%c", file_hdr->c_name, name_end); - } - - crc = 0; - tape_toss_input (in_file_des, file_hdr->c_filesize); - tape_skip_padding (in_file_des, file_hdr->c_filesize); - if (only_verify_crc_flag) - { -#ifdef CP_IFLNK - if ((file_hdr->c_mode & CP_IFMT) == CP_IFLNK) - { - return; /* links don't have a checksum */ - } -#endif - if (crc != file_hdr->c_chksum) - { - error (0, 0, _("%s: checksum error (0x%lx, should be 0x%lx)"), - file_hdr->c_name, crc, file_hdr->c_chksum); - } - } -} - -static int -try_existing_file (struct cpio_file_stat* file_hdr, int in_file_des, - int *existing_dir) -{ - struct stat file_stat; - - *existing_dir = false; - if (lstat (file_hdr->c_name, &file_stat) == 0) - { - if (S_ISDIR (file_stat.st_mode) - && ((file_hdr->c_mode & CP_IFMT) == CP_IFDIR)) - { - /* If there is already a directory there that - we are trying to create, don't complain about - it. */ - *existing_dir = true; - return 0; - } - else if (!unconditional_flag - && file_hdr->c_mtime <= file_stat.st_mtime) - { - error (0, 0, _("%s not created: newer or same age version exists"), - file_hdr->c_name); - tape_toss_input (in_file_des, file_hdr->c_filesize); - tape_skip_padding (in_file_des, file_hdr->c_filesize); - return -1; /* Go to the next file. */ - } - else if (S_ISDIR (file_stat.st_mode) - ? rmdir (file_hdr->c_name) - : unlink (file_hdr->c_name)) - { - error (0, errno, _("cannot remove current %s"), - file_hdr->c_name); - tape_toss_input (in_file_des, file_hdr->c_filesize); - tape_skip_padding (in_file_des, file_hdr->c_filesize); - return -1; /* Go to the next file. */ - } - } - 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 cpio_file_stat *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 cpio_file_stat *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 cpio_file_stat *file_hdr, - int in_file_des) -{ - struct deferment *d; - struct deferment *d_prev; - int ino; - int maj; - int min; - 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; - - 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) - { - open_error (d->header.c_name); - continue; - } - - set_perms (out_file_des, &d->header); - - if (close (out_file_des) < 0) - close_error (d->header.c_name); - - } -} - -static void -copyin_regular_file (struct cpio_file_stat* file_hdr, int in_file_des) -{ - int out_file_des; /* Output file descriptor. */ - - if (to_stdout_option) - out_file_des = STDOUT_FILENO; - else - { - /* Can the current file be linked to a previously copied file? */ - if (file_hdr->c_nlink > 1 - && (archive_format == arf_newascii - || archive_format == arf_crcascii) ) - { - int link_res; - if (file_hdr->c_filesize == 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. Since this file has multiple links and a - filesize of 0, its data is probably attatched to - another file in the archive. Save the link, and - process it later when we get the actual data. We - can't just create it with length 0 and add the - data later, in case the file is readonly. We still - lose if its parent directory is readonly (and we aren't - running as root), but there's nothing we can do about - that. */ - defer_copyin (file_hdr); - tape_toss_input (in_file_des, file_hdr->c_filesize); - tape_skip_padding (in_file_des, file_hdr->c_filesize); - return; - } - /* If the file has data (filesize != 0), then presumably - any other links have already been defer_copyin'ed(), - but GNU cpio version 2.0-2.2 didn't do that, so we - still have to check for links here (and also in case - the archive was created and later appeneded to). */ - /* Debian hack: (97/1/2) This was reported by Ronald - F. Guilmette to the upstream maintainers. -BEM */ - link_res = link_to_maj_min_ino (file_hdr->c_name, - file_hdr->c_dev_maj, file_hdr->c_dev_min, - file_hdr->c_ino); - if (link_res == 0) - { - tape_toss_input (in_file_des, file_hdr->c_filesize); - tape_skip_padding (in_file_des, file_hdr->c_filesize); - return; - } - } - else if (file_hdr->c_nlink > 1 - && archive_format != arf_tar - && archive_format != arf_ustar) - { - int link_res; - /* Debian hack: (97/1/2) This was reported by Ronald - F. Guilmette to the upstream maintainers. -BEM */ - link_res = link_to_maj_min_ino (file_hdr->c_name, - file_hdr->c_dev_maj, - file_hdr->c_dev_min, - file_hdr->c_ino); - if (link_res == 0) - { - tape_toss_input (in_file_des, file_hdr->c_filesize); - tape_skip_padding (in_file_des, file_hdr->c_filesize); - return; - } - } - else if ((archive_format == arf_tar || archive_format == arf_ustar) - && file_hdr->c_tar_linkname - && file_hdr->c_tar_linkname[0] != '\0') - { - int link_res; - link_res = link_to_name (file_hdr->c_name, file_hdr->c_tar_linkname); - if (link_res < 0) - { - error (0, errno, _("cannot link %s to %s"), - file_hdr->c_tar_linkname, file_hdr->c_name); - } - return; - } - - /* If not linked, copy the contents of the file. */ - out_file_des = open (file_hdr->c_name, - O_CREAT | O_WRONLY | O_BINARY, 0600); - - if (out_file_des < 0 && create_dir_flag) - { - create_all_directories (file_hdr->c_name); - out_file_des = open (file_hdr->c_name, - O_CREAT | O_WRONLY | O_BINARY, - 0600); - } - - if (out_file_des < 0) - { - open_error (file_hdr->c_name); - tape_toss_input (in_file_des, file_hdr->c_filesize); - tape_skip_padding (in_file_des, file_hdr->c_filesize); - return; - } - } - - crc = 0; - if (swap_halfwords_flag) - { - if ((file_hdr->c_filesize % 4) == 0) - swapping_halfwords = true; - else - error (0, 0, _("cannot swap halfwords of %s: odd number of halfwords"), - file_hdr->c_name); - } - if (swap_bytes_flag) - { - if ((file_hdr->c_filesize % 2) == 0) - swapping_bytes = true; - else - error (0, 0, _("cannot swap bytes of %s: odd number of bytes"), - file_hdr->c_name); - } - copy_files_tape_to_disk (in_file_des, out_file_des, file_hdr->c_filesize); - disk_empty_output_buffer (out_file_des); - - if (to_stdout_option) - { - if (archive_format == arf_crcascii) - { - if (crc != file_hdr->c_chksum) - error (0, 0, _("%s: checksum error (0x%lx, should be 0x%lx)"), - file_hdr->c_name, crc, file_hdr->c_chksum); - } - tape_skip_padding (in_file_des, file_hdr->c_filesize); - return; - } - - /* Debian hack to fix a bug in the --sparse option. - This bug has been reported to - "bug-gnu-utils@prep.ai.mit.edu". (96/7/10) -BEM */ - if (delayed_seek_count > 0) - { - lseek (out_file_des, delayed_seek_count-1, SEEK_CUR); - write (out_file_des, "", 1); - delayed_seek_count = 0; - } - - set_perms (out_file_des, file_hdr); - - if (close (out_file_des) < 0) - close_error (file_hdr->c_name); - - if (archive_format == arf_crcascii) - { - if (crc != file_hdr->c_chksum) - error (0, 0, _("%s: checksum error (0x%lx, should be 0x%lx)"), - file_hdr->c_name, crc, file_hdr->c_chksum); - } - - tape_skip_padding (in_file_des, file_hdr->c_filesize); - if (file_hdr->c_nlink > 1 - && (archive_format == arf_newascii || archive_format == arf_crcascii) ) - { - /* (see comment above for how the newc and crc formats - store multiple links). Now that we have the data - for this file, create any other links to it which - we defered. */ - create_defered_links (file_hdr); - } -} - -static void -copyin_directory (struct cpio_file_stat *file_hdr, int existing_dir) -{ - int res; /* Result of various function calls. */ -#ifdef HPUX_CDF - int cdf_flag; /* True if file is a CDF. */ - int cdf_char; /* Index of `+' char indicating a CDF. */ -#endif - - if (to_stdout_option) - return; - - /* Strip any trailing `/'s off the filename; tar puts - them on. We might as well do it here in case anybody - else does too, since they cause strange things to happen. */ - strip_trailing_slashes (file_hdr->c_name); - - /* Ignore the current directory. It must already exist, - and we don't want to change its permission, ownership - or time. */ - if (file_hdr->c_name[0] == '.' && file_hdr->c_name[1] == '\0') - { - return; - } - -#ifdef HPUX_CDF - cdf_flag = 0; -#endif - if (!existing_dir) - - { -#ifdef HPUX_CDF - /* If the directory name ends in a + and is SUID, - then it is a CDF. Strip the trailing + from - the name before creating it. */ - cdf_char = strlen (file_hdr->c_name) - 1; - if ( (cdf_char > 0) && - (file_hdr->c_mode & 04000) && - (file_hdr->c_name [cdf_char] == '+') ) - { - file_hdr->c_name [cdf_char] = '\0'; - cdf_flag = 1; - } -#endif - res = mkdir (file_hdr->c_name, file_hdr->c_mode); - } - else - res = 0; - if (res < 0 && create_dir_flag) - { - create_all_directories (file_hdr->c_name); - res = mkdir (file_hdr->c_name, file_hdr->c_mode); - } - if (res < 0) - { - /* In some odd cases where the file_hdr->c_name includes `.', - the directory may have actually been created by - create_all_directories(), so the mkdir will fail - because the directory exists. If that's the case, - don't complain about it. */ - struct stat file_stat; - if (errno != EEXIST) - { - mkdir_error (file_hdr->c_name); - return; - } - if (lstat (file_hdr->c_name, &file_stat)) - { - stat_error (file_hdr->c_name); - return; - } - if (!(S_ISDIR (file_stat.st_mode))) - { - error (0, 0, _("%s is not a directory"), - quotearg_colon (file_hdr->c_name)); - return; - } - } - - set_perms (-1, file_hdr); -} - -static void -copyin_device (struct cpio_file_stat* file_hdr) -{ - int res; /* Result of various function calls. */ - - if (to_stdout_option) - return; - - if (file_hdr->c_nlink > 1 && archive_format != arf_tar - && archive_format != arf_ustar) - { - int link_res; - /* 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 (file_hdr->c_name, - file_hdr->c_dev_maj, file_hdr->c_dev_min, - file_hdr->c_ino); - if (link_res == 0) - { - return; - } - } - else if (archive_format == arf_ustar && - file_hdr->c_tar_linkname && - file_hdr->c_tar_linkname [0] != '\0') - { - int link_res; - link_res = link_to_name (file_hdr->c_name, - file_hdr->c_tar_linkname); - if (link_res < 0) - { - error (0, errno, _("cannot link %s to %s"), - file_hdr->c_tar_linkname, file_hdr->c_name); - /* Something must be wrong, because we couldn't - find the file to link to. But can we assume - that the device maj/min numbers are correct - and fall through to the mknod? It's probably - safer to just return, rather than possibly - creating a bogus device file. */ - } - return; - } - -#ifdef CP_IFIFO - if ((file_hdr->c_mode & CP_IFMT) == CP_IFIFO) - res = mkfifo (file_hdr->c_name, file_hdr->c_mode); - else -#endif - res = mknod (file_hdr->c_name, file_hdr->c_mode, - makedev (file_hdr->c_rdev_maj, file_hdr->c_rdev_min)); - if (res < 0 && create_dir_flag) - { - create_all_directories (file_hdr->c_name); -#ifdef CP_IFIFO - if ((file_hdr->c_mode & CP_IFMT) == CP_IFIFO) - res = mkfifo (file_hdr->c_name, file_hdr->c_mode); - else -#endif - res = mknod (file_hdr->c_name, file_hdr->c_mode, - makedev (file_hdr->c_rdev_maj, file_hdr->c_rdev_min)); - } - if (res < 0) - { - mknod_error (file_hdr->c_name); - return; - } - if (!no_chown_flag) - { - uid_t uid = set_owner_flag ? set_owner : file_hdr->c_uid; - gid_t gid = set_group_flag ? set_group : file_hdr->c_gid; - if ((chown (file_hdr->c_name, uid, gid) < 0) - && errno != EPERM) - chown_error_details (file_hdr->c_name, uid, gid); - } - /* chown may have turned off some permissions we wanted. */ - if (chmod (file_hdr->c_name, file_hdr->c_mode) < 0) - chmod_error_details (file_hdr->c_name, file_hdr->c_mode); - if (retain_time_flag) - set_file_times (-1, file_hdr->c_name, file_hdr->c_mtime, - file_hdr->c_mtime); -} - -static void -copyin_link(struct cpio_file_stat *file_hdr, int in_file_des) -{ - char *link_name = NULL; /* Name of hard and symbolic links. */ - int res; /* Result of various function calls. */ - - if (to_stdout_option) - return; - - if (archive_format != arf_tar && archive_format != arf_ustar) - { - link_name = (char *) xmalloc ((unsigned int) file_hdr->c_filesize + 1); - link_name[file_hdr->c_filesize] = '\0'; - tape_buffered_read (link_name, in_file_des, file_hdr->c_filesize); - tape_skip_padding (in_file_des, file_hdr->c_filesize); - } - else - { - link_name = xstrdup (file_hdr->c_tar_linkname); - } - - res = UMASKED_SYMLINK (link_name, file_hdr->c_name, - file_hdr->c_mode); - if (res < 0 && create_dir_flag) - { - create_all_directories (file_hdr->c_name); - res = UMASKED_SYMLINK (link_name, file_hdr->c_name, - file_hdr->c_mode); - } - if (res < 0) - { - error (0, errno, _("%s: Cannot symlink to %s"), - quotearg_colon (link_name), quote_n (1, file_hdr->c_name)); - free (link_name); - return; - } - if (!no_chown_flag) - { - uid_t uid = set_owner_flag ? set_owner : file_hdr->c_uid; - gid_t gid = set_group_flag ? set_group : file_hdr->c_gid; - if ((lchown (file_hdr->c_name, uid, gid) < 0) - && errno != EPERM) - chown_error_details (file_hdr->c_name, uid, gid); - } - free (link_name); -} - -static void -copyin_file (struct cpio_file_stat* file_hdr, int in_file_des) -{ - int existing_dir; - - if (!to_stdout_option - && 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); - } -} - - -/* Current time for verbose table. */ -static time_t current_time; - - -/* Print the file described by FILE_HDR in long format. - If LINK_NAME is nonzero, it is the name of the file that - this file is a symbolic link to. */ - -void -long_format (struct cpio_file_stat *file_hdr, char *link_name) -{ - char mbuf[11]; - char tbuf[40]; - time_t when; - char *ptbuf; - static int d_first = -1; - - mode_string (file_hdr->c_mode, mbuf); - mbuf[10] = '\0'; - - /* Get time values ready to print. */ - when = file_hdr->c_mtime; - if (d_first < 0) - d_first = (*nl_langinfo(D_MD_ORDER) == 'd'); - if (current_time - when > 6L * 30L * 24L * 60L * 60L - || current_time - when < 0L) - ptbuf = d_first ? "%e %b %Y" : "%b %e %Y"; - else - ptbuf = d_first ? "%e %b %R" : "%b %e %R"; - strftime(tbuf, sizeof(tbuf), ptbuf, localtime(&when)); - ptbuf = tbuf; - - printf ("%s %3lu ", mbuf, file_hdr->c_nlink); - - if (numeric_uid) - printf ("%-8u %-8u ", (unsigned int) file_hdr->c_uid, - (unsigned int) file_hdr->c_gid); - else - printf ("%-8.8s %-8.8s ", getuser (file_hdr->c_uid), - getgroup (file_hdr->c_gid)); - - if ((file_hdr->c_mode & CP_IFMT) == CP_IFCHR - || (file_hdr->c_mode & CP_IFMT) == CP_IFBLK) - printf ("%3lu, %3lu ", file_hdr->c_rdev_maj, - file_hdr->c_rdev_min); - else - printf ("%8"PRIuMAX" ", (uintmax_t) file_hdr->c_filesize); - - printf ("%s ", ptbuf); - - print_name_with_quoting (file_hdr->c_name); - if (link_name) - { - printf (" -> "); - print_name_with_quoting (link_name); - } - putc ('\n', stdout); -} - -void -print_name_with_quoting (register char *p) -{ - register unsigned char c; - - while ( (c = *p++) ) - { - switch (c) - { - case '\\': - printf ("\\\\"); - break; - - case '\n': - printf ("\\n"); - break; - - case '\b': - printf ("\\b"); - break; - - case '\r': - printf ("\\r"); - break; - - case '\t': - printf ("\\t"); - break; - - case '\f': - printf ("\\f"); - break; - - case ' ': - printf ("\\ "); - break; - - case '"': - printf ("\\\""); - break; - - default: - if (isprint (c)) - putchar (c); - else - printf ("\\%03o", (unsigned int) c); - } - } -} - -/* Read a pattern file (for the -E option). Put a list of - `num_patterns' elements in `save_patterns'. Any patterns that were - already in `save_patterns' (from the command line) are preserved. */ - -static void -read_pattern_file () -{ - int max_new_patterns; - char **new_save_patterns; - int new_num_patterns; - int i; - dynamic_string pattern_name; - FILE *pattern_fp; - - if (num_patterns < 0) - num_patterns = 0; - max_new_patterns = 1 + num_patterns; - new_save_patterns = (char **) xmalloc (max_new_patterns * sizeof (char *)); - new_num_patterns = num_patterns; - ds_init (&pattern_name, 128); - - pattern_fp = fopen (pattern_file_name, "r"); - if (pattern_fp == NULL) - open_error (pattern_file_name); - while (ds_fgetstr (pattern_fp, &pattern_name, '\n') != NULL) - { - if (new_num_patterns >= max_new_patterns) - { - max_new_patterns += 1; - new_save_patterns = (char **) - xrealloc ((char *) new_save_patterns, - max_new_patterns * sizeof (char *)); - } - new_save_patterns[new_num_patterns] = xstrdup (pattern_name.ds_string); - ++new_num_patterns; - } - if (ferror (pattern_fp) || fclose (pattern_fp) == EOF) - close_error (pattern_file_name); - - for (i = 0; i < num_patterns; ++i) - new_save_patterns[i] = save_patterns[i]; - - save_patterns = new_save_patterns; - num_patterns = new_num_patterns; -} - - -uintmax_t -from_ascii (char const *where, size_t digs, unsigned logbase) -{ - uintmax_t value = 0; - char const *buf = where; - char const *end = buf + digs; - int overflow = 0; - static char codetab[] = "0123456789ABCDEF"; - - for (; *buf == ' '; buf++) - { - if (buf == end) - return 0; - } - - if (buf == end || *buf == 0) - return 0; - while (1) - { - unsigned d; - - char *p = strchr (codetab, toupper (*buf)); - if (!p) - { - error (0, 0, _("Malformed number %.*s"), digs, where); - break; - } - - d = p - codetab; - if ((d >> logbase) > 1) - { - error (0, 0, _("Malformed number %.*s"), digs, where); - break; - } - value += d; - if (++buf == end || *buf == 0) - break; - overflow |= value ^ (value << logbase >> logbase); - value <<= logbase; - } - if (overflow) - error (0, 0, _("Archive value %.*s is out of range"), - digs, where); - return value; -} - - - -/* 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 (struct cpio_file_stat *file_hdr, int in_des) -{ - union { - char str[6]; - unsigned short num; - struct old_cpio_header old_header; - } magic; - 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) - warn_junk_bytes (bytes_skipped); - - read_in_tar_header (file_hdr, in_des); - return; - } - - file_hdr->c_tar_linkname = NULL; - - tape_buffered_read (magic.str, 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 (magic.str, "070701", 6)) - { - if (bytes_skipped > 0) - warn_junk_bytes (bytes_skipped); - file_hdr->c_magic = 070701; - read_in_new_ascii (file_hdr, in_des); - break; - } - if (archive_format == arf_crcascii - && !strncmp (magic.str, "070702", 6)) - { - if (bytes_skipped > 0) - warn_junk_bytes (bytes_skipped); - file_hdr->c_magic = 070702; - read_in_new_ascii (file_hdr, in_des); - break; - } - if ( (archive_format == arf_oldascii || archive_format == arf_hpoldascii) - && !strncmp (magic.str, "070707", 6)) - { - if (bytes_skipped > 0) - warn_junk_bytes (bytes_skipped); - file_hdr->c_magic = 070707; - read_in_old_ascii (file_hdr, in_des); - break; - } - if ( (archive_format == arf_binary || archive_format == arf_hpbinary) - && (magic.num == 070707 - || magic.num == swab_short ((unsigned short) 070707))) - { - /* Having to skip 1 byte because of word alignment is normal. */ - if (bytes_skipped > 0) - warn_junk_bytes (bytes_skipped); - file_hdr->c_magic = 070707; - read_in_binary (file_hdr, &magic.old_header, in_des); - break; - } - bytes_skipped++; - memmove (magic.str, magic.str + 1, 5); - tape_buffered_read (magic.str, 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 (struct cpio_file_stat *file_hdr, int in_des) -{ - struct old_ascii_header ascii_header; - unsigned long dev; - - tape_buffered_read (ascii_header.c_dev, in_des, - sizeof ascii_header - sizeof ascii_header.c_magic); - dev = FROM_OCTAL (ascii_header.c_dev); - file_hdr->c_dev_maj = major (dev); - file_hdr->c_dev_min = minor (dev); - - file_hdr->c_ino = FROM_OCTAL (ascii_header.c_ino); - file_hdr->c_mode = FROM_OCTAL (ascii_header.c_mode); - file_hdr->c_uid = FROM_OCTAL (ascii_header.c_uid); - file_hdr->c_gid = FROM_OCTAL (ascii_header.c_gid); - file_hdr->c_nlink = FROM_OCTAL (ascii_header.c_nlink); - dev = FROM_OCTAL (ascii_header.c_rdev); - file_hdr->c_rdev_maj = major (dev); - file_hdr->c_rdev_min = minor (dev); - - file_hdr->c_mtime = FROM_OCTAL (ascii_header.c_mtime); - file_hdr->c_namesize = FROM_OCTAL (ascii_header.c_namesize); - file_hdr->c_filesize = FROM_OCTAL (ascii_header.c_filesize); - - /* 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 (struct cpio_file_stat *file_hdr, int in_des) -{ - struct new_ascii_header ascii_header; - - tape_buffered_read (ascii_header.c_ino, in_des, - sizeof ascii_header - sizeof ascii_header.c_magic); - - file_hdr->c_ino = FROM_HEX (ascii_header.c_ino); - file_hdr->c_mode = FROM_HEX (ascii_header.c_mode); - file_hdr->c_uid = FROM_HEX (ascii_header.c_uid); - file_hdr->c_gid = FROM_HEX (ascii_header.c_gid); - file_hdr->c_nlink = FROM_HEX (ascii_header.c_nlink); - file_hdr->c_mtime = FROM_HEX (ascii_header.c_mtime); - file_hdr->c_filesize = FROM_HEX (ascii_header.c_filesize); - file_hdr->c_dev_maj = FROM_HEX (ascii_header.c_dev_maj); - file_hdr->c_dev_min = FROM_HEX (ascii_header.c_dev_min); - file_hdr->c_rdev_maj = FROM_HEX (ascii_header.c_rdev_maj); - file_hdr->c_rdev_min = FROM_HEX (ascii_header.c_rdev_min); - file_hdr->c_namesize = FROM_HEX (ascii_header.c_namesize); - file_hdr->c_chksum = FROM_HEX (ascii_header.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 (struct cpio_file_stat *file_hdr, - struct old_cpio_header *short_hdr, - int in_des) -{ - file_hdr->c_magic = short_hdr->c_magic; - - tape_buffered_read (((char *) short_hdr) + 6, in_des, - sizeof *short_hdr - 6 /* = 20 */); - - /* 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 (char *ptr, int count) -{ - char tmp; - - while (count-- > 0) - { - tmp = *ptr; - *ptr = *(ptr + 1); - ++ptr; - *ptr = tmp; - ++ptr; - } -} - -#if 0 /* Now in util.c, but different */ -/* Return a safer suffix of FILE_NAME, or "." if it has no safer - suffix. Check for fully specified file names and other atrocities. */ - -static const char * -safer_name_suffix (char const *file_name) -{ - char const *p; - - /* Skip file system prefixes, leading file name components that contain - "..", and leading slashes. */ - - size_t prefix_len = FILE_SYSTEM_PREFIX_LEN (file_name); - - for (p = file_name + prefix_len; *p;) - { - if (p[0] == '.' && p[1] == '.' && (ISSLASH (p[2]) || !p[2])) - prefix_len = p + 2 - file_name; - - do - { - char c = *p++; - if (ISSLASH (c)) - break; - } - while (*p); - } - - for (p = file_name + prefix_len; ISSLASH (*p); p++) - continue; - prefix_len = p - file_name; - - if (prefix_len) - { - char *prefix = alloca (prefix_len + 1); - memcpy (prefix, file_name, prefix_len); - prefix[prefix_len] = '\0'; - - - error (0, 0, _("Removing leading `%s' from member names"), prefix); - } - - if (!*p) - p = "."; - - return p; -} -#endif - -/* 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 = NULL; /* Interactive file for rename option. */ - FILE *tty_out = NULL; /* Interactive file for rename option. */ - FILE *rename_in = NULL; /* Batch file for rename option. */ - struct stat file_stat; /* Output file stat record. */ - struct cpio_file_stat 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. */ - - umask (0); /* Reset umask to preserve modes of - created files */ - - /* 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, TTY_NAME); - } - } - else if (rename_flag) - { - /* Open interactive file pair for rename operation. */ - tty_in = fopen (TTY_NAME, "r"); - if (tty_in == NULL) - { - error (2, errno, TTY_NAME); - } - tty_out = fopen (TTY_NAME, "w"); - if (tty_out == NULL) - { - error (2, errno, TTY_NAME); - } - } - - /* Get date and time if needed for processing the table option. */ - if (table_flag && verbose_flag) - { - time (¤t_time); - } - - /* 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 cpio_file_stat *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 (CPIO_TRAILER_NAME, file_hdr.c_name) == 0) - { - done = true; - break; - } - - cpio_safer_name_suffix (file_hdr.c_name, false, abs_paths_flag, - false); - - /* 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%lx, should be 0x%lx)"), - 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); - } -} - |