home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Fresh Fish 7
/
FreshFishVol7.bin
/
bbs
/
gnu
/
cpio-2.3-src.lha
/
GNU
/
src
/
amiga
/
cpio-2.3
/
util.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-04-28
|
31KB
|
1,103 lines
/* util.c - Several utility routines for cpio.
Copyright (C) 1990, 1991, 1992 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <stdio.h>
#include <sys/types.h>
#ifdef HPUX_CDF
#include <sys/stat.h>
#endif
#include "system.h"
#include "cpiohdr.h"
#include "dstring.h"
#include "extern.h"
#include "rmt.h"
#ifndef __MSDOS__
#include <sys/ioctl.h>
#else
#include <io.h>
#endif
#ifdef HAVE_SYS_MTIO_H
#ifdef HAVE_SYS_IO_TRIOCTL_H
#include <sys/io/trioctl.h>
#endif
#include <sys/mtio.h>
#endif
static void empty_output_buffer_swap ();
static void hash_insert ();
/* Write `output_size' bytes of `output_buffer' to file
descriptor OUT_DES and reset `output_size' and `out_buff'. */
void
empty_output_buffer (out_des)
int out_des;
{
int bytes_written;
#ifdef BROKEN_LONG_TAPE_DRIVER
static long output_bytes_before_lseek = 0;
#endif
if (swapping_halfwords || swapping_bytes)
{
empty_output_buffer_swap (out_des);
return;
}
#ifdef BROKEN_LONG_TAPE_DRIVER
/* 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) < 0L)
{
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;
}
/* Write `output_size' bytes of `output_buffer' to file
descriptor OUT_DES with byte and/or halfword swapping and reset
`output_size' and `out_buff'. This routine should not be called
with `swapping_bytes' set unless the caller knows that the
file being written has an even number of bytes, and it should not be
called with `swapping_halfwords' set unless the caller knows
that the file being written has a length divisible by 4. If either
of those restrictions are not met, bytes may be lost in the output
file. OUT_DES must refer to a file that we are creating during
a process_copy_in, so we don't have to check for end of media
errors or be careful about only writing in blocks of `output_size'
bytes. */
static void
empty_output_buffer_swap (out_des)
int out_des;
{
/* Since `output_size' might not be divisible by 4 or 2, we might
not be able to be able to swap all the bytes and halfwords in
`output_buffer' (e.g., if `output_size' is odd), so we might not be
able to write them all. We will swap and write as many bytes as
we can, and save the rest in `left_overs' for the next time we are
called. */
static char left_overs[4];
static int left_over_bytes = 0;
int bytes_written;
int complete_halfwords;
int complete_words;
int extra_bytes;
output_bytes += output_size;
out_buff = output_buffer;
if (swapping_halfwords)
{
if (left_over_bytes != 0)
{
while (output_size > 0 && left_over_bytes < 4)
{
left_overs[left_over_bytes++] = *out_buff++;
--output_size;
}
if (left_over_bytes < 4)
{
out_buff = output_buffer;
output_size = 0;
return;
}
swahw_array (left_overs, 1);
if (swapping_bytes)
swab_array (left_overs, 2);
bytes_written = rmtwrite (out_des, left_overs, 4);
if (bytes_written != 4)
error (1, errno, "write error");
left_over_bytes = 0;
}
complete_words = output_size / 4;
if (complete_words > 0)
{
swahw_array (out_buff, complete_words);
if (swapping_bytes)
swab_array (out_buff, 2 * complete_words);
bytes_written = rmtwrite (out_des, out_buff, 4 * complete_words);
if (bytes_written != (4 * complete_words))
error (1, errno, "write error");
}
out_buff += (4 * complete_words);
extra_bytes = output_size % 4;
while (extra_bytes > 0)
{
left_overs[left_over_bytes++] = *out_buff++;
--extra_bytes;
}
}
else
{
if (left_over_bytes != 0)
{
while (output_size > 0 && left_over_bytes < 2)
{
left_overs[left_over_bytes++] = *out_buff++;
--output_size;
}
if (left_over_bytes < 2)
{
out_buff = output_buffer;
output_size = 0;
return;
}
swab_array (left_overs, 1);
bytes_written = rmtwrite (out_des, left_overs, 2);
if (bytes_written != 2)
error (1, errno, "write error");
left_over_bytes = 0;
}
complete_halfwords = output_size / 2;
if (complete_halfwords > 0)
{
swab_array (out_buff, complete_halfwords);
bytes_written = rmtwrite (out_des, out_buff, 2 * complete_halfwords);
if (bytes_written != (2 * complete_halfwords))
error (1, errno, "write error");
}
out_buff += (2 * complete_halfwords);
extra_bytes = output_size % 2;
while (extra_bytes > 0)
{
left_overs[left_over_bytes++] = *out_buff++;
--extra_bytes;
}
}
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 (ptr, count)
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
void
fill_input_buffer (in_des, num_bytes)
int in_des;
int num_bytes;
{
#ifdef BROKEN_LONG_TAPE_DRIVER
/* 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 > 4Gb). Doing an lseek (des, 0, SEEK_SET) seems to reset the
seek pointer and prevent it from overflowing. */
if (input_is_special
&& (input_bytes_before_lseek += num_bytes) < 0L)
{
lseek(in_des, 0L, SEEK_SET);
input_bytes_before_lseek = 0;
}
#endif
in_buff = input_buffer;
num_bytes = (num_bytes < io_block_size) ? num_bytes : io_block_size;
input_size = rmtread (in_des, input_buffer, num_bytes);
if (input_size == 0 && input_is_special)
{
get_next_reel (in_des);
input_size = rmtread (in_des, input_buffer, num_bytes);
}
if (input_size < 0)
error (1, errno, "read error");
if (input_size == 0)
{
error (0, 0, "premature end of file");
exit (1);
}
input_bytes += input_size;
}
/*