/* copyin.c - extract or list a cpio archive
Copyright (C) 1990, 1991, 1992, 2001, 2002, 2003, 2004,
2005, 2006, 2007, 2009 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 3, 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 <rmt.h>
#ifndef FNM_PATHNAME
# include <fnmatch.h>
#endif
#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, off_t offset)
{
off_t 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 d
|