Пример #1
0
/* Check if FILE_NAME already exists and make a backup of it right now.
   Return success (nonzero) only if the backup is either unneeded, or
   successful.  For now, directories are considered to never need
   backup.  If THIS_IS_THE_ARCHIVE is nonzero, this is the archive and
   so, we do not have to backup block or character devices, nor remote
   entities.  */
bool
maybe_backup_file (const char *file_name, bool this_is_the_archive)
{
  struct stat file_stat;

  assign_string (&before_backup_name, file_name);

  /* A run situation may exist between Emacs or other GNU programs trying to
     make a backup for the same file simultaneously.  If theoretically
     possible, real problems are unlikely.  Doing any better would require a
     convention, GNU-wide, for all programs doing backups.  */

  assign_string (&after_backup_name, 0);

  /* Check if we really need to backup the file.  */

  if (this_is_the_archive && _remdev (file_name))
    return true;

  if (deref_stat (file_name, &file_stat) != 0)
    {
      if (errno == ENOENT)
	return true;

      stat_error (file_name);
      return false;
    }

  if (S_ISDIR (file_stat.st_mode))
    return true;

  if (this_is_the_archive
      && (S_ISBLK (file_stat.st_mode) || S_ISCHR (file_stat.st_mode)))
    return true;

  after_backup_name = find_backup_file_name (file_name, backup_type);
  if (! after_backup_name)
    xalloc_die ();

  if (renameat (chdir_fd, before_backup_name, chdir_fd, after_backup_name)
      == 0)
    {
      if (verbose_option)
	fprintf (stdlis, _("Renaming %s to %s\n"),
		 quote_n (0, before_backup_name),
		 quote_n (1, after_backup_name));
      return true;
    }
  else
    {
      /* The backup operation failed.  */
      int e = errno;
      ERROR ((0, e, _("%s: Cannot rename to %s"),
	      quotearg_colon (before_backup_name),
	      quote_n (1, after_backup_name)));
      assign_string (&after_backup_name, 0);
      return false;
    }
}
Пример #2
0
static void
register_individual_file (char const *name)
{
  struct stat st;
  
  if (deref_stat (dereference_option, name, &st) != 0)
    return; /* Will be complained about later */
  if (S_ISDIR (st.st_mode))
    return;
  
  hash_string_insert (&individual_file_table, name);
}
Пример #3
0
Файл: incremen.c Проект: xrg/tar
void
update_parent_directory (const char *name)
{
  struct directory *directory;
  char *p;

  p = dir_name (name);
  directory = find_directory (p);
  if (directory)
    {
      struct stat st;
      if (deref_stat (dereference_option, p, &st) != 0)
	stat_diag (name);
      else
	directory->mtime = get_stat_mtime (&st);
    }
  free (p);
}
Пример #4
0
void
update_parent_directory (const char *name)
{
  struct directory *directory;
  char *p;

  p = dir_name (name);
  directory = find_directory (p);
  if (directory)
    {
      struct stat st;
      if (deref_stat (dereference_option, p, &st) != 0)
	{
	  if (errno != ENOENT) 
	    stat_diag (directory->name);
	  /* else: should have been already reported */
	}
      else
	directory->mtime = get_stat_mtime (&st);
    }
  free (p);
}
Пример #5
0
/* Recursively scan the given directory DIR.
   DEVICE is the device number where DIR resides (for --one-file-system).
   If CMDLINE is true, the directory name was explicitly listed in the
   command line.
   Unless *PDIR is NULL, store there a pointer to the struct directory
   describing DIR. */
struct directory *
scan_directory (char *dir, dev_t device, bool cmdline)
{
  char *dirp = savedir (dir);	/* for scanning directory */
  namebuf_t nbuf;
  char *tmp;
  struct stat stat_data;
  struct directory *directory;
  char ch;
  
  if (! dirp)
    savedir_error (dir);

  tmp = xstrdup (dir);
  zap_slashes (tmp);
  
  if (deref_stat (dereference_option, tmp, &stat_data))
    {
      dir_removed_diag (tmp, cmdline, stat_diag);
      free (tmp);
      free (dirp);
      return NULL;
    }

  directory = procdir (tmp, &stat_data, device,
		       (cmdline ? PD_FORCE_INIT : 0),
		       &ch);
  
  free (tmp);

  nbuf = namebuf_create (dir);

  if (dirp && directory->children != NO_CHILDREN)
    {
      char *entry;	/* directory entry being scanned */
      dumpdir_iter_t itr;

      makedumpdir (directory, dirp);

      for (entry = dumpdir_first (directory->dump, 1, &itr);
	   entry;
	   entry = dumpdir_next (itr))
	{
	  char *full_name = namebuf_name (nbuf, entry + 1);

	  if (*entry == 'I') /* Ignored entry */
	    *entry = 'N';
	  else if (excluded_name (full_name))
	    *entry = 'N';
	  else
	    {
	      if (deref_stat (dereference_option, full_name, &stat_data))
		{
		  file_removed_diag (full_name, false, stat_diag);
		  *entry = 'N';
		  continue;
		}

	      if (S_ISDIR (stat_data.st_mode))
		{
		  int pd_flag = 0;
		  if (!recursion_option)
		    pd_flag |= PD_FORCE_CHILDREN | NO_CHILDREN;
		  else if (directory->children == ALL_CHILDREN)
		    pd_flag |= PD_FORCE_CHILDREN | ALL_CHILDREN;
		  *entry = 'D';
		  procdir (full_name, &stat_data, device, pd_flag, entry);
		}

	      else if (one_file_system_option && device != stat_data.st_dev)
		*entry = 'N';

	      else if (*entry == 'Y')
		/* New entry, skip further checks */;

	      /* FIXME: if (S_ISHIDDEN (stat_data.st_mode))?? */

	      else if (OLDER_STAT_TIME (stat_data, m)
		       && (!after_date_option
			   || OLDER_STAT_TIME (stat_data, c)))
		*entry = 'N';
	      else
		*entry = 'Y';
	    }
	}
      free (itr);
    }

  namebuf_free (nbuf);

  if (dirp)
    free (dirp);

  return directory;
}
Пример #6
0
/* Examine the directories under directory_name and delete any
   files that were not there at the time of the back-up. */
static bool
try_purge_directory (char const *directory_name)
{
  char *current_dir;
  char *cur, *arc, *p;
  char *temp_stub = NULL;
  struct dumpdir *dump;

  if (!is_dumpdir (&current_stat_info))
    return false;

  current_dir = savedir (directory_name);

  if (!current_dir)
    /* The directory doesn't exist now.  It'll be created.  In any
       case, we don't have to delete any files out of it.  */
    return false;

  /* Verify if dump directory is sane */
  if (!dumpdir_ok (current_stat_info.dumpdir))
    return false;

  /* Process renames */
  for (arc = current_stat_info.dumpdir; *arc; arc += strlen (arc) + 1)
    {
      if (*arc == 'X')
	{
#define TEMP_DIR_TEMPLATE "tar.XXXXXX"
	  size_t len = strlen (arc + 1);
	  temp_stub = xrealloc (temp_stub, len + 1 + sizeof TEMP_DIR_TEMPLATE);
	  memcpy (temp_stub, arc + 1, len);
	  temp_stub[len] = '/';
	  memcpy (temp_stub + len + 1, TEMP_DIR_TEMPLATE,
		  sizeof TEMP_DIR_TEMPLATE);
	  if (!mkdtemp (temp_stub))
	    {
	      ERROR ((0, errno,
		      _("Cannot create temporary directory using template %s"),
		      quote (temp_stub)));
	      free (temp_stub);
	      free (current_dir);
	      return false;
	    }
	}
      else if (*arc == 'R')
	{
	  char *src, *dst;
	  src = arc + 1;
	  arc += strlen (arc) + 1;
	  dst = arc + 1;

	  /* Ensure that neither source nor destination are absolute file
	     names (unless permitted by -P option), and that they do not
	     contain dubious parts (e.g. ../).

	     This is an extra safety precaution. Besides, it might be
	     necessary to extract from archives created with tar versions
	     prior to 1.19. */

	  if (*src)
	    src = safer_name_suffix (src, false, absolute_names_option);
	  if (*dst)
	    dst = safer_name_suffix (dst, false, absolute_names_option);

	  if (*src == 0)
	    src = temp_stub;
	  else if (*dst == 0)
	    dst = temp_stub;

	  if (!rename_directory (src, dst))
	    {
	      free (temp_stub);
	      free (current_dir);
	      /* FIXME: Make sure purge_directory(dst) will return
		 immediately */
	      return false;
	    }
	}
    }

  free (temp_stub);

  /* Process deletes */
  dump = dumpdir_create (current_stat_info.dumpdir);
  p = NULL;
  for (cur = current_dir; *cur; cur += strlen (cur) + 1)
    {
      const char *entry;
      struct stat st;
      if (p)
	free (p);
      p = new_name (directory_name, cur);

      if (deref_stat (false, p, &st))
	{
	  if (errno != ENOENT) /* FIXME: Maybe keep a list of renamed
				  dirs and check it here? */
	    {
	      stat_diag (p);
	      WARN ((0, 0, _("%s: Not purging directory: unable to stat"),
		     quotearg_colon (p)));
	    }
	  continue;
	}

      if (!(entry = dumpdir_locate (dump, cur))
	  || (*entry == 'D' && !S_ISDIR (st.st_mode))
	  || (*entry == 'Y' && S_ISDIR (st.st_mode)))
	{
	  if (one_file_system_option && st.st_dev != root_device)
	    {
	      WARN ((0, 0,
		     _("%s: directory is on a different device: not purging"),
		     quotearg_colon (p)));
	      continue;
	    }

	  if (! interactive_option || confirm ("delete", p))
	    {
	      if (verbose_option)
		fprintf (stdlis, _("%s: Deleting %s\n"),
			 program_name, quote (p));
	      if (! remove_any_file (p, RECURSIVE_REMOVE_OPTION))
		{
		  int e = errno;
		  ERROR ((0, e, _("%s: Cannot remove"), quotearg_colon (p)));
		}
	    }
	}
    }
  free (p);
  dumpdir_free (dump);
  
  free (current_dir);
  return true;
}
Пример #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);
    }
}
Пример #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 ();
}
Пример #9
0
Файл: incremen.c Проект: xrg/tar
/* Recursively scan the given directory. */
static const char *
scan_directory (char *dir, dev_t device)
{
  char *dirp = savedir (dir);	/* for scanning directory */
  char *name_buffer;		/* directory, `/', and directory member */
  size_t name_buffer_size;	/* allocated size of name_buffer, minus 2 */
  size_t name_length;		/* used length in name_buffer */
  struct stat stat_data;
  struct directory *directory;
  
  if (! dirp)
    savedir_error (dir);

  name_buffer_size = strlen (dir) + NAME_FIELD_SIZE;
  name_buffer = xmalloc (name_buffer_size + 2);
  strcpy (name_buffer, dir);
  if (! ISSLASH (dir[strlen (dir) - 1]))
    strcat (name_buffer, "/");
  name_length = strlen (name_buffer);

  if (deref_stat (dereference_option, name_buffer, &stat_data))
    {
      stat_diag (name_buffer);
      /* FIXME: used to be
           children = CHANGED_CHILDREN;
	 but changed to: */
      free (name_buffer);
      free (dirp);
      return NULL;
    }

  directory = procdir (name_buffer, &stat_data, device, 0, NULL);

  if (dirp && directory->children != NO_CHILDREN)
    {
      char *entry;	/* directory entry being scanned */
      size_t entrylen;	/* length of directory entry */
      dumpdir_iter_t itr;

      makedumpdir (directory, dirp);

      for (entry = dumpdir_first (directory->dump, 1, &itr);
	   entry;
	   entry = dumpdir_next (itr))
	{
	  entrylen = strlen (entry);
	  if (name_buffer_size <= entrylen - 1 + name_length)
	    {
	      do
		name_buffer_size += NAME_FIELD_SIZE;
	      while (name_buffer_size <= entrylen - 1 + name_length);
	      name_buffer = xrealloc (name_buffer, name_buffer_size + 2);
	    }
	  strcpy (name_buffer + name_length, entry + 1);

	  if (*entry == 'I') /* Ignored entry */
	    *entry = 'N';
	  else if (excluded_name (name_buffer))
	    *entry = 'N';
	  else
	    {
	      if (deref_stat (dereference_option, name_buffer, &stat_data))
		{
		  stat_diag (name_buffer);
		  *entry = 'N';
		  continue;
		}

	      if (S_ISDIR (stat_data.st_mode))
		{
		  int pd_flag = (verbose_option ? PD_VERBOSE : 0);
		  if (!recursion_option)
		    pd_flag |= PD_FORCE_CHILDREN | NO_CHILDREN;
		  else if (directory->children == ALL_CHILDREN)
		    pd_flag |= PD_FORCE_CHILDREN | ALL_CHILDREN;
		  *entry = 'D';
		  procdir (name_buffer, &stat_data, device, pd_flag, entry);
		}

	      else if (one_file_system_option && device != stat_data.st_dev)
		*entry = 'N';

	      else if (*entry == 'Y')
		/* New entry, skip further checks */;

	      /* FIXME: if (S_ISHIDDEN (stat_data.st_mode))?? */

	      else if (OLDER_STAT_TIME (stat_data, m)
		       && (!after_date_option
			   || OLDER_STAT_TIME (stat_data, c)))
		*entry = 'N';
	      else
		*entry = 'Y';
	    }
	}
      free (itr);
    }

  free (name_buffer);
  if (dirp)
    free (dirp);

  return directory->dump ? directory->dump->contents : NULL;
}