summaryrefslogtreecommitdiff
path: root/src/util.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/util.c')
-rw-r--r--src/util.c439
1 files changed, 267 insertions, 172 deletions
diff --git a/src/util.c b/src/util.c
index 4b64648ee2b1..5bcc40aa2495 100644
--- a/src/util.c
+++ b/src/util.c
@@ -1,5 +1,6 @@
/* util.c - Several utility routines for cpio.
- Copyright (C) 1990, 1991, 1992, 2001, 2004 Free Software Foundation, Inc.
+ Copyright (C) 1990, 1991, 1992, 2001, 2004,
+ 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
@@ -11,9 +12,10 @@
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.,
- 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+ 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>
@@ -23,15 +25,21 @@
#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>
#include <sys/ioctl.h>
#ifdef HAVE_SYS_MTIO_H
-#ifdef HAVE_SYS_IO_TRIOCTL_H
-#include <sys/io/trioctl.h>
-#endif
-#include <sys/mtio.h>
+# ifdef HAVE_SYS_IO_TRIOCTL_H
+# include <sys/io/trioctl.h>
+# endif
+# include <sys/mtio.h>
#endif
#if !HAVE_DECL_ERRNO
@@ -90,6 +98,8 @@ tape_empty_output_buffer (int out_des)
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,
@@ -207,7 +217,7 @@ tape_fill_input_buffer (int in_des, int num_bytes)
Exit with an error if end of file is reached. */
static int
-disk_fill_input_buffer (int in_des, int num_bytes)
+disk_fill_input_buffer (int in_des, off_t num_bytes)
{
in_buff = input_buffer;
num_bytes = (num_bytes < DISK_IO_BLOCK_SIZE) ? num_bytes : DISK_IO_BLOCK_SIZE;
@@ -227,10 +237,10 @@ disk_fill_input_buffer (int in_des, int num_bytes)
When `out_buff' fills up, flush it to file descriptor OUT_DES. */
void
-tape_buffered_write (char *in_buf, int out_des, long num_bytes)
+tape_buffered_write (char *in_buf, int out_des, off_t num_bytes)
{
- register long bytes_left = num_bytes; /* Bytes needing to be copied. */
- register long space_left; /* Room left in output buffer. */
+ off_t bytes_left = num_bytes; /* Bytes needing to be copied. */
+ off_t space_left; /* Room left in output buffer. */
while (bytes_left > 0)
{
@@ -241,7 +251,7 @@ tape_buffered_write (char *in_buf, int out_des, long num_bytes)
{
if (bytes_left < space_left)
space_left = bytes_left;
- bcopy (in_buf, out_buff, (unsigned) space_left);
+ memcpy (out_buff, in_buf, (unsigned) space_left);
out_buff += space_left;
output_size += space_left;
in_buf += space_left;
@@ -254,10 +264,10 @@ tape_buffered_write (char *in_buf, int out_des, long num_bytes)
When `out_buff' fills up, flush it to file descriptor OUT_DES. */
void
-disk_buffered_write (char *in_buf, int out_des, long num_bytes)
+disk_buffered_write (char *in_buf, int out_des, off_t num_bytes)
{
- register long bytes_left = num_bytes; /* Bytes needing to be copied. */
- register long space_left; /* Room left in output buffer. */
+ off_t bytes_left = num_bytes; /* Bytes needing to be copied. */
+ off_t space_left; /* Room left in output buffer. */
while (bytes_left > 0)
{
@@ -268,7 +278,7 @@ disk_buffered_write (char *in_buf, int out_des, long num_bytes)
{
if (bytes_left < space_left)
space_left = bytes_left;
- bcopy (in_buf, out_buff, (unsigned) space_left);
+ memcpy (out_buff, in_buf, (unsigned) space_left);
out_buff += space_left;
output_size += space_left;
in_buf += space_left;
@@ -282,10 +292,10 @@ disk_buffered_write (char *in_buf, int out_des, long num_bytes)
When `in_buff' is exhausted, refill it from file descriptor IN_DES. */
void
-tape_buffered_read (char *in_buf, int in_des, long num_bytes)
+tape_buffered_read (char *in_buf, int in_des, off_t num_bytes)
{
- register long bytes_left = num_bytes; /* Bytes needing to be copied. */
- register long space_left; /* Bytes to copy from input buffer. */
+ off_t bytes_left = num_bytes; /* Bytes needing to be copied. */
+ off_t space_left; /* Bytes to copy from input buffer. */
while (bytes_left > 0)
{
@@ -295,7 +305,7 @@ tape_buffered_read (char *in_buf, int in_des, long num_bytes)
space_left = bytes_left;
else
space_left = input_size;
- bcopy (in_buff, in_buf, (unsigned) space_left);
+ memcpy (in_buf, in_buff, (unsigned) space_left);
in_buff += space_left;
in_buf += space_left;
input_size -= space_left;
@@ -345,7 +355,7 @@ tape_buffered_peek (char *peek_buf, int in_des, int num_bytes)
first block to make room. */
int half;
half = input_buffer_size / 2;
- bcopy (input_buffer + half, input_buffer, half);
+ memmove (input_buffer, input_buffer + half, half);
in_buff = in_buff - half;
append_buf = append_buf - half;
}
@@ -369,17 +379,17 @@ tape_buffered_peek (char *peek_buf, int in_des, int num_bytes)
got_bytes = num_bytes;
else
got_bytes = input_size;
- bcopy (in_buff, peek_buf, (unsigned) got_bytes);
+ memcpy (peek_buf, in_buff, (unsigned) got_bytes);
return got_bytes;
}
/* Skip the next NUM_BYTES bytes of file descriptor IN_DES. */
void
-tape_toss_input (int in_des, long num_bytes)
+tape_toss_input (int in_des, off_t num_bytes)
{
- register long bytes_left = num_bytes; /* Bytes needing to be copied. */
- register long space_left; /* Bytes to copy from input buffer. */
+ off_t bytes_left = num_bytes; /* Bytes needing to be copied. */
+ off_t space_left; /* Bytes to copy from input buffer. */
while (bytes_left > 0)
{
@@ -403,18 +413,19 @@ tape_toss_input (int in_des, long num_bytes)
}
}
-static void
-write_nuls_to_file (long num_bytes, int out_des,
- void (*writer) (char *in_buf, int out_des, long num_bytes))
+void
+write_nuls_to_file (off_t num_bytes, int out_des,
+ void (*writer) (char *in_buf, int out_des, off_t num_bytes))
{
- long blocks;
- long extra_bytes;
- long i;
-
- blocks = num_bytes / 512;
- extra_bytes = num_bytes % 512;
+ off_t blocks;
+ off_t extra_bytes;
+ off_t i;
+ static char zeros_512[512];
+
+ blocks = num_bytes / sizeof zeros_512;
+ extra_bytes = num_bytes % sizeof zeros_512;
for (i = 0; i < blocks; ++i)
- writer (zeros_512, out_des, 512);
+ writer (zeros_512, out_des, sizeof zeros_512);
if (extra_bytes)
writer (zeros_512, out_des, extra_bytes);
}
@@ -428,7 +439,7 @@ write_nuls_to_file (long num_bytes, int out_des,
NUM_BYTES is the number of bytes to copy. */
void
-copy_files_tape_to_disk (int in_des, int out_des, long num_bytes)
+copy_files_tape_to_disk (int in_des, int out_des, off_t num_bytes)
{
long size;
long k;
@@ -458,13 +469,13 @@ copy_files_tape_to_disk (int in_des, int out_des, long num_bytes)
NUM_BYTES is the number of bytes to copy. */
void
-copy_files_disk_to_tape (int in_des, int out_des, long num_bytes,
+copy_files_disk_to_tape (int in_des, int out_des, off_t num_bytes,
char *filename)
{
long size;
long k;
int rc;
- long original_num_bytes;
+ off_t original_num_bytes;
original_num_bytes = num_bytes;
@@ -472,14 +483,20 @@ copy_files_disk_to_tape (int in_des, int out_des, long num_bytes,
{
if (input_size == 0)
if (rc = disk_fill_input_buffer (in_des,
- num_bytes < DISK_IO_BLOCK_SIZE ?
- num_bytes : DISK_IO_BLOCK_SIZE))
+ num_bytes < DISK_IO_BLOCK_SIZE ?
+ num_bytes : DISK_IO_BLOCK_SIZE))
{
if (rc > 0)
- error (0, 0, _("File %s shrunk by %ld bytes, padding with zeros"),
- filename, num_bytes);
+ {
+ char buf[UINTMAX_STRSIZE_BOUND];
+ error (0, 0,
+ ngettext ("File %s shrunk by %s byte, padding with zeros",
+ "File %s shrunk by %s bytes, padding with zeros",
+ num_bytes),
+ filename, STRINGIFY_BIGINT (num_bytes, buf));
+ }
else
- error (0, 0, _("Read error at byte %ld in file %s, padding with zeros"),
+ error (0, 0, _("Read error at byte %lld in file %s, padding with zeros"),
original_num_bytes - num_bytes, filename);
write_nuls_to_file (num_bytes, out_des, tape_buffered_write);
break;
@@ -505,12 +522,12 @@ copy_files_disk_to_tape (int in_des, int out_des, long num_bytes,
NUM_BYTES is the number of bytes to copy. */
void
-copy_files_disk_to_disk (int in_des, int out_des, long num_bytes,
+copy_files_disk_to_disk (int in_des, int out_des, off_t num_bytes,
char *filename)
{
long size;
long k;
- long original_num_bytes;
+ off_t original_num_bytes;
int rc;
original_num_bytes = num_bytes;
@@ -520,10 +537,16 @@ copy_files_disk_to_disk (int in_des, int out_des, long num_bytes,
if (rc = disk_fill_input_buffer (in_des, num_bytes))
{
if (rc > 0)
- error (0, 0, _("File %s shrunk by %ld bytes, padding with zeros"),
- filename, num_bytes);
+ {
+ char buf[UINTMAX_STRSIZE_BOUND];
+ error (0, 0,
+ ngettext ("File %s shrunk by %s byte, padding with zeros",
+ "File %s shrunk by %s bytes, padding with zeros",
+ num_bytes),
+ filename, STRINGIFY_BIGINT (num_bytes, buf));
+ }
else
- error (0, 0, _("Read error at byte %ld in file %s, padding with zeros"),
+ error (0, 0, _("Read error at byte %lld in file %s, padding with zeros"),
original_num_bytes - num_bytes, filename);
write_nuls_to_file (num_bytes, out_des, disk_buffered_write);
break;
@@ -545,20 +568,23 @@ copy_files_disk_to_disk (int in_des, int out_des, long num_bytes,
void
warn_if_file_changed (char *file_name, unsigned long old_file_size,
- unsigned long old_file_mtime)
+ off_t old_file_mtime)
{
struct stat new_file_stat;
if ((*xstat) (file_name, &new_file_stat) < 0)
{
- error (0, errno, "%s", file_name);
+ stat_error (file_name);
return;
}
/* Only check growth, shrinkage detected in copy_files_disk_to_{disk,tape}()
*/
if (new_file_stat.st_size > old_file_size)
- error (0, 0, _("File %s grew, %ld new bytes not copied"),
- file_name, (long)(new_file_stat.st_size - old_file_size));
+ error (0, 0,
+ ngettext ("File %s grew, %"PRIuMAX" new byte not copied",
+ "File %s grew, %"PRIuMAX" new bytes not copied",
+ (long)(new_file_stat.st_size - old_file_size)),
+ file_name, (uintmax_t) (new_file_stat.st_size - old_file_size));
else if (new_file_stat.st_mtime != old_file_mtime)
error (0, 0, _("File %s was modified while being copied"), file_name);
@@ -658,82 +684,40 @@ struct inode_val
};
/* Inode hash table. Allocated by first call to add_inode. */
-static struct inode_val **hash_table = NULL;
-
-/* Size of current hash table. Initial size is 47. (47 = 2*22 + 3) */
-static int hash_size = 22;
+static Hash_table *hash_table = NULL;
-/* Number of elements in current hash table. */
-static int hash_num;
+static size_t
+inode_val_hasher (const void *val, size_t n_buckets)
+{
+ const struct inode_val *ival = val;
+ return ival->inode % n_buckets;
+}
-/* Find the file name associated with NODE_NUM. If there is no file
- associated with NODE_NUM, return NULL. */
+static bool
+inode_val_compare (const void *val1, const void *val2)
+{
+ const struct inode_val *ival1 = val1;
+ const struct inode_val *ival2 = val2;
+ return ival1->inode == ival2->inode
+ && ival1->major_num == ival2->major_num
+ && ival1->minor_num == ival2->minor_num;
+}
char *
find_inode_file (unsigned long node_num, unsigned long major_num,
unsigned long minor_num)
{
- int start; /* Initial hash location. */
- int temp; /* Rehash search variable. */
-
- if (hash_table != NULL)
- {
- /* Hash function is node number modulo the table size. */
- start = node_num % hash_size;
-
- /* Initial look into the table. */
- if (hash_table[start] == NULL)
- return NULL;
- if (hash_table[start]->inode == node_num
- && hash_table[start]->major_num == major_num
- && hash_table[start]->minor_num == minor_num)
- return hash_table[start]->file_name;
-
- /* The home position is full with a different inode record.
- Do a linear search terminated by a NULL pointer. */
- for (temp = (start + 1) % hash_size;
- hash_table[temp] != NULL && temp != start;
- temp = (temp + 1) % hash_size)
- {
- if (hash_table[temp]->inode == node_num
- && hash_table[start]->major_num == major_num
- && hash_table[start]->minor_num == minor_num)
- return hash_table[temp]->file_name;
- }
- }
- return NULL;
-}
-
-/* Do the hash insert. Used in normal inserts and resizing the hash
- table. It is guaranteed that there is room to insert the item.
- NEW_VALUE is the pointer to the previously allocated inode, file
- name association record. */
-
-static void
-hash_insert (struct inode_val *new_value)
-{
- int start; /* Home position for the value. */
- int temp; /* Used for rehashing. */
-
- /* Hash function is node number modulo the table size. */
- start = new_value->inode % hash_size;
-
- /* Do the initial look into the table. */
- if (hash_table[start] == NULL)
- {
- hash_table[start] = new_value;
- return;
- }
-
- /* If we get to here, the home position is full with a different inode
- record. Do a linear search for the first NULL pointer and insert
- the new item there. */
- temp = (start + 1) % hash_size;
- while (hash_table[temp] != NULL)
- temp = (temp + 1) % hash_size;
-
- /* Insert at the NULL. */
- hash_table[temp] = new_value;
+ struct inode_val sample;
+ struct inode_val *ival;
+
+ if (!hash_table)
+ return NULL;
+
+ sample.inode = node_num;
+ sample.major_num = major_num;
+ sample.minor_num = minor_num;
+ ival = hash_lookup (hash_table, &sample);
+ return ival ? ival->file_name : NULL;
}
/* Associate FILE_NAME with the inode NODE_NUM. (Insert into hash table.) */
@@ -743,7 +727,8 @@ add_inode (unsigned long node_num, char *file_name, unsigned long major_num,
unsigned long minor_num)
{
struct inode_val *temp;
-
+ struct inode_val *e;
+
/* Create new inode record. */
temp = (struct inode_val *) xmalloc (sizeof (struct inode_val));
temp->inode = node_num;
@@ -751,39 +736,12 @@ add_inode (unsigned long node_num, char *file_name, unsigned long major_num,
temp->minor_num = minor_num;
temp->file_name = xstrdup (file_name);
- /* Do we have to increase the size of (or initially allocate)
- the hash table? */
- if (hash_num == hash_size || hash_table == NULL)
- {
- struct inode_val **old_table; /* Pointer to old table. */
- int i; /* Index for re-insert loop. */
-
- /* Save old table. */
- old_table = hash_table;
- if (old_table == NULL)
- hash_num = 0;
-
- /* Calculate new size of table and allocate it.
- Sequence of table sizes is 47, 97, 197, 397, 797, 1597, 3197, 6397 ...
- where 3197 and most of the sizes after 6397 are not prime. The other
- numbers listed are prime. */
- hash_size = 2 * hash_size + 3;
- hash_table = (struct inode_val **)
- xmalloc (hash_size * sizeof (struct inode_val *));
- bzero (hash_table, hash_size * sizeof (struct inode_val *));
-
- /* Insert the values from the old table into the new table. */
- for (i = 0; i < hash_num; i++)
- hash_insert (old_table[i]);
-
- if (old_table != NULL)
- free (old_table);
- }
-
- /* Insert the new record and increment the count of elements in the
- hash table. */
- hash_insert (temp);
- hash_num++;
+ if (!((hash_table
+ || (hash_table = hash_initialize (0, 0, inode_val_hasher,
+ inode_val_compare, 0)))
+ && (e = hash_insert (hash_table, temp))))
+ xalloc_die ();
+ /* FIXME: e is not used */
}
@@ -800,14 +758,14 @@ open_archive (char *file)
copy_in = process_copy_in;
if (copy_function == copy_in)
- fd = rmtopen (file, O_RDONLY | O_BINARY, 0666, rsh_command_option);
+ fd = rmtopen (file, O_RDONLY | O_BINARY, MODE_RW, rsh_command_option);
else
{
if (!append_flag)
- fd = rmtopen (file, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666,
+ fd = rmtopen (file, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, MODE_RW,
rsh_command_option);
else
- fd = rmtopen (file, O_RDWR | O_BINARY, 0666, rsh_command_option);
+ fd = rmtopen (file, O_RDWR | O_BINARY, MODE_RW, rsh_command_option);
}
return fd;
@@ -887,7 +845,7 @@ get_next_reel (int tape_des)
tape_des = open_archive (archive_name);
if (tape_des == -1)
- error (1, errno, "%s", archive_name);
+ open_error (archive_name);
}
else
{
@@ -907,7 +865,7 @@ get_next_reel (int tape_des)
tape_des = open_archive (next_archive_name);
if (tape_des == -1)
- error (0, errno, "%s", next_archive_name);
+ open_error (next_archive_name);
}
while (tape_des < 0);
}
@@ -1003,9 +961,10 @@ umasked_symlink (char *name1, char *name2, int mode)
/* Take an input pathname and check it for CDF's. Insert an extra
`/' in the pathname after each "hidden" directory. If we add
- any `/'s, return a malloced string (which it will reuse for
- later calls so our caller doesn't have to worry about freeing
- the string) instead of the original input string. */
+ any `/'s, return a malloced string instead of the original input
+ string.
+ FIXME: This creates a memory leak.
+*/
char *
add_cdf_double_slashes (char *input_name)
@@ -1055,7 +1014,7 @@ add_cdf_double_slashes (char *input_name)
*p = '\0';
if ((*xstat) (input_name, &dir_stat) < 0)
{
- error (0, errno, "%s", input_name);
+ stat_error (input_name);
return input_name;
}
@@ -1081,7 +1040,7 @@ add_cdf_double_slashes (char *input_name)
*p = '\0';
if ((*xstat) (input_name, &dir_stat) < 0)
{
- error (0, errno, "%s", input_name);
+ stat_error (input_name);
return input_name;
}
*p = '/';
@@ -1109,7 +1068,7 @@ islastparentcdf (char *path)
int slash_count;
int length; /* Length of result, not including NUL. */
- slash = rindex (path, '/');
+ slash = strrchr (path, '/');
if (slash == 0)
return 0;
else
@@ -1131,9 +1090,6 @@ islastparentcdf (char *path)
#define DISKBLOCKSIZE (512)
-enum sparse_write_states { begin, in_zeros, not_in_zeros };
-
-
static int
buf_all_zeros (char *buf, int bufsize)
{
@@ -1151,7 +1107,7 @@ int delayed_seek_count = 0;
/* Write NBYTE bytes from BUF to remote tape connection FILDES.
Return the number of bytes written on success, -1 on error. */
-int
+static int
sparse_write (int fildes, char *buf, unsigned int nbyte)
{
int complete_block_count;
@@ -1162,7 +1118,7 @@ sparse_write (int fildes, char *buf, unsigned int nbyte)
int lseek_rc;
int write_rc;
int i;
- enum sparse_write_states state;
+ enum { begin, in_zeros, not_in_zeros } state;
complete_block_count = nbyte / DISKBLOCKSIZE;
leftover_bytes_count = nbyte % DISKBLOCKSIZE;
@@ -1192,6 +1148,7 @@ sparse_write (int fildes, char *buf, unsigned int nbyte)
}
buf += DISKBLOCKSIZE;
break;
+
case in_zeros :
if (buf_all_zeros (buf, DISKBLOCKSIZE))
{
@@ -1206,6 +1163,7 @@ sparse_write (int fildes, char *buf, unsigned int nbyte)
}
buf += DISKBLOCKSIZE;
break;
+
case not_in_zeros :
if (buf_all_zeros (buf, DISKBLOCKSIZE))
{
@@ -1228,6 +1186,7 @@ sparse_write (int fildes, char *buf, unsigned int nbyte)
case in_zeros :
delayed_seek_count = seek_count;
break;
+
case not_in_zeros :
write_rc = write (fildes, cur_write_start, write_count);
delayed_seek_count = 0;
@@ -1245,3 +1204,139 @@ sparse_write (int fildes, char *buf, unsigned int nbyte)
}
return nbyte;
}
+
+#define CPIO_UID(uid) (set_owner_flag ? set_owner : (uid))
+#define CPIO_GID(gid) (set_group_flag ? set_group : (gid))
+
+void
+stat_to_cpio (struct cpio_file_stat *hdr, struct stat *st)
+{
+ hdr->c_dev_maj = major (st->st_dev);
+ hdr->c_dev_min = minor (st->st_dev);
+ hdr->c_ino = st->st_ino;
+ /* For POSIX systems that don't define the S_IF macros,
+ we can't assume that S_ISfoo means the standard Unix
+ S_IFfoo bit(s) are set. So do it manually, with a
+ different name. Bleah. */
+ hdr->c_mode = (st->st_mode & 07777);
+ if (S_ISREG (st->st_mode))
+ hdr->c_mode |= CP_IFREG;
+ else if (S_ISDIR (st->st_mode))
+ hdr->c_mode |= CP_IFDIR;
+#ifdef S_ISBLK
+ else if (S_ISBLK (st->st_mode))
+ hdr->c_mode |= CP_IFBLK;
+#endif
+#ifdef S_ISCHR
+ else if (S_ISCHR (st->st_mode))
+ hdr->c_mode |= CP_IFCHR;
+#endif
+#ifdef S_ISFIFO
+ else if (S_ISFIFO (st->st_mode))
+ hdr->c_mode |= CP_IFIFO;
+#endif
+#ifdef S_ISLNK
+ else if (S_ISLNK (st->st_mode))
+ hdr->c_mode |= CP_IFLNK;
+#endif
+#ifdef S_ISSOCK
+ else if (S_ISSOCK (st->st_mode))
+ hdr->c_mode |= CP_IFSOCK;
+#endif
+#ifdef S_ISNWK
+ else if (S_ISNWK (st->st_mode))
+ hdr->c_mode |= CP_IFNWK;
+#endif
+ hdr->c_uid = CPIO_UID (st->st_uid);
+ hdr->c_gid = CPIO_GID (st->st_gid);
+ hdr->c_nlink = st->st_nlink;
+ hdr->c_rdev_maj = major (st->st_rdev);
+ hdr->c_rdev_min = minor (st->st_rdev);
+ hdr->c_mtime = st->st_mtime;
+ hdr->c_filesize = st->st_size;
+ hdr->c_chksum = 0;
+ hdr->c_tar_linkname = NULL;
+}
+
+#ifndef HAVE_FCHOWN
+# define fchown(fd, uid, gid) (-1)
+#endif
+
+int
+fchown_or_chown (int fd, const char *name, uid_t uid, uid_t gid)
+{
+ if (HAVE_FCHOWN && fd != -1)
+ return fchown (fd, uid, gid);
+ else
+ return chown (name, uid, gid);
+}
+
+int
+fchmod_or_chmod (int fd, const char *name, mode_t mode)
+{
+ if (HAVE_FCHMOD && fd != -1)
+ return fchmod (fd, mode);
+ else
+ return chmod(name, mode);
+}
+
+void
+set_perms (int fd, struct cpio_file_stat *header)
+{
+ if (!no_chown_flag)
+ {
+ uid_t uid = CPIO_UID (header->c_uid);
+ gid_t gid = CPIO_GID (header->c_gid);
+ if ((fchown_or_chown (fd, header->c_name, uid, gid) < 0)
+ && errno != EPERM)
+ chown_error_details (header->c_name, uid, gid);
+ }
+ /* chown may have turned off some permissions we wanted. */
+ if (fchmod_or_chmod (fd, header->c_name, header->c_mode) < 0)
+ chmod_error_details (header->c_name, header->c_mode);
+#ifdef HPUX_CDF
+ if ((header->c_mode & CP_IFMT) && cdf_flag)
+ /* Once we "hide" the directory with the chmod(),
+ we have to refer to it using name+ instead of name. */
+ file_hdr->c_name [cdf_char] = '+';
+#endif
+ if (retain_time_flag)
+ set_file_times (fd, header->c_name, header->c_mtime, header->c_mtime);
+}
+
+void
+set_file_times (int fd,
+ const char *name, unsigned long atime, unsigned long mtime)
+{
+ struct timespec ts[2];
+
+ memset (&ts, 0, sizeof ts);
+
+ ts[0].tv_sec = atime;
+ ts[1].tv_sec = mtime;
+
+ /* Silently ignore EROFS because reading the file won't have upset its
+ timestamp if it's on a read-only filesystem. */
+ if (gl_futimens (fd, name, ts) < 0 && errno != EROFS)
+ utime_error (name);
+}
+
+/* Do we have to ignore absolute paths, and if so, does the filename
+ have an absolute path? */
+void
+cpio_safer_name_suffix (char *name, bool link_target, bool absolute_names,
+ bool strip_leading_dots)
+{
+ char *p = safer_name_suffix (name, link_target, absolute_names);
+ if (strip_leading_dots && strcmp (p, "./"))
+ /* strip leading `./' from the filename. */
+ while (*p == '.' && *(p + 1) == '/')
+ {
+ ++p;
+ while (*p == '/')
+ ++p;
+ }
+ if (p != name)
+ memmove (name, p, (size_t)(strlen (p) + 1));
+}
+