/* util.c - Several utility routines for cpio.
Copyright (C) 1990, 1991, 1992, 2001, 2004, 2006, 2007, 2010 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 "cpiohdr.h"
#include "dstring.h"
#include "extern.h"
#include <paxlib.h>
#include "filetypes.h"
#include <safe-read.h>
#include <full-write.h>
#include <rmt.h>
#include <hash.h>
#include <utimens.h>
#ifdef HAVE_SYS_IOCTL_H
# include <sys/ioctl.h>
#endif
#ifdef HAVE_SYS_MTIO_H
# ifdef HAVE_SYS_IO_TRIOCTL_H
# include <sys/io/trioctl.h>
# endif
# include <sys/mtio.h>
#endif
#if !HAVE_DECL_ERRNO
extern int errno;
#endif
/* Write `output_size' bytes of `output_buffer' to file
descriptor OUT_DES and reset `output_size' and `out_buff'. */
void
tape_empty_output_buffer (int out_des)
{
int bytes_written;
#ifdef BROKEN_LONG_TAPE_DRIVER
static long output_bytes_before_lseek = 0;
/* Some tape drivers seem to have a signed internal seek pointer and
they lose if it overflows and becomes negative (e.g. when writing
tapes > 2Gb). Doing an lseek (des, 0, SEEK_SET) seems to reset the
seek pointer and prevent it from overflowing. */
if (output_is_special
&& ( (output_bytes_before_lseek += output_size) >= 1073741824L) )
{
lseek(out_des, 0L, SEEK_SET);
output_bytes_before_lseek = 0;
}
#endif
bytes_written = rmtwrite (out_des, output_buffer, output_size);
if (bytes_written != output_size)
{
int rest_bytes_written;
int rest_output_size;
if (output_is_special
&& (bytes_written >= 0
|| (bytes_written < 0
&& (errno == ENOSPC || errno == EIO || errno == ENXIO))))
{
get_next_reel (out_des);
if (bytes_written > 0)
rest_output_size = output_size - bytes_written;
else
rest_output_size = output_size;
rest_bytes_written = rmtwrite (out_des, output_buffer,
rest_output_size);
if (rest_bytes_written != rest_output_size)
error (1, errno, _("write error"));
}
else
error (1, errno, _("write error"));
}
output_bytes += output_size;
out_buff = output_buffer;
output_size = 0;
}
static int sparse_write (int fildes, char *buf, unsigned int nbyte);
/* Write `output_size' bytes of `output_buffer' to file
descriptor OUT_DES and reset `output_size' and `out_buff'.
If `swapping_halfwords' or `swapping_bytes' is set,
do the appropriate swapping first. Our callers have
to make sure to only set these flags if `output_size'
is appropriate (a multiple of 4 for `swapping_halfwords',
2 for `swapping_bytes'). The fact that DISK_IO_BLOCK_SIZE
must always be a multiple of 4 helps us (and our callers)
insure this. */
void
disk_empty_output_buffer (int out_des)
{
int bytes_written;
if (swapping_halfwords || swapping_bytes)
{
if (swapping_halfwords)
{
int complete_words;
complete_words = output_size / 4;
swahw_array (output_buffer, complete_words);
if (swapping_bytes)
swab_array (output_buffer, 2 * complete_words);
}
else
{
int complete_halfwords;
complete_halfwords = output_size /2;
swab_array (output_buffer, complete_halfwords);
}
}
if (sparse_flag)
bytes_written = sparse_write (out_des, output_buffer, output_size);
else
bytes_written = write (out_des, output_buffer, output_size);
if (bytes_written != output_size)
{
error (1, errno, _("write error"));
}
output_bytes += output_size;
out_buff = output_buffer;
output_size = 0;
}
/* Exchange the halfwords of each element of the array of COUNT longs
starting at PTR. PTR does not have to be aligned at a word
boundary. */
void
swahw_array (char *ptr, int count)
{
char tmp;
for (; count > 0; --count)
{
tmp = *ptr;
*ptr = *(ptr + 2);
*(ptr + 2) = tmp;
++ptr;
tmp = *ptr;
*ptr = *(ptr + 2);
*(ptr + 2) = tmp;
ptr += 3;
}
}
/* Read at most NUM_BYTES or `io_block_size' bytes, whichever is smaller,
into the start of `input_buffer' from file descriptor IN_DES.
Set `input_size' to the number of bytes read and reset `in_buff'.
Exit with an error if end of file is reached. */
#ifdef BROKEN_LONG_TAPE_DRIVER
static long input_bytes_before_lseek = 0;
#endif
static vo
|