Example #1
0
/* This is like name_match, except that
    1. It returns a pointer to the name it matched, and doesn't set FOUND
    in structure. The caller will have to do that if it wants to.
    2. If the namelist is empty, it returns null, unlike name_match, which
    returns TRUE. */
struct name *
name_scan (const char *file_name)
{
  size_t length = strlen (file_name);

  while (1)
    {
      struct name *cursor = namelist_match (file_name, length);
      if (cursor)
	return cursor;

      /* Filename from archive not found in namelist.  If we have the whole
	 namelist here, just return 0.  Otherwise, read the next name in and
	 compare it.  If this was the last name, namelist->found_count will
	 remain on.  If not, we loop to compare the newly read name.  */

      if (same_order_option && namelist && namelist->found_count)
	{
	  name_gather ();	/* read one more */
	  if (namelist->found_count)
	    return 0;
	}
      else
	return 0;
    }
}
Example #2
0
/* Return true if and only if name FILE_NAME (from an archive) matches any
   name from the namelist.  */
bool
name_match (const char *file_name)
{
  size_t length = strlen (file_name);

  while (1)
    {
      struct name *cursor = namelist;

      if (!cursor)
	return true;
      
      if (cursor->name[0] == 0)
	{
	  chdir_do (cursor->change_dir);
	  namelist = NULL;
	  nametail = NULL;
	  return true;
	}

      cursor = namelist_match (file_name, length);
      if (cursor)
	{
	  if (!(ISSLASH (file_name[cursor->length]) && recursion_option)
	      || cursor->found_count == 0)
	    cursor->found_count++; /* remember it matched */
	  if (starting_file_option)
	    {
	      free (namelist);
	      namelist = NULL;
	      nametail = NULL;
	    }
	  chdir_do (cursor->change_dir);

	  /* We got a match.  */
	  return ISFOUND (cursor);
	}

      /* Filename from archive not found in namelist.  If we have the whole
	 namelist here, just return 0.  Otherwise, read the next name in and
	 compare it.  If this was the last name, namelist->found_count will
	 remain on.  If not, we loop to compare the newly read name.  */

      if (same_order_option && namelist->found_count)
	{
	  name_gather ();	/* read one more */
	  if (namelist->found_count)
	    return false;
	}
      else
	return false;
    }
}
void
delete_archive_members (void)
{
  enum read_header logical_status = HEADER_STILL_UNREAD;
  enum read_header previous_status = HEADER_STILL_UNREAD;

  /* FIXME: Should clean the routine before cleaning these variables :-( */
  struct name *name;
  off_t blocks_to_skip = 0;
  off_t blocks_to_keep = 0;
  int kept_blocks_in_record;

  name_gather ();
  open_archive (ACCESS_UPDATE);
  acting_as_filter = strcmp (archive_name_array[0], "-") == 0;

  do
    {
      enum read_header status = read_header (true);

      switch (status)
	{
	case HEADER_STILL_UNREAD:
	  abort ();

	case HEADER_SUCCESS:
	  if ((name = name_scan (current_stat_info.file_name)) == NULL)
	    {
	      skip_member ();
	      break;
	    }
	  name->found_count++;
	  if (!ISFOUND(name))
	    {
	      skip_member ();
	      break;
	    }

	  /* Fall through.  */
	case HEADER_SUCCESS_EXTENDED:
	  logical_status = status;
	  break;

	case HEADER_ZERO_BLOCK:
	  if (ignore_zeros_option)
	    {
	      set_next_block_after (current_header);
	      break;
	    }
	  /* Fall through.  */
	case HEADER_END_OF_FILE:
	  logical_status = HEADER_END_OF_FILE;
	  break;

	case HEADER_FAILURE:
	  set_next_block_after (current_header);
	  switch (previous_status)
	    {
	    case HEADER_STILL_UNREAD:
	      WARN ((0, 0, _("This does not look like a tar archive")));
	      /* Fall through.  */

	    case HEADER_SUCCESS:
	    case HEADER_SUCCESS_EXTENDED:
	    case HEADER_ZERO_BLOCK:
	      ERROR ((0, 0, _("Skipping to next header")));
	      /* Fall through.  */

	    case HEADER_FAILURE:
	      break;

	    case HEADER_END_OF_FILE:
	      abort ();
	    }
	  break;
	}

      previous_status = status;
    }
  while (logical_status == HEADER_STILL_UNREAD);

  records_skipped = records_read - 1;
  new_record = xmalloc (record_size);

  if (logical_status == HEADER_SUCCESS
      || logical_status == HEADER_SUCCESS_EXTENDED)
    {
      write_archive_to_stdout = false;

      /* Save away blocks before this one in this record.  */

      new_blocks = current_block - record_start;
      if (new_blocks)
	memcpy (new_record, record_start, new_blocks * BLOCKSIZE);

      if (logical_status == HEADER_SUCCESS)
	{
	  /* FIXME: Pheew!  This is crufty code!  */
	  logical_status = HEADER_STILL_UNREAD;
	  goto flush_file;
	}

      /* FIXME: Solaris 2.4 Sun cc (the ANSI one, not the old K&R) says:
	 "delete.c", line 223: warning: loop not entered at top
	 Reported by Bruno Haible.  */
      while (1)
	{
	  enum read_header status;

	  /* Fill in a record.  */

	  if (current_block == record_end)
	    flush_archive ();
	  status = read_header (false);

	  xheader_decode (&current_stat_info);

	  if (status == HEADER_ZERO_BLOCK && ignore_zeros_option)
	    {
	      set_next_block_after (current_header);
	      continue;
	    }
	  if (status == HEADER_END_OF_FILE || status == HEADER_ZERO_BLOCK)
	    {
	      logical_status = HEADER_END_OF_FILE;
	      break;
	    }

	  if (status == HEADER_FAILURE)
	    {
	      ERROR ((0, 0, _("Deleting non-header from archive")));
	      set_next_block_after (current_header);
	      continue;
	    }

	  /* Found another header.  */

	  if ((name = name_scan (current_stat_info.file_name)) != NULL)
	    {
	      name->found_count++;
	      if (ISFOUND(name))
		{
		flush_file:
		  set_next_block_after (current_header);
		  blocks_to_skip = (current_stat_info.stat.st_size
				    + BLOCKSIZE - 1) / BLOCKSIZE;
		  
		  while (record_end - current_block <= blocks_to_skip)
		    {
		      blocks_to_skip -= (record_end - current_block);
		      flush_archive ();
		    }
		  current_block += blocks_to_skip;
		  blocks_to_skip = 0;
		  continue;
		}
	    }
	  /* Copy header.  */

	  if (extended_header.size)
	    {
	      write_recent_bytes (extended_header.buffer,
				  extended_header.size);
	    }
	  else
	    {
	      write_recent_blocks (recent_long_name, recent_long_name_blocks);
	      write_recent_blocks (recent_long_link, recent_long_link_blocks);
	    }
	  new_record[new_blocks] = *current_header;
	  new_blocks++;
	  blocks_to_keep
	    = (current_stat_info.stat.st_size + BLOCKSIZE - 1) / BLOCKSIZE;
	  set_next_block_after (current_header);
	  if (new_blocks == blocking_factor)
	    write_record (1);

	  /* Copy data.  */

	  kept_blocks_in_record = record_end - current_block;
	  if (kept_blocks_in_record > blocks_to_keep)
	    kept_blocks_in_record = blocks_to_keep;

	  while (blocks_to_keep)
	    {
	      int count;

	      if (current_block == record_end)
		{
		  flush_read ();
		  current_block = record_start;
		  kept_blocks_in_record = blocking_factor;
		  if (kept_blocks_in_record > blocks_to_keep)
		    kept_blocks_in_record = blocks_to_keep;
		}
	      count = kept_blocks_in_record;
	      if (blocking_factor - new_blocks < count)
		count = blocking_factor - new_blocks;

	      if (! count)
		abort ();

	      memcpy (new_record + new_blocks, current_block, count * BLOCKSIZE);
	      new_blocks += count;
	      current_block += count;
	      blocks_to_keep -= count;
	      kept_blocks_in_record -= count;

	      if (new_blocks == blocking_factor)
		write_record (1);
	    }
	}

      if (logical_status == HEADER_END_OF_FILE)
	{
	  /* Write the end of tape.  FIXME: we can't use write_eot here,
	     as it gets confused when the input is at end of file.  */

	  int total_zero_blocks = 0;

	  do
	    {
	      int zero_blocks = blocking_factor - new_blocks;
	      memset (new_record + new_blocks, 0, BLOCKSIZE * zero_blocks);
	      total_zero_blocks += zero_blocks;
	      write_record (total_zero_blocks < 2);
	    }
	  while (total_zero_blocks < 2);
	}

      if (! acting_as_filter && ! _isrmt (archive))
	{
	  if (sys_truncate (archive))
	    truncate_warn (archive_name_array[0]);
	}
    }
  free (new_record);

  close_archive ();
  names_notfound ();
}
Example #4
0
void
delete_archive_members (void)
{
  enum read_header logical_status = HEADER_STILL_UNREAD;
  enum read_header previous_status = HEADER_STILL_UNREAD;

  /* FIXME: Should clean the routine before cleaning these variables :-( */
  struct name *name;
  int blocks_to_skip = 0;
  int blocks_to_keep = 0;
  int kept_blocks_in_record;

  name_gather ();
  open_archive (ACCESS_UPDATE);

  while (logical_status == HEADER_STILL_UNREAD)
    {
      enum read_header status = read_header ();

      switch (status)
	{
	case HEADER_STILL_UNREAD:
	  abort ();

	case HEADER_SUCCESS:
	  if (name = name_scan (current_file_name), !name)
	    {
	      set_next_block_after (current_header);
	      if (current_header->oldgnu_header.isextended)
		skip_extended_headers ();
	      skip_file ((long) (current_stat.st_size));
	      break;
	    }
	  name->found = 1;
	  logical_status = HEADER_SUCCESS;
	  break;

	case HEADER_ZERO_BLOCK:
	case HEADER_END_OF_FILE:
	  logical_status = HEADER_END_OF_FILE;
	  break;

	case HEADER_FAILURE:
	  set_next_block_after (current_header);
	  switch (previous_status)
	    {
	    case HEADER_STILL_UNREAD:
	      WARN ((0, 0, _("This does not look like a tar archive")));
	      /* Fall through.  */

	    case HEADER_SUCCESS:
	    case HEADER_ZERO_BLOCK:
	      ERROR ((0, 0, _("Skipping to next header")));
	      /* Fall through.  */

	    case HEADER_FAILURE:
	      break;

	    case HEADER_END_OF_FILE:
	      abort ();
	    }
	  break;
	}

      previous_status = status;
    }

  if (logical_status != HEADER_SUCCESS)
    {
      write_eot ();
      close_archive ();
      names_notfound ();
      return;
    }

  write_archive_to_stdout = 0;
  new_record = (union block *) xmalloc ((size_t) record_size);

  /* Save away blocks before this one in this record.  */

  new_blocks = current_block - record_start;
  blocks_needed = blocking_factor - new_blocks;
  if (new_blocks)
    memcpy ((void *) new_record, (void *) record_start,
	   (size_t) (new_blocks * BLOCKSIZE));

#if 0
  /* FIXME: Old code, before the goto was inserted.  To be redesigned.  */
  set_next_block_after (current_header);
  if (current_header->oldgnu_header.isextended)
    skip_extended_headers ();
  skip_file ((long) (current_stat.st_size));
#endif
  logical_status = HEADER_STILL_UNREAD;
  goto flush_file;

  /* FIXME: Solaris 2.4 Sun cc (the ANSI one, not the old K&R) says:
       "delete.c", line 223: warning: loop not entered at top
     Reported by Bruno Haible.  */
  while (1)
    {
      enum read_header status;

      /* Fill in a record.  */

      if (current_block == record_end)
	{
	  flush_archive ();
	  records_read++;
	}
      status = read_header ();

      if (status == HEADER_ZERO_BLOCK && ignore_zeros_option)
	{
	  set_next_block_after (current_header);
	  continue;
	}
      if (status == HEADER_END_OF_FILE || status == HEADER_ZERO_BLOCK)
	{
	  logical_status = HEADER_END_OF_FILE;
	  memset (new_record[new_blocks].buffer, 0,
		 (size_t) (BLOCKSIZE * blocks_needed));
	  new_blocks += blocks_needed;
	  blocks_needed = 0;
	  write_record (0);
	  break;
	}

      if (status == HEADER_FAILURE)
	{
	  ERROR ((0, 0, _("Deleting non-header from archive")));
	  set_next_block_after (current_header);
	  continue;
	}

      /* Found another header.  */

      if (name = name_scan (current_file_name), name)
	{
	  name->found = 1;
	flush_file:
	  set_next_block_after (current_header);
	  blocks_to_skip = (current_stat.st_size + BLOCKSIZE - 1) / BLOCKSIZE;

	  while (record_end - current_block <= blocks_to_skip)
	    {
	      blocks_to_skip -= (record_end - current_block);
	      flush_archive ();
	      records_read++;
	    }
	  current_block += blocks_to_skip;
	  blocks_to_skip = 0;
	  continue;
	}

      /* Copy header.  */

      new_record[new_blocks] = *current_header;
      new_blocks++;
      blocks_needed--;
      blocks_to_keep
	= (current_stat.st_size + BLOCKSIZE - 1) / BLOCKSIZE;
      set_next_block_after (current_header);
      if (blocks_needed == 0)
	write_record (1);

      /* Copy data.  */

      kept_blocks_in_record = record_end - current_block;
      if (kept_blocks_in_record > blocks_to_keep)
	kept_blocks_in_record = blocks_to_keep;

      while (blocks_to_keep)
	{
	  int count;

	  if (current_block == record_end)
	    {
	      flush_read ();
	      records_read++;
	      current_block = record_start;
	      kept_blocks_in_record = blocking_factor;
	      if (kept_blocks_in_record > blocks_to_keep)
		kept_blocks_in_record = blocks_to_keep;
	    }
	  count = kept_blocks_in_record;
	  if (count > blocks_needed)
	    count = blocks_needed;

	  memcpy ((void *) (new_record + new_blocks),
		  (void *) current_block,
		  (size_t) (count * BLOCKSIZE));
	  new_blocks += count;
	  blocks_needed -= count;
	  current_block += count;
	  blocks_to_keep -= count;
	  kept_blocks_in_record -= count;

	  if (blocks_needed == 0)
	    write_record (1);
	}
    }

  write_eot ();
  close_archive ();
  names_notfound ();
}
Example #5
0
void
collect_and_sort_names (void)
{
  struct name *name;
  struct name *next_name;
  int counter;
  struct stat stat_info;

  name_gather ();

  if (listed_incremental_option)
    read_directory_file ();

  if (!name_list_head)
    add_name (".");

  for (name = name_list_head; name; name = next_name)
    {
      next_name = name->next;
      if (name->match_found || name->dir_contents)
	continue;
      if (name->is_wildcard)	/* FIXME: just skip wildcards for now */
	continue;
      if (name->change_dir)
	if (chdir (name->change_dir) < 0)
	  {
	    ERROR ((0, errno, _("Cannot chdir to %s"), name->change_dir));
	    continue;
	  }

      if (
#ifdef AIX
	  statx (name->name, &stat_info, STATSIZE, STX_HIDDEN | STX_LINK)
#else
	  lstat (name->name, &stat_info) < 0
#endif
	  )
	{
	  ERROR ((0, errno, _("Cannot stat %s"), name->name));
	  continue;
	}
      if (S_ISDIR (stat_info.st_mode))
	{
	  name->match_found = true;
	  add_hierarchy_to_namelist (name->name, stat_info.st_dev);
	}
    }

  counter = 0;
  for (name = name_list_head; name; name = name->next)
    counter++;
  name_list_head = (struct name *)
    merge_sort ((voidstar) name_list_head, counter,
		(char *) (&(name_list_head->next)) - (char *) name_list_head,
		compare_names);

  for (name = name_list_head; name; name = name->next)
    name->match_found = false;

  if (listed_incremental_option)
    write_dir_file ();
}
Example #6
0
void
read_and (void (*do_something) ())
{
  enum read_header status = HEADER_STILL_UNREAD;
  enum read_header prev_status;
  char save_typeflag;

  name_gather ();
  open_archive (ACCESS_READ);

  while (1)
    {
      prev_status = status;
      status = read_header ();
      switch (status)
	{
	case HEADER_STILL_UNREAD:
	  abort ();

	case HEADER_SUCCESS:

	  /* Valid header.  We should decode next field (mode) first.
	     Ensure incoming names are null terminated.  */

	  /* FIXME: This is a quick kludge before 1.12 goes out.  */
	  current_stat.st_mtime
	    = from_oct (1 + 12, current_header->header.mtime);

	  if (!name_match (current_file_name)
	      || current_stat.st_mtime < newer_mtime_option
	      || (exclude_option && check_exclude (current_file_name)))
	    {
	      int isextended = 0;

	      if (current_header->header.typeflag == GNUTYPE_VOLHDR
		  || current_header->header.typeflag == GNUTYPE_MULTIVOL
		  || current_header->header.typeflag == GNUTYPE_NAMES)
		{
		  (*do_something) ();
		  continue;
		}
	      if (show_omitted_dirs_option
		  && current_header->header.typeflag == DIRTYPE)
		WARN ((0, 0, _("Omitting %s"), current_file_name));

	      /* Skip past it in the archive.  */

	      if (current_header->oldgnu_header.isextended)
		isextended = 1;
	      save_typeflag = current_header->header.typeflag;
	      set_next_block_after (current_header);
	      if (isextended)
		{
#if 0
		  union block *exhdr;

		  while (1)
		    {
		      exhdr = find_next_block ();
		      if (!exhdr->sparse_header.isextended)
			{
			  set_next_block_after (exhdr);
			  break;
			}
		    }
		  set_next_block_after (exhdr);
#endif
		  skip_extended_headers ();
		}

	      /* Skip to the next header on the archive.  */

	      if (save_typeflag != DIRTYPE)
		skip_file ((long long) current_stat.st_size);
	      continue;
	    }

	  (*do_something) ();
	  continue;

	case HEADER_ZERO_BLOCK:
	  if (block_number_option)
	    fprintf (stdlis, _("block %10ld: ** Block of NULs **\n"),
		     current_block_ordinal ());

	  set_next_block_after (current_header);
	  status = prev_status;
	  if (ignore_zeros_option)
	    continue;
	  break;

	case HEADER_END_OF_FILE:
	  if (block_number_option)
	    fprintf (stdlis, _("block %10ld: ** End of File **\n"),
		     current_block_ordinal ());
	  break;

	case HEADER_FAILURE:
	  /* If the previous header was good, tell them that we are
	     skipping bad ones.  */
	  set_next_block_after (current_header);
	  switch (prev_status)
	    {
	    case HEADER_STILL_UNREAD:
	      WARN ((0, 0, _("Could not extract file(s); file might not be a tar archive")));
	      /* Fall through.  */

	    case HEADER_ZERO_BLOCK:
	    case HEADER_SUCCESS:
	      WARN ((0, 0, _("Skipping to next file header")));
	      break;

	    case HEADER_END_OF_FILE:
	    case HEADER_FAILURE:
	      /* We are in the middle of a cascade of errors.  */
	      break;
	    }
	  continue;
	}
      break;
    }

  apply_delayed_set_stat ();
  close_archive ();
  names_notfound ();		/* print names not found */
}
Example #7
0
void
collect_and_sort_names (void)
{
  struct name *name;
  struct name *next_name, *prev_name;
  int num_names;
  struct stat statbuf;
  Hash_table *nametab;
  
  name_gather ();

  if (!namelist)
    addname (".", 0, false, NULL);

  if (listed_incremental_option)
    {
      switch (chdir_count ())
	{
	case 0:
	  break;

	case 1:
	  if (namelist->change_dir == 0)
	    USAGE_ERROR ((0, 0,
			  _("Using -C option inside file list is not "
			    "allowed with --listed-incremental")));
	  break;

	default:
	  USAGE_ERROR ((0, 0,
			_("Only one -C option is allowed with "
			  "--listed-incremental")));
	}

      read_directory_file ();
    }
  
  num_names = 0;
  for (name = namelist; name; name = name->next, num_names++)
    {
      if (name->found_count || name->directory)
	continue;
      if (name->matching_flags & EXCLUDE_WILDCARDS)
	/* NOTE: EXCLUDE_ANCHORED is not relevant here */
	/* FIXME: just skip regexps for now */
	continue;
      chdir_do (name->change_dir);

      if (name->name[0] == 0)
	continue;

      if (deref_stat (dereference_option, name->name, &statbuf) != 0)
	{
	  stat_diag (name->name);
	  continue;
	}
      if (S_ISDIR (statbuf.st_mode))
	{
	  name->found_count++;
	  add_hierarchy_to_namelist (name, statbuf.st_dev, true);
	}
    }

  namelist = merge_sort (namelist, num_names, compare_names);

  num_names = 0;
  nametab = hash_initialize (0, 0,
			     name_hash,
			     name_compare, NULL);
  for (name = namelist; name; name = next_name)
    {
      next_name = name->next;
      name->caname = normalize_filename (name->name);
      if (prev_name)
	{
	  struct name *p = hash_lookup (nametab, name);
	  if (p)
	    {
	      /* Keep the one listed in the command line */
	      if (!name->parent)
		{
		  if (p->child)
		    rebase_child_list (p->child, name);
		  /* FIXME: remove_directory (p->caname); ? */
		  remname (p);
		  free_name (p);
		  num_names--;
		}
	      else
		{
		  if (name->child)
		    rebase_child_list (name->child, p);
		  /* FIXME: remove_directory (name->caname); ? */
		  remname (name);
		  free_name (name);
		  continue;
		}
	    }
	}
      name->found_count = 0;
      if (!hash_insert (nametab, name))
	xalloc_die ();
      prev_name = name;
      num_names++;
    }
  nametail = prev_name;
  hash_free (nametab);

  namelist = merge_sort (namelist, num_names, compare_names_found);

  if (listed_incremental_option)
    {
      for (name = namelist; name && name->name[0] == 0; name++)
	;
      if (name)
	append_incremental_renames (name->directory);
    }
}
Example #8
0
/* Implement the 'r' (add files to end of archive), and 'u' (add files
   to end of archive if they aren't there, or are more up to date than
   the version in the archive) commands.  */
void
update_archive (void)
{
  enum read_header previous_status = HEADER_STILL_UNREAD;
  bool found_end = false;

  name_gather ();
  open_archive (ACCESS_UPDATE);
  xheader_write_global ();

  while (!found_end)
    {
      enum read_header status = read_header (false);

      switch (status)
	{
	case HEADER_STILL_UNREAD:
	case HEADER_SUCCESS_EXTENDED:
	  abort ();

	case HEADER_SUCCESS:
	  {
	    struct name *name;

	    decode_header (current_header, &current_stat_info,
			   &current_format, 0);
	    archive_format = current_format;
	    
	    if (subcommand_option == UPDATE_SUBCOMMAND
		&& (name = name_scan (current_stat_info.file_name)) != NULL)
	      {
		struct stat s;

		chdir_do (name->change_dir);
		if (deref_stat (dereference_option,
				current_stat_info.file_name, &s) == 0
		    && s.st_mtime <= current_stat_info.stat.st_mtime)
		  add_avoided_name (current_stat_info.file_name);
	      }

	    skip_member ();
	    break;
	  }

	case HEADER_ZERO_BLOCK:
	  current_block = current_header;
	  found_end = true;
	  break;

	case HEADER_END_OF_FILE:
	  found_end = true;
	  break;

	case HEADER_FAILURE:
	  set_next_block_after (current_header);
	  switch (previous_status)
	    {
	    case HEADER_STILL_UNREAD:
	      WARN ((0, 0, _("This does not look like a tar archive")));
	      /* Fall through.  */

	    case HEADER_SUCCESS:
	    case HEADER_ZERO_BLOCK:
	      ERROR ((0, 0, _("Skipping to next header")));
	      /* Fall through.  */

	    case HEADER_FAILURE:
	      break;

	    case HEADER_END_OF_FILE:
	    case HEADER_SUCCESS_EXTENDED:
	      abort ();
	    }
	  break;
	}

      tar_stat_destroy (&current_stat_info);
      xheader_destroy (&extended_header);
      previous_status = status;
    }

  reset_eof ();
  time_to_start_writing = true;
  output_start = current_block->buffer;

  {
    char *file_name;

    while ((file_name = name_from_list ()) != NULL)
      {
	if (excluded_name (file_name))
	  continue;
	if (interactive_option && !confirm ("add", file_name))
	  continue;
	if (subcommand_option == CAT_SUBCOMMAND)
	  append_file (file_name);
	else
	  dump_file (file_name, 1, (dev_t) 0);
      }
  }

  write_eot ();
  close_archive ();
  names_notfound ();
}
Example #9
0
int read_archive()

#endif
{
    Stat            sb;
    char            name[PATH_MAX + 1];
    int             match;
    int		    pad;

    name_gather();		/* get names from command line */
    name[0] = '\0';
    while (get_header(name, &sb) == 0) {
	match = name_match(name) ^ f_reverse_match;
	if (f_list) {		/* only wanted a table of contents */
	    if (match) {
		print_entry(name, &sb);
	    }
	    if (((ar_format == TAR) 
		? buf_skip(ROUNDUP((OFFSET) sb.sb_size, BLOCKSIZE)) 
		: buf_skip((OFFSET) sb.sb_size)) < 0) {
		warn(name, "File data is corrupt");
	    }
	} else if (match) {
	    if (rplhead != (Replstr *)NULL) {
		rpl_name(name);
		if (strlen(name) == 0) {
		    continue;
		}
	    }
	    if (get_disposition("extract", name) || 
                get_newname(name, sizeof(name))) {
		/* skip file... */
		if (((ar_format == TAR) 
		    ? buf_skip(ROUNDUP((OFFSET) sb.sb_size, BLOCKSIZE)) 
		    : buf_skip((OFFSET) sb.sb_size)) < 0) {
		    warn(name, "File data is corrupt");
		}
		continue;
	    } 
	    if (inentry(name, &sb) < 0) {
		warn(name, "File data is corrupt");
	    }
	    if (f_verbose) {
		print_entry(name, &sb);
	    }
	    if (ar_format == TAR && sb.sb_nlink > 1) {
		/*
		 * This kludge makes sure that the link table is cleared
		 * before attempting to process any other links.
		 */
		if (sb.sb_nlink > 1) {
		    linkfrom(name, &sb);
		}
	    }
	    if (ar_format == TAR && (pad = sb.sb_size % BLOCKSIZE) != 0) {
		pad = BLOCKSIZE - pad;
		buf_skip((OFFSET) pad);
	    }
	} else {
	    if (((ar_format == TAR) 
		? buf_skip(ROUNDUP((OFFSET) sb.sb_size, BLOCKSIZE)) 
		: buf_skip((OFFSET) sb.sb_size)) < 0) {
		warn(name, "File data is corrupt");
	    }
	}
    }

    close_archive();
}
Example #10
0
File: delete.c Project: WndSks/msys
void
delete_archive_members (void)
{
  enum read_header logical_status = HEADER_STILL_UNREAD;
  enum read_header previous_status = HEADER_STILL_UNREAD;

  /* FIXME: Should clean the routine before cleaning these variables :-( */
  struct name *name;
  off_t blocks_to_skip = 0;
  off_t blocks_to_keep = 0;
  int kept_blocks_in_record;

  name_gather ();
  open_archive (ACCESS_UPDATE);
  acting_as_filter = strcmp (archive_name_array[0], "-") == 0;

  do
    {
      enum read_header status = read_header ();

      switch (status)
	{
	case HEADER_STILL_UNREAD:
	  abort ();

	case HEADER_SUCCESS:
	  if (name = name_scan (current_file_name), !name)
	    {
	      skip_member ();
	      break;
	    }
	  name->found = 1;
	  logical_status = HEADER_SUCCESS;
	  break;

	case HEADER_ZERO_BLOCK:
	  if (ignore_zeros_option)
	    {
	      set_next_block_after (current_header);
	      break;
	    }
	  /* Fall through.  */
	case HEADER_END_OF_FILE:
	  logical_status = HEADER_END_OF_FILE;
	  break;

	case HEADER_FAILURE:
	  set_next_block_after (current_header);
	  switch (previous_status)
	    {
	    case HEADER_STILL_UNREAD:
	      WARN ((0, 0, _("This does not look like a tar archive")));
	      /* Fall through.  */

	    case HEADER_SUCCESS:
	    case HEADER_ZERO_BLOCK:
	      ERROR ((0, 0, _("Skipping to next header")));
	      /* Fall through.  */

	    case HEADER_FAILURE:
	      break;

	    case HEADER_END_OF_FILE:
	      abort ();
	    }
	  break;
	}

      previous_status = status;
    }
  while (logical_status == HEADER_STILL_UNREAD);

  new_record = xmalloc (record_size);

  if (logical_status == HEADER_SUCCESS)
    {
      write_archive_to_stdout = 0;

      /* Save away blocks before this one in this record.  */

      new_blocks = current_block - record_start;
      if (new_blocks)
	memcpy (new_record, record_start, new_blocks * BLOCKSIZE);

#if 0
      /* FIXME: Old code, before the goto was inserted.  To be redesigned.  */
      skip_member ();
#endif
      logical_status = HEADER_STILL_UNREAD;
      goto flush_file;

      /* FIXME: Solaris 2.4 Sun cc (the ANSI one, not the old K&R) says:
	 "delete.c", line 223: warning: loop not entered at top
	 Reported by Bruno Haible.  */
      while (1)
	{
	  enum read_header status;

	  /* Fill in a record.  */

	  if (current_block == record_end)
	    {
	      flush_archive ();
	      records_read++;
	    }
	  status = read_header ();

	  if (status == HEADER_ZERO_BLOCK && ignore_zeros_option)
	    {
	      set_next_block_after (current_header);
	      continue;
	    }
	  if (status == HEADER_END_OF_FILE || status == HEADER_ZERO_BLOCK)
	    {
	      logical_status = HEADER_END_OF_FILE;
	      break;
	    }

	  if (status == HEADER_FAILURE)
	    {
	      ERROR ((0, 0, _("Deleting non-header from archive")));
	      set_next_block_after (current_header);
	      continue;
	    }

	  /* Found another header.  */

	  if (name = name_scan (current_file_name), name)
	    {
	      name->found = 1;
	    flush_file:
	      set_next_block_after (current_header);
	      blocks_to_skip = (current_stat.st_size + BLOCKSIZE - 1) / BLOCKSIZE;

	      while (record_end - current_block <= blocks_to_skip)
		{
		  blocks_to_skip -= (record_end - current_block);
		  flush_archive ();
		  records_read++;
		}
	      current_block += blocks_to_skip;
	      blocks_to_skip = 0;
	      continue;
	    }

	  /* Copy header.  */

	  new_record[new_blocks] = *current_header;
	  new_blocks++;
	  blocks_to_keep
	    = (current_stat.st_size + BLOCKSIZE - 1) / BLOCKSIZE;
	  set_next_block_after (current_header);
	  if (new_blocks == blocking_factor)
	    write_record (1);

	  /* Copy data.  */

	  kept_blocks_in_record = record_end - current_block;
	  if (kept_blocks_in_record > blocks_to_keep)
	    kept_blocks_in_record = blocks_to_keep;

	  while (blocks_to_keep)
	    {
	      int count;

	      if (current_block == record_end)
		{
		  flush_read ();
		  records_read++;
		  current_block = record_start;
		  kept_blocks_in_record = blocking_factor;
		  if (kept_blocks_in_record > blocks_to_keep)
		    kept_blocks_in_record = blocks_to_keep;
		}
	      count = kept_blocks_in_record;
	      if (blocking_factor - new_blocks < count)
		count = blocking_factor - new_blocks;

	      if (! count)
		abort ();

	      memcpy (new_record + new_blocks, current_block, count * BLOCKSIZE);
	      new_blocks += count;
	      current_block += count;
	      blocks_to_keep -= count;
	      kept_blocks_in_record -= count;

	      if (new_blocks == blocking_factor)
		write_record (1);
	    }
	}
    }

  if (logical_status == HEADER_END_OF_FILE)
    {
      /* Write the end of tape.  FIXME: we can't use write_eot here,
	 as it gets confused when the input is at end of file.  */

      int total_zero_blocks = 0;

      do
	{
	  int zero_blocks = blocking_factor - new_blocks;
	  memset (new_record + new_blocks, 0, BLOCKSIZE * zero_blocks);
	  total_zero_blocks += zero_blocks;
	  write_record (total_zero_blocks < 2);
	}
      while (total_zero_blocks < 2);
    }

  free (new_record);

  if (! acting_as_filter && ! _isrmt (archive))
    {
#if MSDOS
      int status = write (archive, "", 0);
#else
      off_t pos = lseek (archive, (off_t) 0, SEEK_CUR);
      int status = pos < 0 ? -1 : ftruncate (archive, pos);
#endif
      if (status != 0)
	truncate_warn (archive_name_array[0]);
    }

  close_archive ();
  names_notfound ();
}
Example #11
0
/* Implement the 'r' (add files to end of archive), and 'u' (add files to
   end of archive if they arent there, or are more up to date than the
   version in the archive.) commands.*/
void
update_archive ()
{
  int found_end = 0;
  int status = 3;
  int prev_status;
  char *p;
  struct name *name;
  extern void dump_file ();

  name_gather ();
  if (cmd_mode == CMD_UPDATE)
    name_expand ();
  open_archive (2);		/* Open for updating */

  do
    {
      prev_status = status;
      status = read_header ();
      switch (status)
	{
	case EOF:
	  found_end = 1;
	  break;

	case 0:		/* A bad record */
	  userec (head);
	  switch (prev_status)
	    {
	    case 3:
	      msg ("This doesn't look like a tar archive.");
	      /* FALL THROUGH */
	    case 2:
	    case 1:
	      msg ("Skipping to next header");
	    case 0:
	      break;
	    }
	  break;

	  /* A good record */
	case 1:
	  /* printf("File %s\n",head->header.name); */
	  /* head->header.name[NAMSIZ-1]='\0'; */
	  if (cmd_mode == CMD_UPDATE && (name = name_scan (current_file_name)))
	    {

	      /* struct stat hstat; */
	      struct stat nstat;
	      int head_standard;

	      decode_header (head, &hstat, &head_standard, 0);
	      if (stat (current_file_name, &nstat) < 0)
		{
		  msg_perror ("can't stat %s:", current_file_name);
		}
	      else
		{
		  if (hstat.st_mtime >= nstat.st_mtime)
		    name->found++;
		}
	    }
	  userec (head);
	  if (head->header.isextended)
	    skip_extended_headers ();
	  skip_file ((long) hstat.st_size);
	  break;

	case 2:
	  ar_record = head;
	  found_end = 1;
	  break;
	}
    }
  while (!found_end);

  reset_eof ();
  time_to_start_writing = 1;
  output_start = ar_record->charptr;

  while (p = name_from_list ())
    {
      if (f_confirm && !confirm ("add", p))
	continue;
      if (cmd_mode == CMD_CAT)
	append_file (p);
      else
	dump_file (p, -1, 1);
    }

  write_eot ();
  close_archive ();
  names_notfound ();
}
Example #12
0
void
collect_and_sort_names (void)
{
  struct name *name;
  struct name *next_name;
  int num_names;
  struct stat statbuf;

  name_gather ();

  if (listed_incremental_option)
    read_directory_file ();

  if (!namelist)
    addname (".");

  for (name = namelist; name; name = next_name)
    {
      next_name = name->next;
      if (name->found || name->dir_contents)
	continue;
      if (name->regexp)		/* FIXME: just skip regexps for now */
	continue;
      if (name->change_dir)
	if (chdir (name->change_dir) < 0)
	  {
	    ERROR ((0, errno, _("Cannot chdir to %s"), name->change_dir));
	    continue;
	  }

      if (
#ifdef AIX
	  statx (name->name, &statbuf, STATSIZE, STX_HIDDEN | STX_LINK)
#else
	  lstat (name->name, &statbuf) < 0
#endif
	  )
	{
	  ERROR ((0, errno, _("Cannot stat %s"), name->name));
	  continue;
	}
      if (S_ISDIR (statbuf.st_mode))
	{
	  name->found = 1;
	  add_hierarchy_to_namelist (name->name, statbuf.st_dev);
	}
    }

  num_names = 0;
  for (name = namelist; name; name = name->next)
    num_names++;
  namelist = (struct name *)
    merge_sort ((voidstar) namelist, num_names,
		(char *) (&(namelist->next)) - (char *) namelist,
		compare_names);

  for (name = namelist; name; name = name->next)
    name->found = 0;

  if (listed_incremental_option)
    write_dir_file ();
}