Commit message: Rewrite dynamic string support.

* src/dstring.c (ds_init): Take a single argument.
(ds_free): New function.
(ds_resize): Take a single argument.  Use x2nrealloc to expand
the storage.
(ds_reset,ds_append,ds_concat,ds_endswith): New function.
(ds_fgetstr): Rewrite.  In particular, this fixes integer overflow.
* src/dstring.h (dynamic_string): Keep both the allocated length
(ds_size) and index of the next free byte in the string (ds_idx).
(ds_init,ds_resize): Change signature.
(ds_len): New macro.
(ds_free,ds_reset,ds_append,ds_concat,ds_endswith): New protos.
* src/copyin.c: Use new ds_ functions.
* src/copyout.c: Likewise.
* src/copypass.c: Likewise.
* src/util.c: Likewise.
CVE: CVE-2021-38185
CWE: CWE-190
Vulnerability description: GNU cpio through 2.13 allows attackers to execute arbitrary code via a crafted pattern file, because of a dstring.c ds_fgetstr integer overflow that triggers an out-of-bounds heap write. NOTE: it is unclear whether there are common cases where the pattern file, associated with the -E option, is untrusted data.

Project: cpio

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 = get_link_name (file_hdr, in_file_des);
	      if (link_name)
		{
		  long_format (file_hdr, link_name);
		  free (link_name);
		}
	    }
	  else
	    long_format (file_hdr, file_hdr->c_tar_linkname);
	  return;
	}
      else
#endif
	long_format (file_hdr, (char *) 0);
    }
  else
    {
      /* Print out the name as it is.  The name_end delimiter is normally
	 '\n', but can be reset to '\0' by the -0 option. */
      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%x, should be 0x%x)"),
		 file_hdr->c_name, crc, file_hdr->c_chksum);
	}
    }
}

Project: cpio

ds_resize (dynamic_string *string)
{
  if (string->ds_idx == string->ds_size)
    {
      string->ds_string = x2nrealloc (string->ds_string, &string->ds_size,
				      1);
    }
}

Project: cpio

find_inode_val (ino_t node_num, unsigned long major_num,
		 unsigned long minor_num)
{
  struct inode_val sample;
  
  if (!hash_table)
    return NULL;
  
  sample.inode = node_num;
  sample.major_num = major_num;
  sample.minor_num = minor_num;
  return hash_lookup (hash_table, &sample);
}

Project: cpio

ds_fgetstr (FILE *f, dynamic_string *s, char eos)
{
  int next_ch;

  /* Initialize.  */
  s->ds_idx = 0;

  /* Read the input string.  */
  while ((next_ch = getc (f)) != eos && next_ch != EOF)
    {
      ds_resize (s);
      s->ds_string[s->ds_idx++] = next_ch;
    }
  ds_resize (s);
  s->ds_string[s->ds_idx] = '\0';

  if (s->ds_idx == 0 && next_ch == EOF)
    return NULL;
  else
    return s->ds_string;
}

Project: cpio

tape_fill_input_buffer (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) >= 1073741824L) )
    {
      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 == SAFE_READ_ERROR)
    error (PAXEXIT_FAILURE, errno, _("read error"));
  if (input_size == 0)
    error (PAXEXIT_FAILURE, 0, _("premature end of file"));
  input_bytes += input_size;
}

Project: cpio

write_out_binary_header (dev_t rdev,
			 struct cpio_file_stat *file_hdr, int out_des)
{
  struct old_cpio_header short_hdr;

  short_hdr.c_magic = 070707;
  short_hdr.c_dev = makedev (file_hdr->c_dev_maj, file_hdr->c_dev_min);

  if ((warn_option & CPIO_WARN_TRUNCATE) && (file_hdr->c_ino >> 16) != 0)
    error (0, 0, _("%s: truncating inode number"), file_hdr->c_name);

  short_hdr.c_ino = file_hdr->c_ino & 0xFFFF;
  if (short_hdr.c_ino != file_hdr->c_ino)
    field_width_warning (file_hdr->c_name, _("inode number"));
  
  short_hdr.c_mode = file_hdr->c_mode & 0xFFFF;
  if (short_hdr.c_mode != file_hdr->c_mode)
    field_width_warning (file_hdr->c_name, _("file mode"));
  
  short_hdr.c_uid = file_hdr->c_uid & 0xFFFF;
  if (short_hdr.c_uid != file_hdr->c_uid)
    field_width_warning (file_hdr->c_name, _("uid"));
  
  short_hdr.c_gid = file_hdr->c_gid & 0xFFFF;
  if (short_hdr.c_gid != file_hdr->c_gid)
    field_width_warning (file_hdr->c_name, _("gid"));
  
  short_hdr.c_nlink = file_hdr->c_nlink & 0xFFFF;
  if (short_hdr.c_nlink != file_hdr->c_nlink)
    field_width_warning (file_hdr->c_name, _("number of links"));
		      
  short_hdr.c_rdev = rdev;
  short_hdr.c_mtimes[0] = file_hdr->c_mtime >> 16;
  short_hdr.c_mtimes[1] = file_hdr->c_mtime & 0xFFFF;

  short_hdr.c_namesize = file_hdr->c_namesize & 0xFFFF;
  if (short_hdr.c_namesize != file_hdr->c_namesize)
    {
      char maxbuf[UINTMAX_STRSIZE_BOUND + 1];
      error (0, 0, _("%s: value %s %s out of allowed range 0..%u"),
	     file_hdr->c_name, _("name size"),
	     STRINGIFY_BIGINT (file_hdr->c_namesize, maxbuf), 0xFFFFu);
      return 1;
    }
		      
  short_hdr.c_filesizes[0] = file_hdr->c_filesize >> 16;
  short_hdr.c_filesizes[1] = file_hdr->c_filesize & 0xFFFF;

  if (((off_t)short_hdr.c_filesizes[0] << 16) + short_hdr.c_filesizes[1]
       != file_hdr->c_filesize)
    {
      char maxbuf[UINTMAX_STRSIZE_BOUND + 1];
      error (0, 0, _("%s: value %s %s out of allowed range 0..%lu"),
	     file_hdr->c_name, _("file size"),
	     STRINGIFY_BIGINT (file_hdr->c_namesize, maxbuf), 0xFFFFFFFFlu);
      return 1;
    }
		      
  /* Output the file header.  */
  tape_buffered_write ((char *) &short_hdr, out_des, 26);

  /* Write file name to output.  */
  tape_buffered_write (file_hdr->c_name, out_des, file_hdr->c_namesize);

  tape_pad_output (out_des, file_hdr->c_namesize + 26);
  return 0;
}

Project: cpio

copyin_file (struct cpio_file_stat *file_hdr, int in_file_des)
{
  bool existing_dir = false;

  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:
      cpio_create_dir (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);
    }
}

Project: cpio

write_nuls_to_file (off_t num_bytes, int out_des, 
                    void (*writer) (char *in_buf, int out_des, off_t num_bytes))
{
  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, sizeof zeros_512);
  if (extra_bytes)
    writer (zeros_512, out_des, extra_bytes);
}

Project: cpio

sparse_write (int fildes, char *buf, size_t nbytes, bool flush)
{
  size_t nwritten = 0;
  ssize_t n;
  char *start_ptr = buf;

  static off_t delayed_seek_count = 0;
  off_t seek_count = 0;

  enum { begin, in_zeros, not_in_zeros } state =
			   delayed_seek_count ? in_zeros : begin;
  
  while (nbytes)
    {
      size_t rest = nbytes;

      if (rest < DISKBLOCKSIZE)
	/* Force write */
	state = not_in_zeros;
      else
	{
	  if (buf_all_zeros (buf, rest))
	    {
	      if (state == not_in_zeros)
		{
		  ssize_t bytes = buf - start_ptr + rest;
		  
		  n = write (fildes, start_ptr, bytes);
		  if (n == -1)
		    return -1;
		  nwritten += n;
		  if (n < bytes)
		    return nwritten + seek_count;
		  start_ptr = NULL;
		}
	      else
		seek_count += rest;
	      state = in_zeros;
	    }
	  else
	    {
	      seek_count += delayed_seek_count;
	      if (lseek (fildes, seek_count, SEEK_CUR) == -1)
		return -1;
	      delayed_seek_count = seek_count = 0;
	      state = not_in_zeros;
	      start_ptr = buf;
	    }
	}
      buf += rest;
      nbytes -= rest;
    }

  if (state != in_zeros)
    {
      seek_count += delayed_seek_count;
      if (seek_count && lseek (fildes, seek_count, SEEK_CUR) == -1)
	return -1;
      delayed_seek_count = seek_count = 0;

      n = write (fildes, start_ptr, buf - start_ptr);
      if (n == -1)
	return n;
      nwritten += n;
    }
  delayed_seek_count += seek_count;

  if (flush && delayed_seek_count)
    {
      if (lseek (fildes, delayed_seek_count - 1, SEEK_CUR) == -1)
	return -1;
      n = write (fildes, "", 1);
      if (n != 1)
	return n;
      delayed_seek_count = 0;
    }      
  
  return nwritten + seek_count;
}

Project: cpio

ds_fgets (FILE *f, dynamic_string *s)
{
  return ds_fgetstr (f, s, '\n');
}

Project: cpio

cpio_to_stat (struct stat *st, struct cpio_file_stat *hdr)
{
  memset (st, 0, sizeof (*st));
  st->st_dev = makedev (hdr->c_dev_maj, hdr->c_dev_min);
  st->st_ino = hdr->c_ino;
  st->st_mode = hdr->c_mode & 0777;
  if (hdr->c_mode & CP_IFREG)
    st->st_mode |= S_IFREG;
  else if (hdr->c_mode & CP_IFDIR)
    st->st_mode |= S_IFDIR;
#ifdef S_IFBLK
  else if (hdr->c_mode & CP_IFBLK)
    st->st_mode |= S_IFBLK;
#endif
#ifdef S_IFCHR
  else if (hdr->c_mode & CP_IFCHR)
    st->st_mode |= S_IFCHR;
#endif
#ifdef S_IFFIFO
  else if (hdr->c_mode & CP_IFIFO)
    st->st_mode |= S_IFIFO;
#endif
#ifdef S_IFLNK
  else if (hdr->c_mode & CP_IFLNK)
    st->st_mode |= S_IFLNK;
#endif
#ifdef S_IFSOCK
  else if (hdr->c_mode & CP_IFSOCK)
    st->st_mode |= S_IFSOCK;
#endif
#ifdef S_IFNWK
  else if (hdr->c_mode & CP_IFNWK)
    st->st_mode |= S_IFNWK;
#endif
  st->st_nlink = hdr->c_nlink;
  st->st_uid = CPIO_UID (hdr->c_uid);
  st->st_gid = CPIO_GID (hdr->c_gid);
  st->st_rdev = makedev (hdr->c_rdev_maj, hdr->c_rdev_min);
  st->st_mtime = hdr->c_mtime;
  st->st_size = hdr->c_filesize;
}

Project: cpio

change_dir ()
{
  if (change_directory_option && chdir (change_directory_option))
    {
      if (errno == ENOENT && create_dir_flag)
	{
	  if (make_path (change_directory_option, -1, -1,
			 (warn_option & CPIO_WARN_INTERDIR) ?
			 _("Creating directory `%s'") : NULL))
	    exit (PAXEXIT_FAILURE);

	  if (chdir (change_directory_option) == 0)
	    return;
	}
      error (PAXEXIT_FAILURE, errno,
	     _("cannot change to directory `%s'"), change_directory_option);
    }
}

Project: cpio

write_out_new_ascii_header (const char *magic_string,
			    struct cpio_file_stat *file_hdr, int out_des)
{
  char ascii_header[110];
  char *p;

  p = stpcpy (ascii_header, magic_string);
  to_ascii_or_warn (p, file_hdr->c_ino, 8, LG_16,
		    file_hdr->c_name, _("inode number"));
  p += 8;
  to_ascii_or_warn (p, file_hdr->c_mode, 8, LG_16, file_hdr->c_name,
		    _("file mode"));
  p += 8;
  to_ascii_or_warn (p, file_hdr->c_uid, 8, LG_16, file_hdr->c_name,
		    _("uid"));
  p += 8;
  to_ascii_or_warn (p, file_hdr->c_gid, 8, LG_16, file_hdr->c_name,
		    _("gid"));
  p += 8;
  to_ascii_or_warn (p, file_hdr->c_nlink, 8, LG_16, file_hdr->c_name,
		    _("number of links"));
  p += 8;
  to_ascii_or_warn (p, file_hdr->c_mtime, 8, LG_16, file_hdr->c_name,
		    _("modification time"));
  p += 8;
  if (to_ascii_or_error (p, file_hdr->c_filesize, 8, LG_16, file_hdr->c_name,
			 _("file size")))
    return 1;
  p += 8;
  if (to_ascii_or_error (p, file_hdr->c_dev_maj, 8, LG_16, file_hdr->c_name,
			 _("device major number")))
    return 1;
  p += 8;
  if (to_ascii_or_error (p, file_hdr->c_dev_min, 8, LG_16, file_hdr->c_name,
			 _("device minor number")))
    return 1;
  p += 8;
  if (to_ascii_or_error (p, file_hdr->c_rdev_maj, 8, LG_16, file_hdr->c_name,
			 _("rdev major")))
    return 1;
  p += 8;
  if (to_ascii_or_error (p, file_hdr->c_rdev_min, 8, LG_16, file_hdr->c_name,
			 _("rdev minor")))
    return 1;
  p += 8;
  if (to_ascii_or_error (p, file_hdr->c_namesize, 8, LG_16, file_hdr->c_name,
			 _("name size")))
    return 1;
  p += 8;
  to_ascii (p, file_hdr->c_chksum & 0xffffffff, 8, LG_16, false);

  tape_buffered_write (ascii_header, out_des, sizeof ascii_header);

  /* Write file name to output.  */
  tape_buffered_write (file_hdr->c_name, out_des, (long) file_hdr->c_namesize);
  tape_pad_output (out_des, file_hdr->c_namesize + sizeof ascii_header);
  return 0;
}

Project: cpio

cpio_mkdir (struct cpio_file_stat *file_hdr, int *setstat_delayed)
{
  int rc;
  mode_t mode = file_hdr->c_mode;
  
  if (!(file_hdr->c_mode & S_IWUSR))
    {
      rc = mkdir (file_hdr->c_name, mode | S_IWUSR);
      if (rc == 0)
	{
	  delay_cpio_set_stat (file_hdr, 0);
	  *setstat_delayed = 1;
	}
    }
  else
    {
      rc = mkdir (file_hdr->c_name, mode);
      *setstat_delayed = 0;
    }
  return rc;
}

Project: cpio

writeout_final_defers (int out_des)
{
  struct deferment *d;
  int other_count;
  while (deferouts != NULL)
    {
      d = deferouts;
      other_count = count_defered_links_to_dev_ino (&d->header);
      if (other_count == 1)
	{
	  writeout_defered_file (&d->header, out_des);
	}
      else
	{
	  struct cpio_file_stat file_hdr;
	  file_hdr = d->header;
	  file_hdr.c_filesize = 0;
	  write_out_header (&file_hdr, out_des);
	}
      deferouts = deferouts->next;
    }
}

Project: cpio

prepare_append (int out_file_des)
{
  int start_of_header;
  int start_of_block;
  int useful_bytes_in_block;
  char *tmp_buf;

  start_of_header = last_header_start;
  /* Figure out how many bytes we will rewrite, and where they start.  */
  useful_bytes_in_block = start_of_header % io_block_size;
  start_of_block = start_of_header - useful_bytes_in_block;

  if (lseek (out_file_des, start_of_block, SEEK_SET) < 0)
    error (PAXEXIT_FAILURE, errno, _("cannot seek on output"));
  if (useful_bytes_in_block > 0)
    {
      tmp_buf = (char *) xmalloc (useful_bytes_in_block);
      read (out_file_des, tmp_buf, useful_bytes_in_block);
      if (lseek (out_file_des, start_of_block, SEEK_SET) < 0)
	error (PAXEXIT_FAILURE, errno, _("cannot seek on output"));
      /* fix juo -- is this copy_tape_buf_out?  or copy_disk? */
      tape_buffered_write (tmp_buf, out_file_des, useful_bytes_in_block);
      free (tmp_buf);
    }

  /* We are done reading the archive, so clear these since they
     will now be used for reading in files that we are appending
     to the archive.  */
  input_size = 0;
  input_bytes = 0;
  in_buff = input_buffer;
}

Project: cpio

apply_delayed_set_stat ()
{
  while (delayed_set_stat_head)
    {
      struct delayed_set_stat *data = delayed_set_stat_head;
      if (data->invert_permissions)
	{
	  data->stat.c_mode ^= data->invert_permissions;
	}
      set_perms (-1, &data->stat);
      delayed_set_stat_head = data->next;
      free (data);
    }
}

Project: cpio

cpio_file_stat_init (struct cpio_file_stat *file_hdr)
{
  memset (file_hdr, 0, sizeof (*file_hdr));
}

Project: cpio

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 (PAXEXIT_FAILURE, errno, _("write error"));
	}
      else
	error (PAXEXIT_FAILURE, errno, _("write error"));
    }
  output_bytes += output_size;
  out_buff = output_buffer;
  output_size = 0;
}

Project: cpio

arf_stores_inode_p (enum archive_format arf)
{
  switch (arf)
    {
    case arf_tar:
    case arf_ustar:
      return 0;

    default:
      break;
    }
  return 1;
}

Project: cpio

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);
}

Project: cpio

cpio_file_stat_free (struct cpio_file_stat *file_hdr)
{
  free (file_hdr->c_name);
  cpio_file_stat_init (file_hdr);
}

Project: cpio

to_ascii_or_error (char *where, uintmax_t n, size_t digits,
		   unsigned logbase,
		   const char *filename, const char *fieldname)
{
  if (to_ascii (where, n, digits, logbase, false))
    {
      field_width_error (filename, fieldname, n, digits, false);
      return 1;
    }
  return 0;
}

Project: cpio

write_out_header (struct cpio_file_stat *file_hdr, int out_des)
{
  dev_t dev;
  dev_t rdev;
  
  switch (archive_format)
    {
    case arf_newascii:
      return write_out_new_ascii_header ("070701", file_hdr, out_des);
      
    case arf_crcascii:
      return write_out_new_ascii_header ("070702", file_hdr, out_des);
      
    case arf_oldascii:
      return write_out_old_ascii_header (makedev (file_hdr->c_dev_maj,
						  file_hdr->c_dev_min),
					 makedev (file_hdr->c_rdev_maj,
						  file_hdr->c_rdev_min),
					 file_hdr, out_des);
      
    case arf_hpoldascii:
      hp_compute_dev (file_hdr, &dev, &rdev);
      return write_out_old_ascii_header (dev, rdev, file_hdr, out_des);
      
    case arf_tar:
    case arf_ustar:
      if (is_tar_filename_too_long (file_hdr->c_name))
	{
	  error (0, 0, _("%s: file name too long"), file_hdr->c_name);
	  return 1;
	}
      return write_out_tar_header (file_hdr, out_des);

    case arf_binary:
      return write_out_binary_header (makedev (file_hdr->c_rdev_maj,
					       file_hdr->c_rdev_min),
				      file_hdr, out_des);

    case arf_hpbinary:
      hp_compute_dev (file_hdr, &dev, &rdev);
      /* FIXME: dev ignored. Should it be? */
      return write_out_binary_header (rdev, file_hdr, out_des);

    default:
      abort ();
    }
}

Project: cpio

tape_buffered_peek (char *peek_buf, int in_des, int num_bytes)
{
  long tmp_input_size;
  long got_bytes;
  char *append_buf;

#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) >= 1073741824L) )
    {
      lseek(in_des, 0L, SEEK_SET);
      input_bytes_before_lseek = 0;
    }
#endif

  while (input_size < num_bytes)
    {
      append_buf = in_buff + input_size;
      if ( (append_buf - input_buffer) >= input_buffer_size)
	{
	  /* We can keep up to 2 "blocks" (either the physical block size
	     or 512 bytes(the size of a tar record), which ever is
	     larger) in the input buffer when we are peeking.  We
	     assume that our caller will never be interested in peeking
	     ahead at more than 512 bytes, so we know that by the time
	     we need a 3rd "block" in the buffer we can throw away the
	     first block to make room.  */
	  int half;
	  half = input_buffer_size / 2;
	  memmove (input_buffer, input_buffer + half, half);
	  in_buff = in_buff - half;
	  append_buf = append_buf - half;
	}
      tmp_input_size = rmtread (in_des, append_buf, io_block_size);
      if (tmp_input_size == 0)
	{
	  if (input_is_special)
	    {
	      get_next_reel (in_des);
	      tmp_input_size = rmtread (in_des, append_buf, io_block_size);
	    }
	  else
	    break;
	}
      if (tmp_input_size < 0)
	error (PAXEXIT_FAILURE, errno, _("read error"));
      input_bytes += tmp_input_size;
      input_size += tmp_input_size;
    }
  if (num_bytes <= input_size)
    got_bytes = num_bytes;
  else
    got_bytes = input_size;
  memcpy (peek_buf, in_buff, (unsigned) got_bytes);
  return got_bytes;
}

Project: cpio

last_link (struct cpio_file_stat *file_hdr)
{
  return file_hdr->c_nlink == count_defered_links_to_dev_ino (file_hdr) + 1;
}

Project: cpio

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"), (int) digs, where);
	  break;
	}
      
      d = p - codetab;
      if ((d >> logbase) > 1)
	{
	  error (0, 0, _("Malformed number %.*s"), (int) 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"),
	   (int) digs, where);
  return value;
}

Project: cpio

writeout_defered_file (struct cpio_file_stat *header, int out_file_des)
{
  int in_file_des;
  struct cpio_file_stat file_hdr;

  file_hdr = *header;


  in_file_des = open (header->c_name,
		      O_RDONLY | O_BINARY, 0);
  if (in_file_des < 0)
    {
      open_error (header->c_name);
      return;
    }

  if (archive_format == arf_crcascii)
    file_hdr.c_chksum = read_for_checksum (in_file_des,
					   file_hdr.c_filesize,
					   header->c_name);

  if (write_out_header (&file_hdr, out_file_des))
    return;
  copy_files_disk_to_tape (in_file_des, out_file_des, file_hdr.c_filesize,
			   header->c_name);
  warn_if_file_changed(header->c_name, file_hdr.c_filesize, file_hdr.c_mtime);

  if (archive_format == arf_tar || archive_format == arf_ustar)
    add_inode (file_hdr.c_ino, file_hdr.c_name, file_hdr.c_dev_maj,
	       file_hdr.c_dev_min);

  tape_pad_output (out_file_des, file_hdr.c_filesize);

  if (reset_time_flag)
    set_file_times (in_file_des, file_hdr.c_name, file_hdr.c_mtime,
		    file_hdr.c_mtime);
  if (close (in_file_des) < 0)
    close_error (header->c_name);
}

Project: cpio

link_to_maj_min_ino (char *file_name, int st_dev_maj, int st_dev_min,
		     ino_t st_ino)
{
  int	link_res;
  char *link_name;
  link_res = -1;
  /* Is the file a link to a previously copied file?  */
  link_name = find_inode_file (st_ino,
			       st_dev_maj,
			       st_dev_min);
  if (link_name == NULL)
    add_inode (st_ino, file_name,
	       st_dev_maj,
	       st_dev_min);
  else
    link_res = link_to_name (file_name, link_name);
  return link_res;
}

Project: cpio

tape_pad_output (int out_file_des, int offset)
{
  size_t pad;

  if (archive_format == arf_newascii || archive_format == arf_crcascii)
    pad = (4 - (offset % 4)) % 4;
  else if (archive_format == arf_tar || archive_format == arf_ustar)
    pad = (512 - (offset % 512)) % 512;
  else if (archive_format != arf_oldascii && archive_format != arf_hpoldascii)
    pad = (2 - (offset % 2)) % 2;
  else
    pad = 0;

  if (pad != 0)
    write_nuls_to_file (pad, out_file_des, tape_buffered_write);
}

Project: cpio

tape_toss_input (int in_des, off_t num_bytes)
{
  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)
    {
      if (input_size == 0)
	tape_fill_input_buffer (in_des, io_block_size);
      if (bytes_left < input_size)
	space_left = bytes_left;
      else
	space_left = input_size;

      if (crc_i_flag && only_verify_crc_flag)
	{
 	  int k;
	  for (k = 0; k < space_left; ++k)
	    crc += in_buff[k] & 0xff;
	}

      in_buff += space_left;
      input_size -= space_left;
      bytes_left -= space_left;
    }
}

Project: cpio

repair_delayed_set_stat (struct cpio_file_stat *file_hdr)
{
  struct delayed_set_stat *data;
  for (data = delayed_set_stat_head; data; data = data->next)
    {
      if (strcmp (file_hdr->c_name, data->stat.c_name) == 0)
	{
	  data->invert_permissions = 0;
	  memcpy (&data->stat, file_hdr,
		  offsetof (struct cpio_file_stat, c_name));
	  return 0;
	}
    }
  return 1;
}

Project: cpio

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_chksum = FROM_HEX (ascii_header.c_chksum);
  read_name_from_file (file_hdr, in_des, FROM_HEX (ascii_header.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);
}

Project: cpio

ds_concat (dynamic_string *s, char const *str)
{
  size_t len = strlen (str);
  while (len + 1 > s->ds_size)
    ds_resize (s);
  memcpy (s->ds_string + s->ds_idx, str, len);
  s->ds_idx += len;
  s->ds_string[s->ds_idx] = 0;
}

Project: cpio

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)
    /* The 'p' string is shortened version of 'name' with one exception;  when
       the 'name' points to an empty string (buffer where name[0] == '\0') the
       'p' then points to static string ".".  So caller needs to ensure there
       are at least two bytes available in 'name' buffer so memmove succeeds. */
    memmove (name, p, (size_t)(strlen (p) + 1));
}

Project: cpio

find_inode_file (ino_t node_num, unsigned long major_num,
		 unsigned long minor_num)
{
  struct inode_val *ival = find_inode_val (node_num, major_num, minor_num);
  return ival ? ival->file_name : NULL;
}

Project: cpio

read_for_checksum (int in_file_des, int file_size, char *file_name)
{
  uint32_t crc;
  char buf[BUFSIZ];
  int bytes_left;
  int bytes_read;
  int i;

  crc = 0;

  for (bytes_left = file_size; bytes_left > 0; bytes_left -= bytes_read)
    {
      bytes_read = read (in_file_des, buf, BUFSIZ);
      if (bytes_read < 0)
	error (PAXEXIT_FAILURE, errno, _("cannot read checksum for %s"), file_name);
      if (bytes_read == 0)
	break;
      if (bytes_left < bytes_read)
        bytes_read = bytes_left;
      for (i = 0; i < bytes_read; ++i)
	crc += buf[i] & 0xff;
    }
  if (lseek (in_file_des, 0L, SEEK_SET))
    error (PAXEXIT_FAILURE, errno, _("cannot read checksum for %s"), file_name);

  return crc;
}

Project: cpio

field_width_warning (const char *filename, const char *fieldname)
{
  if (warn_option & CPIO_WARN_TRUNCATE)
    error (0, 0, _("%s: truncating %s"), filename, fieldname);
}

Project: cpio

count_defered_links_to_dev_ino (struct cpio_file_stat *file_hdr)
{
  struct deferment *d;
  ino_t	ino = file_hdr->c_ino;
  long 	maj = file_hdr->c_dev_maj;
  long  min = file_hdr->c_dev_min;
  size_t count = 0;

  for (d = deferouts; d != NULL; d = d->next)
    {
      if (d->header.c_ino == ino
	  && d->header.c_dev_maj == maj
	  && d->header.c_dev_min == min)
	++count;
    }
  return count;
}

Project: cpio

repair_inter_delayed_set_stat (struct stat *dir_stat_info)
{
  struct delayed_set_stat *data;
  for (data = delayed_set_stat_head; data; data = data->next)
    {
      struct stat st;
      if (stat (data->stat.c_name, &st) != 0)
	{
	  stat_error (data->stat.c_name);
	  return -1;
	}

      if (st.st_dev == dir_stat_info->st_dev
	  && st.st_ino == dir_stat_info->st_ino)
	{
	  stat_to_cpio (&data->stat, dir_stat_info);
	  data->invert_permissions =
	    ((dir_stat_info->st_mode ^ st.st_mode)
	     & MODE_RWX & ~ newdir_umask);
	  return 0;
	}
    }
  return 1;
}

Project: cpio

get_next_reel (int tape_des)
{
  static int reel_number = 1;
  FILE *tty_in;			/* File for interacting with user.  */
  FILE *tty_out;		/* File for interacting with user.  */
  int old_tape_des;
  char *next_archive_name;
  dynamic_string new_name = DYNAMIC_STRING_INITIALIZER;
  char *str_res;

  /* Open files for interactive communication.  */
  tty_in = fopen (TTY_NAME, "r");
  if (tty_in == NULL)
    error (PAXEXIT_FAILURE, errno, TTY_NAME);
  tty_out = fopen (TTY_NAME, "w");
  if (tty_out == NULL)
    error (PAXEXIT_FAILURE, errno, TTY_NAME);

  old_tape_des = tape_des;
  tape_offline (tape_des);
  rmtclose (tape_des);

  /* Give message and wait for carrage return.  User should hit carrage return
     only after loading the next tape.  */
  ++reel_number;
  if (new_media_message)
    fprintf (tty_out, "%s", new_media_message);
  else if (new_media_message_with_number)
    fprintf (tty_out, "%s%d%s", new_media_message_with_number, reel_number,
	     new_media_message_after_number);
  else if (archive_name)
    fprintf (tty_out, _("Found end of tape.  Load next tape and press RETURN. "));
  else
    fprintf (tty_out, _("Found end of tape.  To continue, type device/file name when ready.\n"));

  fflush (tty_out);

  if (archive_name)
    {
      int c;

      do
	c = getc (tty_in);
      while (c != EOF && c != '\n');

      tape_des = open_archive (archive_name);
      if (tape_des == -1)
	open_error (archive_name);
    }
  else
    {
      do
	{
	  if (tape_des < 0)
	    {
	      fprintf (tty_out,
		       _("To continue, type device/file name when ready.\n"));
	      fflush (tty_out);
	    }

	  str_res = ds_fgets (tty_in, &new_name);
	  if (str_res == NULL || str_res[0] == '\0')
	    exit (PAXEXIT_FAILURE);
	  next_archive_name = str_res;

	  tape_des = open_archive (next_archive_name);
	  if (tape_des == -1)
	    open_error (next_archive_name);
	}
      while (tape_des < 0);
    }

  /* We have to make sure that `tape_des' has not changed its value even
     though we closed it and reopened it, since there are local
     copies of it in other routines.  This works fine on Unix (even with
     rmtread and rmtwrite) since open will always return the lowest
     available file descriptor and we haven't closed any files (e.g.,
     stdin, stdout or stderr) that were opened before we originally opened
     the archive.  */

  if (tape_des != old_tape_des)
    error (PAXEXIT_FAILURE, 0, _("internal error: tape descriptor changed from %d to %d"),
	   old_tape_des, tape_des);

  ds_free (&new_name);
  fclose (tty_in);
  fclose (tty_out);
}

Project: cpio

warn_if_file_changed (char *file_name, off_t old_file_size,
		      time_t old_file_mtime)
{
  struct stat new_file_stat;
  if ((*xstat) (file_name, &new_file_stat) < 0)
    {
      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,
	   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);
}

Project: cpio

ds_init (dynamic_string *string)
{
  memset (string, 0, sizeof *string);
}

Project: cpio

get_inode_and_dev (struct cpio_file_stat *hdr, struct stat *st)
{
  if (renumber_inodes_option)
    {
      if (st->st_nlink > 1)
	{
	  struct inode_val *ival = find_inode_val (st->st_ino,
						   major (st->st_dev),
						   minor (st->st_dev));
	  if (!ival)
	    ival = add_inode (st->st_ino, NULL,
			      major (st->st_dev), minor (st->st_dev));
	  hdr->c_ino = ival->trans_inode;
	}
      else
	hdr->c_ino = next_inode++;
    }
  else
    hdr->c_ino = st->st_ino;
  if (ignore_devno_option)
    {
      hdr->c_dev_maj = 0;
      hdr->c_dev_min = 0;
    }
  else
    {
      hdr->c_dev_maj = major (st->st_dev);
      hdr->c_dev_min = minor (st->st_dev);
    }
}

Project: cpio

ds_reset (dynamic_string *s, size_t len)
{
  while (len > s->ds_size)
    ds_resize (s);
  s->ds_idx = len;
}

Project: cpio

delay_cpio_set_stat (struct cpio_file_stat *file_stat,
		     mode_t invert_permissions)
{
  size_t file_name_len = strlen (file_stat->c_name);
  struct delayed_set_stat *data =
    xmalloc (sizeof (struct delayed_set_stat) + file_name_len + 1);
  data->next = delayed_set_stat_head;
  memcpy (&data->stat, file_stat, sizeof data->stat);
  data->stat.c_name = (char*) (data + 1);
  strcpy (data->stat.c_name, file_stat->c_name);
  data->invert_permissions = invert_permissions;
  delayed_set_stat_head = data;
}

Project: cpio

copy_files_tape_to_disk (int in_des, int out_des, off_t num_bytes)
{
  off_t size;
  off_t k;

  while (num_bytes > 0)
    {
      if (input_size == 0)
	tape_fill_input_buffer (in_des, io_block_size);
      size = (input_size < num_bytes) ? input_size : num_bytes;
      if (crc_i_flag)
	{
	  for (k = 0; k < size; ++k)
	    crc += in_buff[k] & 0xff;
	}
      disk_buffered_write (in_buff, out_des, size);
      num_bytes -= size;
      input_size -= size;
      in_buff += size;
    }
}

Project: cpio

set_copypass_perms (int fd, const char *name, struct stat *st)
{
  struct cpio_file_stat header;
  header.c_name = (char*)name;
  stat_to_cpio (&header, st);
  set_perms (fd, &header);
}

Project: cpio

read_name_from_file (struct cpio_file_stat *file_hdr, int fd, uintmax_t len)
{
  if (len == 0)
    {
      error (0, 0, _("malformed header: file name of zero length"));
    }
  else
    {
      cpio_realloc_c_name (file_hdr, len);
      tape_buffered_read (file_hdr->c_name, fd, len);
      if (file_hdr->c_name[len-1] != 0)
	{
	  error (0, 0, _("malformed header: file name is not nul-terminated"));
	  /* Skip this file */
	  len = 0;
	}
    }
  file_hdr->c_namesize = len;
}

Project: cpio

buf_all_zeros (char *buf, int bufsize)
{
  int	i;
  for (i = 0; i < bufsize; ++i)
    {
      if (*buf++ != '\0')
	return 0;
    }
  return 1;
}

Project: cpio

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;
  input_size = read (in_des, input_buffer, num_bytes);
  if (input_size == SAFE_READ_ERROR)
    {
      input_size = 0;
      return (-1);
    }
  else if (input_size == 0)
    return (1);
  input_bytes += input_size;
  return (0);
}

Project: cpio

to_ascii_or_warn (char *where, uintmax_t n, size_t digits,
		  unsigned logbase,
		  const char *filename, const char *fieldname)
{
  if (to_ascii (where, n, digits, logbase, false))
    field_width_warning (filename, fieldname);
}

Project: cpio

add_inode (ino_t node_num, char *file_name, unsigned long major_num,
	   unsigned long minor_num)
{
  struct inode_val *temp;
  struct inode_val *e = NULL;
  
  /* Create new inode record.  */
  temp = (struct inode_val *) xmalloc (sizeof (struct inode_val));
  temp->inode = node_num;
  temp->major_num = major_num;
  temp->minor_num = minor_num;
  temp->file_name = file_name ? xstrdup (file_name) : NULL;

  if (renumber_inodes_option)
    temp->trans_inode = next_inode++;
  else
    temp->trans_inode = temp->inode;

  if (!((hash_table
	 || (hash_table = hash_initialize (0, 0, inode_val_hasher,
					   inode_val_compare, 0)))
	&& (e = hash_insert (hash_table, temp))))
    xalloc_die ();
  return e;
}

Project: cpio

read_pattern_file (void)
{
  char **new_save_patterns = NULL;
  size_t max_new_patterns;
  size_t new_num_patterns;
  int i;
  dynamic_string pattern_name = DYNAMIC_STRING_INITIALIZER;
  FILE *pattern_fp;

  if (num_patterns < 0)
    num_patterns = 0;
  new_num_patterns = num_patterns;
  max_new_patterns = num_patterns;
  new_save_patterns = xcalloc (max_new_patterns, sizeof (new_save_patterns[0]));

  pattern_fp = fopen (pattern_file_name, "r");
  if (pattern_fp == NULL)
    open_fatal (pattern_file_name);
  while (ds_fgetstr (pattern_fp, &pattern_name, '\n') != NULL)
    {
      if (new_num_patterns == max_new_patterns)
	new_save_patterns = x2nrealloc (new_save_patterns,
					&max_new_patterns,
					sizeof (new_save_patterns[0]));
      new_save_patterns[new_num_patterns] = xstrdup (pattern_name.ds_string);
      ++new_num_patterns;
    }

  ds_free (&pattern_name);
  
  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;
}

Project: cpio

ds_append (dynamic_string *s, int c)
{
  ds_resize (s);
  s->ds_string[s->ds_idx] = c;
  if (c)
    {
      s->ds_idx++;
      ds_resize (s);
      s->ds_string[s->ds_idx] = 0;
    }      
}

Project: cpio

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;
}

Project: cpio

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)
    {
      union
      {
	char s[512];
	unsigned short us;
      }	tmpbuf;
      int check_tar;
      int peeked_bytes;

      while (archive_format == arf_unknown)
	{
	  peeked_bytes = tape_buffered_peek (tmpbuf.s, in_des, 512);
	  if (peeked_bytes < 6)
	    error (PAXEXIT_FAILURE, 0, _("premature end of archive"));

	  if (!strncmp (tmpbuf.s, "070701", 6))
	    archive_format = arf_newascii;
	  else if (!strncmp (tmpbuf.s, "070707", 6))
	    archive_format = arf_oldascii;
	  else if (!strncmp (tmpbuf.s, "070702", 6))
	    {
	      archive_format = arf_crcascii;
	      crc_i_flag = true;
	    }
	  else if (tmpbuf.us == 070707
		   || tmpbuf.us == swab_short ((unsigned short) 070707))
	    archive_format = arf_binary;
	  else if (peeked_bytes >= 512
		   && (check_tar = is_tar_header (tmpbuf.s)))
	    {
	      if (check_tar == 2)
		archive_format = arf_ustar;
	      else
		archive_format = arf_tar;
	    }
	  else
	    {
	      tape_buffered_read (tmpbuf.s, 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, sizeof (magic.str));
  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, sizeof (magic.str) - 1);
      tape_buffered_read (magic.str + sizeof (magic.str) - 1, in_des, 1L);
    }
}

Project: cpio

tape_buffered_write (char *in_buf, int out_des, off_t num_bytes)
{
  off_t bytes_left = num_bytes;	/* Bytes needing to be copied.  */
  off_t space_left;	/* Room left in output buffer.  */

  while (bytes_left > 0)
    {
      space_left = io_block_size - output_size;
      if (space_left == 0)
	tape_empty_output_buffer (out_des);
      else
	{
	  if (bytes_left < space_left)
	    space_left = bytes_left;
	  memcpy (out_buff, in_buf, (unsigned) space_left);
	  out_buff += space_left;
	  output_size += space_left;
	  in_buf += space_left;
	  bytes_left -= space_left;
	}
    }
}

Project: cpio

set_new_media_message (char *message)
{
  char *p;
  int prev_was_percent;

  p = message;
  prev_was_percent = 0;
  while (*p != '\0')
    {
      if (*p == 'd' && prev_was_percent)
	break;
      prev_was_percent = (*p == '%');
      ++p;
    }
  if (*p == '\0')
    {
      new_media_message = xstrdup (message);
    }
  else
    {
      int length = p - message - 1;

      new_media_message_with_number = xmalloc (length + 1);
      strncpy (new_media_message_with_number, message, length);
      new_media_message_with_number[length] = '\0';
      length = strlen (p + 1);
      new_media_message_after_number = xmalloc (length + 1);
      strcpy (new_media_message_after_number, p + 1);
    }
}

Project: cpio

ds_free (dynamic_string *string)
{
  free (string->ds_string);
}

Project: cpio

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);
  if (retain_time_flag)
    set_file_times (fd, header->c_name, header->c_mtime, header->c_mtime);
}

Project: cpio

link_to_name (char const *link_name, char const *link_target)
{
  int res = link (link_target, link_name);
  if (res < 0 && create_dir_flag)
    {
      create_all_directories (link_name);
      res = link (link_target, link_name);
    }
  if (res == 0)
    {
      if (verbose_flag)
	error (0, 0, _("%s linked to %s"),
	       link_target, link_name);
    }
  else if (link_flag)
    {
      error (0, errno, _("cannot link %s to %s"),
	     link_target, link_name);
    }
  return res;
}

Project: cpio

disk_empty_output_buffer (int out_des, bool flush)
{
  ssize_t 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, flush);
  else
    bytes_written = write (out_des, output_buffer, output_size);

  if (bytes_written != output_size)
    {
      if (bytes_written == -1)
	error (PAXEXIT_FAILURE, errno, _("write error"));
      else
	error (PAXEXIT_FAILURE, 0, _("write error: partial write"));
    }
  output_bytes += output_size;
  out_buff = output_buffer;
  output_size = 0;
}

Project: cpio

try_existing_file (struct cpio_file_stat* file_hdr, int in_file_des,
		   bool *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;
}

Project: cpio

process_copy_pass (void)
{
  dynamic_string input_name = DYNAMIC_STRING_INITIALIZER;
                                /* Name of file from stdin.  */
  dynamic_string output_name = DYNAMIC_STRING_INITIALIZER;
                                /* Name of new file.  */
  size_t dirname_len;		/* Length of `directory_name'.  */
  int res;			/* Result of functions.  */
  char *slash;			/* For moving past slashes in input name.  */
  struct stat in_file_stat;	/* Stat record for input file.  */
  struct stat out_file_stat;	/* Stat record for output file.  */
  int in_file_des;		/* Input file descriptor.  */
  int out_file_des;		/* Output file descriptor.  */
  int existing_dir;		/* True if file is a dir & already exists.  */

  newdir_umask = umask (0);     /* Reset umask to preserve modes of
				   created files  */

  /* Initialize the copy pass.  */
  
  dirname_len = strlen (directory_name);
  if (change_directory_option && !ISSLASH (directory_name[0]))
    {
      char *pwd = xgetcwd ();
      
      ds_concat (&output_name, pwd);
      ds_append (&output_name, '/');
    }
  ds_concat (&output_name, directory_name);
  ds_append (&output_name, '/');
  dirname_len = ds_len (&output_name);
  output_is_seekable = true;

  change_dir ();
  
  /* Copy files with names read from stdin.  */
  while (ds_fgetstr (stdin, &input_name, name_end) != NULL)
    {
      int link_res = -1;

      /* Check for blank line and ignore it if found.  */
      if (input_name.ds_string[0] == '\0')
	{
	  error (0, 0, _("blank line ignored"));
	  continue;
	}

      /* Check for current directory and ignore it if found.  */
      if (input_name.ds_string[0] == '.'
	  && (input_name.ds_string[1] == '\0'
	      || (input_name.ds_string[1] == '/'
		  && input_name.ds_string[2] == '\0')))
	continue;

      if ((*xstat) (input_name.ds_string, &in_file_stat) < 0)
	{
	  stat_error (input_name.ds_string);
	  continue;
	}

      /* Make the name of the new file.  */
      for (slash = input_name.ds_string; *slash == '/'; ++slash)
	;
      ds_reset (&output_name, dirname_len);
      ds_concat (&output_name, slash);

      existing_dir = false;
      if (lstat (output_name.ds_string, &out_file_stat) == 0)
	{
	  if (S_ISDIR (out_file_stat.st_mode)
	      && S_ISDIR (in_file_stat.st_mode))
	    {
	      /* If there is already a directory there that
		 we are trying to create, don't complain about it.  */
	      existing_dir = true;
	    }
	  else if (!unconditional_flag
		   && in_file_stat.st_mtime <= out_file_stat.st_mtime)
	    {
	      error (0, 0, _("%s not created: newer or same age version exists"),
		     output_name.ds_string);
	      continue;		/* Go to the next file.  */
	    }
	  else if (S_ISDIR (out_file_stat.st_mode)
			? rmdir (output_name.ds_string)
			: unlink (output_name.ds_string))
	    {
	      error (0, errno, _("cannot remove current %s"),
		     output_name.ds_string);
	      continue;		/* Go to the next file.  */
	    }
	}

      /* Do the real copy or link.  */
      if (S_ISREG (in_file_stat.st_mode))
	{
	  /* Can the current file be linked to a another file?
	     Set link_name to the original file name.  */
	  if (link_flag)
	    /* User said to link it if possible.  Try and link to
	       the original copy.  If that fails we'll still try
	       and link to a copy we've already made.  */
	    link_res = link_to_name (output_name.ds_string, 
				     input_name.ds_string);
	  if ( (link_res < 0) && (in_file_stat.st_nlink > 1) )
	    link_res = link_to_maj_min_ino (output_name.ds_string, 
				major (in_file_stat.st_dev), 
				minor (in_file_stat.st_dev), 
				in_file_stat.st_ino);

	  /* If the file was not linked, copy contents of file.  */
	  if (link_res < 0)
	    {
	      in_file_des = open (input_name.ds_string,
				  O_RDONLY | O_BINARY, 0);
	      if (in_file_des < 0)
		{
		  open_error (input_name.ds_string);
		  continue;
		}
	      out_file_des = open (output_name.ds_string,
				   O_CREAT | O_WRONLY | O_BINARY, 0600);
	      if (out_file_des < 0 && create_dir_flag)
		{
		  create_all_directories (output_name.ds_string);
		  out_file_des = open (output_name.ds_string,
				       O_CREAT | O_WRONLY | O_BINARY, 0600);
		}
	      if (out_file_des < 0)
		{
		  open_error (output_name.ds_string);
		  close (in_file_des);
		  continue;
		}

	      copy_files_disk_to_disk (in_file_des, out_file_des, in_file_stat.st_size, input_name.ds_string);
	      disk_empty_output_buffer (out_file_des, true);
	      
	      set_copypass_perms (out_file_des,
				  output_name.ds_string, &in_file_stat);

	      if (reset_time_flag)
                {
                  set_file_times (in_file_des,
				  input_name.ds_string,
                                  in_file_stat.st_atime,
                                  in_file_stat.st_mtime);
                  set_file_times (out_file_des,
				  output_name.ds_string,
                                  in_file_stat.st_atime,
                                  in_file_stat.st_mtime);
	        } 

	      if (close (in_file_des) < 0)
		close_error (input_name.ds_string);

	      if (close (out_file_des) < 0)
		close_error (output_name.ds_string);

	      warn_if_file_changed(input_name.ds_string, in_file_stat.st_size,
                                   in_file_stat.st_mtime);
	    }
	}
      else if (S_ISDIR (in_file_stat.st_mode))
	{
	  struct cpio_file_stat file_stat;
	  
	  stat_to_cpio (&file_stat, &in_file_stat);
	  file_stat.c_name = output_name.ds_string;
	  cpio_create_dir (&file_stat, existing_dir);
	}
      else if (S_ISCHR (in_file_stat.st_mode) ||
	       S_ISBLK (in_file_stat.st_mode) ||
#ifdef S_ISFIFO
	       S_ISFIFO (in_file_stat.st_mode) ||
#endif
#ifdef S_ISSOCK
	       S_ISSOCK (in_file_stat.st_mode) ||
#endif
	       0)
	{
	  /* Can the current file be linked to a another file?
	     Set link_name to the original file name.  */
	  if (link_flag)
	    /* User said to link it if possible.  */
	    link_res = link_to_name (output_name.ds_string, 
				     input_name.ds_string);
	  if ( (link_res < 0) && (in_file_stat.st_nlink > 1) )
	    link_res = link_to_maj_min_ino (output_name.ds_string, 
			major (in_file_stat.st_dev),
			minor (in_file_stat.st_dev),
			in_file_stat.st_ino);

	  if (link_res < 0)
	    {
	      res = mknod (output_name.ds_string, in_file_stat.st_mode,
			   in_file_stat.st_rdev);
	      if (res < 0 && create_dir_flag)
		{
		  create_all_directories (output_name.ds_string);
		  res = mknod (output_name.ds_string, in_file_stat.st_mode,
			       in_file_stat.st_rdev);
		}
	      if (res < 0)
		{
		  mknod_error (output_name.ds_string);
		  continue;
		}
	      set_copypass_perms (-1, output_name.ds_string, &in_file_stat);
	    }
	}

#ifdef S_ISLNK
      else if (S_ISLNK (in_file_stat.st_mode))
	{
	  char *link_name;
	  int link_size;
	  link_name = (char *) xmalloc ((unsigned int) in_file_stat.st_size + 1);

	  link_size = readlink (input_name.ds_string, link_name,
			        in_file_stat.st_size);
	  if (link_size < 0)
	    {
	      readlink_error (input_name.ds_string);
	      free (link_name);
	      continue;
	    }
	  link_name[link_size] = '\0';

	  res = UMASKED_SYMLINK (link_name, output_name.ds_string,
				 in_file_stat.st_mode);
	  if (res < 0 && create_dir_flag)
	    {
	      create_all_directories (output_name.ds_string);
	      res = UMASKED_SYMLINK (link_name, output_name.ds_string,
				     in_file_stat.st_mode);
	    }
	  if (res < 0)
	    {
	      symlink_error (output_name.ds_string, link_name);
	      free (link_name);
	      continue;
	    }

	  /* Set the attributes of the new link.  */
	  if (!no_chown_flag)
            {
              uid_t uid = set_owner_flag ? set_owner : in_file_stat.st_uid;
              gid_t gid = set_group_flag ? set_group : in_file_stat.st_gid;
	      if ((lchown (output_name.ds_string, uid, gid) < 0)
		  && errno != EPERM)
	        chown_error_details (output_name.ds_string, uid, gid);
            }
	  free (link_name);
	}
#endif
      else
	{
	  error (0, 0, _("%s: unknown file type"), input_name.ds_string);
	}

      if (verbose_flag)
	fprintf (stderr, "%s\n", output_name.ds_string);
      if (dot_flag)
	fputc ('.', stderr);
    }

  if (dot_flag)
    fputc ('\n', stderr);

  apply_delayed_set_stat ();
  
  if (!quiet_flag)
    {
      size_t blocks = (output_bytes + io_block_size - 1) / io_block_size;
      fprintf (stderr,
	       ngettext ("%lu block\n", "%lu blocks\n",
			 (unsigned long) blocks),
	       (unsigned long) blocks);
    }

  ds_free (&input_name);
  ds_free (&output_name);
}

Project: cpio

tape_offline (int tape_des)
{
#if defined(MTIOCTOP) && defined(MTOFFL)
  struct mtop control;

  control.mt_op = MTOFFL;
  control.mt_count = 1;
  rmtioctl (tape_des, MTIOCTOP, (char*) &control);	/* Don't care if it fails.  */
#endif
}

Project: cpio

hp_compute_dev (struct cpio_file_stat *file_hdr, dev_t *pdev, dev_t *prdev)
{
  /* 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.  */
  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
      file_hdr->c_filesize = makedev (file_hdr->c_rdev_maj,
				      file_hdr->c_rdev_min);
      *pdev = *prdev = makedev (0, 1);
      break;

    default:
      *pdev = makedev (file_hdr->c_dev_maj, file_hdr->c_dev_min);
      *prdev = makedev (file_hdr->c_rdev_maj, file_hdr->c_rdev_min);
      break;
    }
}

Project: cpio

to_ascii (char *where, uintmax_t v, size_t digits, unsigned logbase, bool nul)
{
  static char codetab[] = "0123456789ABCDEF";

  if (nul)
    where[--digits] = 0;
  while (digits > 0)
    {
      where[--digits] = codetab[(v & ((1 << logbase) - 1))];
      v >>= logbase;
    }

  return v != 0;
}

Project: cpio

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);
      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
    cpio_set_c_name (file_hdr, new_name.ds_string);
  return 0;
}

Project: cpio

writeout_other_defers (struct cpio_file_stat *file_hdr, int out_des)
{
  struct deferment *d;
  struct deferment *d_prev;
  ino_t	ino;
  int 	maj;
  int   min;
  ino = file_hdr->c_ino;
  maj = file_hdr->c_dev_maj;
  min = file_hdr->c_dev_min;
  d_prev = NULL;
  d = deferouts;
  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;
	  d->header.c_filesize = 0;
	  write_out_header (&d->header, out_des);
	  if (d_prev != NULL)
	    d_prev->next = d->next;
	  else
	    deferouts = d->next;
	  d_free = d;
	  d = d->next;
	  free_deferment (d_free);
	}
      else
	{
	  d_prev = d;
	  d = d->next;
	}
    }
  return;
}

Project: cpio

create_defered_links_to_skipped (struct cpio_file_stat *file_hdr,
				 int in_file_des)
{
  struct deferment *d;
  struct deferment *d_prev;
  ino_t	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;
	  cpio_set_c_name (file_hdr, 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;
}

Project: cpio

assign_string (char **pvar, char *value)
{
  char *p = xrealloc (*pvar, strlen (value) + 1);
  strcpy (p, value);
  *pvar = p;
}

Project: cpio

inode_val_hasher (const void *val, size_t n_buckets)
{
  const struct inode_val *ival = val;
  return ival->inode % n_buckets;
}

Project: cpio

copy_files_disk_to_disk (int in_des, int out_des, off_t num_bytes,
			 char *filename)
{
  off_t size;
  off_t k;
  off_t original_num_bytes;
  int rc;

  original_num_bytes = num_bytes;
  while (num_bytes > 0)
    {
      if (input_size == 0)
	if ((rc = disk_fill_input_buffer (in_des, num_bytes)))
	  {
	    if (rc > 0)
	      {
		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 %lld in file %s, padding with zeros"),
		     (long long) (original_num_bytes - num_bytes), filename);
	    write_nuls_to_file (num_bytes, out_des, disk_buffered_write);
	    break;
	  }
      size = (input_size < num_bytes) ? input_size : num_bytes;
      if (crc_i_flag)
	{
	  for (k = 0; k < size; ++k)
	    crc += in_buff[k] & 0xff;
	}
      disk_buffered_write (in_buff, out_des, size);
      num_bytes -= size;
      input_size -= size;
      in_buff += size;
    }
}

Project: cpio

process_copy_out (void)
{
  dynamic_string input_name = DYNAMIC_STRING_INITIALIZER;
                                /* Name of file read from stdin.  */
  struct stat file_stat;	/* Stat record for file.  */
  struct cpio_file_stat file_hdr = CPIO_FILE_STAT_INITIALIZER;
                                /* Output header information.  */
  int in_file_des;		/* Source file descriptor.  */
  int out_file_des;		/* Output file descriptor.  */
  char *orig_file_name = NULL;

  /* Initialize the copy out.  */
  file_hdr.c_magic = 070707;

  /* Check whether the output file might be a tape.  */
  out_file_des = archive_des;
  if (_isrmt (out_file_des))
    {
      output_is_special = 1;
      output_is_seekable = 0;
    }
  else
    {
      if (fstat (out_file_des, &file_stat))
	error (PAXEXIT_FAILURE, errno, _("standard output is closed"));
      output_is_special =
#ifdef S_ISBLK
	S_ISBLK (file_stat.st_mode) ||
#endif
	S_ISCHR (file_stat.st_mode);
      output_is_seekable = S_ISREG (file_stat.st_mode);
    }

  change_dir ();
  
  if (append_flag)
    {
      process_copy_in ();
      prepare_append (out_file_des);
    }

  /* Copy files with names read from stdin.  */
  while (ds_fgetstr (stdin, &input_name, name_end) != NULL)
    {
      /* Check for blank line.  */
      if (input_name.ds_string[0] == 0)
	{
	  error (0, 0, _("blank line ignored"));
	  continue;
	}

      /* Process next file.  */
      if ((*xstat) (input_name.ds_string, &file_stat) < 0)
	stat_error (input_name.ds_string);
      else
	{
	  /* Set values in output header.  */
	  stat_to_cpio (&file_hdr, &file_stat);
	  
	  if (archive_format == arf_tar || archive_format == arf_ustar)
	    {
	      if (file_hdr.c_mode & CP_IFDIR)
		{
		  /* Make sure the name ends with a slash */
		  if (!ds_endswith (&input_name, '/'))
		    ds_append (&input_name, '/');
		}
	    }
	  
	  assign_string (&orig_file_name, input_name.ds_string);
	  cpio_safer_name_suffix (input_name.ds_string, false,
				  !no_abs_paths_flag, true);
	  cpio_set_c_name (&file_hdr, input_name.ds_string);

	  /* Copy the named file to the output.  */
	  switch (file_hdr.c_mode & CP_IFMT)
	    {
	    case CP_IFREG:
	      if (archive_format == arf_tar || archive_format == arf_ustar)
		{
		  char *otherfile;
		  if ((otherfile = find_inode_file (file_hdr.c_ino,
						    file_hdr.c_dev_maj,
						    file_hdr.c_dev_min)))
		    {
		      file_hdr.c_tar_linkname = otherfile;
		      if (write_out_header (&file_hdr, out_file_des))
			continue;
		      break;
		    }
		}
	      if ( (archive_format == arf_newascii || archive_format == arf_crcascii)
		  && (file_hdr.c_nlink > 1) )
		{
		  if (last_link (&file_hdr) )
		    {
		      writeout_other_defers (&file_hdr, out_file_des);
		    }
		  else
		    {
		      add_link_defer (&file_hdr);
		      break;
		    }
		}
	      in_file_des = open (orig_file_name,
				  O_RDONLY | O_BINARY, 0);
	      if (in_file_des < 0)
		{
		  open_error (orig_file_name);
		  continue;
		}

	      if (archive_format == arf_crcascii)
		file_hdr.c_chksum = read_for_checksum (in_file_des,
						       file_hdr.c_filesize,
						       orig_file_name);

	      if (write_out_header (&file_hdr, out_file_des))
		continue;
	      copy_files_disk_to_tape (in_file_des,
				       out_file_des, file_hdr.c_filesize,
				       orig_file_name);
	      warn_if_file_changed(orig_file_name, file_hdr.c_filesize,
                                   file_hdr.c_mtime);

	      if (archive_format == arf_tar || archive_format == arf_ustar)
		add_inode (file_hdr.c_ino, orig_file_name, file_hdr.c_dev_maj,
			   file_hdr.c_dev_min);

	      tape_pad_output (out_file_des, file_hdr.c_filesize);

	      if (reset_time_flag)
                set_file_times (in_file_des,
				orig_file_name,
                                file_stat.st_atime, file_stat.st_mtime);
	      if (close (in_file_des) < 0)
		close_error (orig_file_name);
	      break;

	    case CP_IFDIR:
	      file_hdr.c_filesize = 0;
	      if (write_out_header (&file_hdr, out_file_des))
		continue;
	      break;

	    case CP_IFCHR:
	    case CP_IFBLK:
#ifdef CP_IFSOCK
	    case CP_IFSOCK:
#endif
#ifdef CP_IFIFO
	    case CP_IFIFO:
#endif
	      if (archive_format == arf_tar)
		{
		  error (0, 0, _("%s not dumped: not a regular file"),
			 orig_file_name);
		  continue;
		}
	      else if (archive_format == arf_ustar)
		{
		  char *otherfile;
		  if ((otherfile = find_inode_file (file_hdr.c_ino,
						    file_hdr.c_dev_maj,
						    file_hdr.c_dev_min)))
		    {
		      /* This file is linked to another file already in the 
		         archive, so write it out as a hard link. */
		      file_hdr.c_mode = (file_stat.st_mode & 07777);
		      file_hdr.c_mode |= CP_IFREG;
		      file_hdr.c_tar_linkname = otherfile;
		      if (write_out_header (&file_hdr, out_file_des))
			continue;
		      break;
		    }
		  add_inode (file_hdr.c_ino, orig_file_name, 
			     file_hdr.c_dev_maj, file_hdr.c_dev_min);
		}
	      file_hdr.c_filesize = 0;
	      if (write_out_header (&file_hdr, out_file_des))
		continue;
	      break;

#ifdef CP_IFLNK
	    case CP_IFLNK:
	      {
		char *link_name = (char *) xmalloc (file_stat.st_size + 1);
		int link_size;

		link_size = readlink (orig_file_name, link_name,
			              file_stat.st_size);
		if (link_size < 0)
		  {
		    readlink_warn (orig_file_name);
		    free (link_name);
		    continue;
		  }
		link_name[link_size] = 0;
		cpio_safer_name_suffix (link_name, false,
					!no_abs_paths_flag, true);
		link_size = strlen (link_name);
		file_hdr.c_filesize = link_size;
		if (archive_format == arf_tar || archive_format == arf_ustar)
		  {
		    if (link_size + 1 > 100)
		      {
			error (0, 0, _("%s: symbolic link too long"),
			       file_hdr.c_name);
		      }
		    else
		      {
			link_name[link_size] = '\0';
			file_hdr.c_tar_linkname = link_name;
			if (write_out_header (&file_hdr, out_file_des))
			  continue;
		      }
		  }
		else
		  {
		    if (write_out_header (&file_hdr, out_file_des))
		      continue;
		    tape_buffered_write (link_name, out_file_des, link_size);
		    tape_pad_output (out_file_des, link_size);
		  }
		free (link_name);
	      }
	      break;
#endif

	    default:
	      error (0, 0, _("%s: unknown file type"), orig_file_name);
	    }
	  
	  if (verbose_flag)
	    fprintf (stderr, "%s\n", orig_file_name);
	  if (dot_flag)
	    fputc ('.', stderr);
	}
    }

  free (orig_file_name);
  
  writeout_final_defers(out_file_des);
  /* The collection is complete; append the trailer.  */
  file_hdr.c_ino = 0;
  file_hdr.c_mode = 0;
  file_hdr.c_uid = 0;
  file_hdr.c_gid = 0;
  file_hdr.c_nlink = 1;		/* Must be 1 for crc format.  */
  file_hdr.c_dev_maj = 0;
  file_hdr.c_dev_min = 0;
  file_hdr.c_rdev_maj = 0;
  file_hdr.c_rdev_min = 0;
  file_hdr.c_mtime = 0;
  file_hdr.c_chksum = 0;

  file_hdr.c_filesize = 0;
  cpio_set_c_name (&file_hdr, CPIO_TRAILER_NAME);
  if (archive_format != arf_tar && archive_format != arf_ustar)
    write_out_header (&file_hdr, out_file_des);
  else
    write_nuls_to_file (1024, out_file_des, tape_buffered_write);

  /* Fill up the output block.  */
  tape_clear_rest_of_block (out_file_des);
  tape_empty_output_buffer (out_file_des);
  if (dot_flag)
    fputc ('\n', stderr);
  if (!quiet_flag)
    {
      size_t blocks = (output_bytes + io_block_size - 1) / io_block_size;
      fprintf (stderr,
	       ngettext ("%lu block\n", "%lu blocks\n",
			 (unsigned long) blocks), (unsigned long) blocks);
    }
  cpio_file_stat_free (&file_hdr);
  ds_free (&input_name);
}

Project: cpio

tape_buffered_read (char *in_buf, int in_des, off_t num_bytes)
{
  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)
    {
      if (input_size == 0)
	tape_fill_input_buffer (in_des, io_block_size);
      if (bytes_left < input_size)
	space_left = bytes_left;
      else
	space_left = input_size;
      memcpy (in_buf, in_buff, (unsigned) space_left);
      in_buff += space_left;
      in_buf += space_left;
      input_size -= space_left;
      bytes_left -= space_left;
    }
}

Project: cpio

umasked_symlink (char *name1, char *name2, int mode)
{
  int	old_umask;
  int	rc;
  mode = ~(mode & 0777) & 0777;
  old_umask = umask (mode);
  rc = symlink (name1, name2);
  umask (old_umask);
  return rc;
}

Project: cpio

long_format (struct cpio_file_stat *file_hdr, char const *link_name)
{
  char mbuf[11];
  char tbuf[40];
  time_t when;

  mode_string (file_hdr->c_mode, mbuf);
  mbuf[10] = '\0';

  /* Get time values ready to print.  */
  when = file_hdr->c_mtime;
  strcpy (tbuf, ctime (&when));
  if (current_time - when > 6L * 30L * 24L * 60L * 60L
      || current_time - when < 0L)
    {
      /* The file is older than 6 months, or in the future.
	 Show the year instead of the time of day.  */
      strcpy (tbuf + 11, tbuf + 19);
    }
  tbuf[16] = '\0';

  printf ("%s %3lu ", mbuf, (unsigned long) 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 ",
	    (unsigned long) file_hdr->c_rdev_maj,
	    (unsigned long) file_hdr->c_rdev_min);
  else
    printf ("%8"PRIuMAX" ", (uintmax_t) file_hdr->c_filesize);

  printf ("%s ", tbuf + 4);

  printf ("%s", quotearg (file_hdr->c_name));
  if (link_name)
    {
      printf (" -> ");
      printf ("%s", quotearg (link_name));
    }
  putc ('\n', stdout);
}

Project: cpio

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_filesize = (unsigned long) short_hdr->c_filesizes[0] << 16
                      | short_hdr->c_filesizes[1];
  read_name_from_file (file_hdr, in_des, short_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;
    }
}

Project: cpio

cpio_set_c_name (struct cpio_file_stat *file_hdr, char *name)
{
  size_t len = strlen (name) + 1;

  cpio_realloc_c_name (file_hdr, len);
  file_hdr->c_namesize = len;
  memmove (file_hdr->c_name, name, len);
}

Project: cpio

delay_set_stat (char const *file_name, struct stat *st,
		mode_t invert_permissions)
{
  struct cpio_file_stat fs;

  stat_to_cpio (&fs, st);
  fs.c_name = (char*) file_name;
  delay_cpio_set_stat (&fs, invert_permissions);
}

Project: cpio

open_archive (char *file)
{
  int fd;
  void (*copy_in) ();		/* Workaround for pcc bug.  */

  copy_in = process_copy_in;

  if (copy_function == copy_in)
    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, MODE_RW,
			rsh_command_option);
      else
	fd = rmtopen (file, O_RDWR | O_BINARY, MODE_RW, rsh_command_option);
    }

  return fd;
}

Project: cpio

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_filesize = FROM_OCTAL (ascii_header.c_filesize);
  read_name_from_file (file_hdr, in_des, FROM_OCTAL (ascii_header.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;
    }
}

Project: cpio

ds_endswith (dynamic_string *s, int c)
{
  return (s->ds_idx > 0 && s->ds_string[s->ds_idx - 1] == c);
}

Project: cpio

field_width_error (const char *filename, const char *fieldname,
		   uintmax_t value, size_t width, bool nul)
{
  char valbuf[UINTMAX_STRSIZE_BOUND + 1];
  char maxbuf[UINTMAX_STRSIZE_BOUND + 1];
  error (0, 0, _("%s: value %s %s out of allowed range 0..%s"),
	 filename, fieldname,
	 STRINGIFY_BIGINT (value, valbuf),
	 STRINGIFY_BIGINT (MAX_VAL_WITH_DIGITS (width - nul, LG_8),
			   maxbuf));
}

Project: cpio

ds_fgetname (FILE *f, dynamic_string *s)
{
  return ds_fgetstr (f, s, '\0');
}

Project: cpio

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;
    }
}

Project: cpio

write_out_old_ascii_header (dev_t dev, dev_t rdev,
			    struct cpio_file_stat *file_hdr, int out_des)
{
  char ascii_header[76];
  char *p = ascii_header;
  
  to_ascii (p, file_hdr->c_magic, 6, LG_8, false);
  p += 6;
  to_ascii_or_warn (p, dev, 6, LG_8, file_hdr->c_name, _("device number"));
  p += 6;
  to_ascii_or_warn (p, file_hdr->c_ino, 6, LG_8, file_hdr->c_name,
		    _("inode number"));
  p += 6;
  to_ascii_or_warn (p, file_hdr->c_mode, 6, LG_8, file_hdr->c_name,
		    _("file mode"));
  p += 6;
  to_ascii_or_warn (p, file_hdr->c_uid, 6, LG_8, file_hdr->c_name, _("uid"));
  p += 6;
  to_ascii_or_warn (p, file_hdr->c_gid, 6, LG_8, file_hdr->c_name, _("gid"));
  p += 6;
  to_ascii_or_warn (p, file_hdr->c_nlink, 6, LG_8, file_hdr->c_name,
		    _("number of links"));
  p += 6;
  to_ascii_or_warn (p, rdev, 6, LG_8, file_hdr->c_name, _("rdev"));
  p += 6;
  to_ascii_or_warn (p, file_hdr->c_mtime, 11, LG_8, file_hdr->c_name,
		    _("modification time"));
  p += 11;
  if (to_ascii_or_error (p, file_hdr->c_namesize, 6, LG_8, file_hdr->c_name,
			 _("name size")))
    return 1;
  p += 6;
  if (to_ascii_or_error (p, file_hdr->c_filesize, 11, LG_8, file_hdr->c_name,
			 _("file size")))
    return 1;

  tape_buffered_write (ascii_header, out_des, sizeof ascii_header);

  /* Write file name to output.  */
  tape_buffered_write (file_hdr->c_name, out_des, file_hdr->c_namesize);
  return 0;
}

Project: cpio

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 (fdutimens (fd, name, ts) < 0 && errno != EROFS)
    utime_error (name);
}

Project: cpio

tape_clear_rest_of_block (int out_file_des)
{
  write_nuls_to_file (io_block_size - output_size, out_file_des, 
                      tape_buffered_write);
}

Project: cpio

process_copy_in (void)
{
  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 = CPIO_FILE_STAT_INITIALIZER;
                                /* Output header information.  */
  int in_file_des;		/* Input file descriptor.  */
  char skip_file;		/* Flag for use with patterns.  */
  int i;			/* Loop index variable.  */

  newdir_umask = umask (0);     /* Reset umask to preserve modes of
				   created files  */
  
  /* Initialize the copy in.  */
  if (pattern_file_name)
    {
      read_pattern_file ();
    }
  
  if (rename_batch_file)
    {
      rename_in = fopen (rename_batch_file, "r");
      if (rename_in == NULL)
	{
	  error (PAXEXIT_FAILURE, 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 (PAXEXIT_FAILURE, errno, TTY_NAME);
	}
      tty_out = fopen (TTY_NAME, "w");
      if (tty_out == NULL)
	{
	  error (PAXEXIT_FAILURE, errno, TTY_NAME);
	}
    }

  /* Get date and time if needed for processing the table option.  */
  if (table_flag && verbose_flag)
    {
      time (&current_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 (PAXEXIT_FAILURE, 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;

  change_dir ();
  
  /* While there is more input in the collection, process the input.  */
  while (1)
    {
      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 = %ld, mode = 0%o, uid = %d, gid = %d\n",
		h->c_magic, (long)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
      if (file_hdr.c_namesize == 0)
	skip_file = true;
      else
	{
	  /* Is this the header for the TRAILER file?  */
	  if (strcmp (CPIO_TRAILER_NAME, file_hdr.c_name) == 0)
	    break;

	  cpio_safer_name_suffix (file_hdr.c_name, false, !no_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%x, should be 0x%x)"),
		       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);

  apply_delayed_set_stat ();

  cpio_file_stat_free (&file_hdr);
  
  if (append_flag)
    return;

  if (archive_format == arf_newascii || archive_format == arf_crcascii)
    {
      create_final_defers ();
    }
  if (!quiet_flag)
    {
      size_t blocks;
      blocks = (input_bytes + io_block_size - 1) / io_block_size;
      fprintf (stderr,
	       ngettext ("%lu block\n", "%lu blocks\n",
			 (unsigned long) blocks),
	       (unsigned long) blocks);
    }
}

Project: cpio

cpio_realloc_c_name (struct cpio_file_stat *file_hdr, size_t len)
{
  while (file_hdr->c_name_buflen < len)
    file_hdr->c_name = x2realloc (file_hdr->c_name, &file_hdr->c_name_buflen);
}

Project: cpio

stat_to_cpio (struct cpio_file_stat *hdr, struct stat *st)
{
  get_inode_and_dev (hdr, st);

  /* 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_nlink = st->st_nlink;
  hdr->c_uid = CPIO_UID (st->st_uid);
  hdr->c_gid = CPIO_GID (st->st_gid);
  if (S_ISBLK (st->st_mode) || S_ISCHR (st->st_mode))
    {
      hdr->c_rdev_maj = major (st->st_rdev);
      hdr->c_rdev_min = minor (st->st_rdev);
    }
  else
    {
      hdr->c_rdev_maj = 0;
      hdr->c_rdev_min = 0;
    }
  hdr->c_mtime = st->st_mtime;
  hdr->c_filesize = st->st_size;
  hdr->c_chksum = 0;
  hdr->c_tar_linkname = NULL;
}

Project: cpio

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);
}

Project: cpio

add_link_defer (struct cpio_file_stat *file_hdr)
{
  struct deferment *d;
  d = create_deferment (file_hdr);
  d->next = deferouts;
  deferouts = d;
}

Project: cpio

copy_files_disk_to_tape (int in_des, int out_des, off_t num_bytes,
			 char *filename)
{
  off_t size;
  off_t k;
  int rc;
  off_t original_num_bytes;

  original_num_bytes = num_bytes;

  while (num_bytes > 0)
    {
      if (input_size == 0)
	if ((rc = disk_fill_input_buffer (in_des,
					  num_bytes < DISK_IO_BLOCK_SIZE ?
					  num_bytes : DISK_IO_BLOCK_SIZE)))
	  {
	    if (rc > 0)
	      {
		  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 %lld in file %s, padding with zeros"),
		     (long long) (original_num_bytes - num_bytes), filename);
	    write_nuls_to_file (num_bytes, out_des, tape_buffered_write);
	    break;
	  }
      size = (input_size < num_bytes) ? input_size : num_bytes;
      if (crc_i_flag)
	{
	  for (k = 0; k < size; ++k)
	    crc += in_buff[k] & 0xff;
	}
      tape_buffered_write (in_buff, out_des, size);
      num_bytes -= size;
      input_size -= size;
      in_buff += size;
    }
}

Project: cpio

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 (archive_format != arf_tar && archive_format != arf_ustar)
    {
      if (to_stdout_option)
        {
          tape_toss_input (in_file_des, file_hdr->c_filesize);
          tape_skip_padding (in_file_des, file_hdr->c_filesize);
          return;
        }
      link_name = get_link_name (file_hdr, in_file_des);
      if (!link_name)
	return;
    }
  else
    {
      if (to_stdout_option)
        return;
      link_name = xstrdup (file_hdr->c_tar_linkname);
    }

  cpio_safer_name_suffix (link_name, true, !no_abs_paths_flag, false);
  
  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);
}

Project: cpio

disk_buffered_write (char *in_buf, int out_des, off_t num_bytes)
{
  off_t bytes_left = num_bytes;	/* Bytes needing to be copied.  */
  off_t space_left;	/* Room left in output buffer.  */

  while (bytes_left > 0)
    {
      space_left = DISK_IO_BLOCK_SIZE - output_size;
      if (space_left == 0)
	disk_empty_output_buffer (out_des, false);
      else
	{
	  if (bytes_left < space_left)
	    space_left = bytes_left;
	  memcpy (out_buff, in_buf, (unsigned) space_left);
	  out_buff += space_left;
	  output_size += space_left;
	  in_buf += space_left;
	  bytes_left -= space_left;
	}
    }
}

Project: cpio

cpio_create_dir (struct cpio_file_stat *file_hdr, int existing_dir)
{
  int res;			/* Result of various function calls.  */
  int setstat_delayed = 0;
  
  if (to_stdout_option)
    return 0;
  
  /* 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 0;
    }

  if (!existing_dir)
    res = cpio_mkdir (file_hdr, &setstat_delayed);
  else
    res = 0;
  if (res < 0 && create_dir_flag)
    {
      create_all_directories (file_hdr->c_name);
      res = cpio_mkdir (file_hdr, &setstat_delayed);
    }
  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 -1;
	}
      if (lstat (file_hdr->c_name, &file_stat))
	{
	  stat_error (file_hdr->c_name);
	  return -1;
	}
      if (!(S_ISDIR (file_stat.st_mode)))
	{
	  error (0, 0, _("%s is not a directory"),
		 quotearg_colon (file_hdr->c_name));
	  return -1;
	}
    }

  if (!setstat_delayed && repair_delayed_set_stat (file_hdr))
    set_perms (-1, file_hdr);
  return 0;
}

Project: cpio

create_all_directories (char const *name)
{
  char *dir;

  dir = dir_name (name);
  
  if (dir == NULL)
    error (PAXEXIT_FAILURE, 0, _("virtual memory exhausted"));

  if (dir[0] != '.' || dir[1] != '\0')
    {
      const char *fmt;
      if (warn_option & CPIO_WARN_INTERDIR)
	fmt = _("Creating intermediate directory `%s'");
      else
	fmt = NULL;
      make_path (dir, -1, -1, fmt);
    }

  free (dir);
}