Ejemplo n.º 1
0
int
remove_any_file (const char *path, int recurse)
{
  struct L_STAT stat_buffer;

  if (L_LSTAT (path, &stat_buffer) < 0)
    return 0;

  if (S_ISDIR (stat_buffer.st_mode))
    if (recurse)
      {
	DIR *dirp = opendir (path);
	struct dirent *dp;

	if (dirp == NULL)
	  return 0;

	while (dp = readdir (dirp), dp && !is_dot_or_dotdot (dp->d_name))
	  {
	    char *path_buffer = new_name (path, dp->d_name);

	    if (!remove_any_file (path_buffer, 1))
	      {
		int saved_errno = errno;

		free (path_buffer);
		closedir (dirp);
		errno = saved_errno; /* FIXME: errno should be read-only */
		return 0;
	      }
	    free (path_buffer);
	  }
	closedir (dirp);
	return rmdir (path) >= 0;
      }
    else
      {
	/* FIXME: Saving errno might not be needed anymore, now that
	   extract_archive tests for the special case before recovery.  */
	int saved_errno = errno;

	if (rmdir (path) >= 0)
	  return 1;
	errno = saved_errno;	/* FIXME: errno should be read-only */
	return 0;
      }

  return unlink (path) >= 0;
}
Ejemplo n.º 2
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;
}
Ejemplo n.º 3
0
void
incremental_restore (int skipcrud)
{
  char *current_dir;
  char *archive_dir;
  struct accumulator *accumulator;
  char *p;
  DIR *dirp;
  struct dirent *d;
  char *cur, *arc;
  long size;
  size_t size_to_copy;
  union block *data_block;
  char *to;

#define CURRENT_FILE_NAME (skipcrud + current.name)

  dirp = opendir (CURRENT_FILE_NAME);

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

      skip_file (current.stat.st_size);
      return;
    }

  accumulator = new_accumulator ();
  while (d = readdir (dirp), d)
    {
      if (is_dot_or_dotdot (d->d_name))
	continue;

      add_to_accumulator (accumulator, d->d_name, NAMLEN (d) + 1);
    }
  closedir (dirp);
  add_to_accumulator (accumulator, "", (size_t) 1);

  current_dir = get_accumulator (accumulator);
  archive_dir = (char *) xmalloc ((size_t) current.stat.st_size);
  to = archive_dir;
  for (size = current.stat.st_size; size > 0; size -= size_to_copy)
    {
      data_block = find_next_block ();
      if (!data_block)
	{
	  ERROR ((0, 0, _("Unexpected end of file in archive")));
	  break;		/* FIXME: What happens then?  */
	}
      size_to_copy = available_space_after (data_block);
      if (size_to_copy > size)
	size_to_copy = size;
      memcpy (to, data_block->buffer, size_to_copy);
      to += size_to_copy;
      set_next_block_after ((union block *)
			    (data_block->buffer + size_to_copy - 1));
    }

  for (cur = current_dir; *cur; cur += strlen (cur) + 1)
    {
      for (arc = archive_dir; *arc; arc += strlen (arc) + 1)
	{
	  arc++;
	  if (!strcmp (arc, cur))
	    break;
	}
      if (*arc == '\0')
	{
	  p = concat_with_slash (CURRENT_FILE_NAME, cur);
	  if (interactive_option && !confirm (_("delete %s?"), p))
	    {
	      free (p);
	      continue;
	    }
	  if (verbose_option)
	    {
	      if (checkpoint_option)
		flush_progress_dots ();
	      fprintf (stdlis, _("%s: Deleting %s\n"), program_name, p);
	    }
	  if (!remove_any_file (p, true))
	    ERROR ((0, errno, _("Error while deleting %s"), p));
	  free (p);
	}

    }
  delete_accumulator (accumulator);
  free (archive_dir);

#undef CURRENT_FILE_NAME
}
Ejemplo n.º 4
0
/* Remove FILE_NAME, returning 1 on success.  If FILE_NAME is a directory,
   then if OPTION is RECURSIVE_REMOVE_OPTION is set remove FILE_NAME
   recursively; otherwise, remove it only if it is empty.  If FILE_NAME is
   a directory that cannot be removed (e.g., because it is nonempty)
   and if OPTION is WANT_DIRECTORY_REMOVE_OPTION, then return -1.
   Return 0 on error, with errno set; if FILE_NAME is obviously the working
   directory return zero with errno set to zero.  */
int
remove_any_file (const char *file_name, enum remove_option option)
{
  /* Try unlink first if we cannot unlink directories, as this saves
     us a system call in the common case where we're removing a
     non-directory.  */
  bool try_unlink_first = cannot_unlink_dir ();

  if (try_unlink_first)
    {
      if (unlinkat (chdir_fd, file_name, 0) == 0)
	return 1;

      /* POSIX 1003.1-2001 requires EPERM when attempting to unlink a
	 directory without appropriate privileges, but many Linux
	 kernels return the more-sensible EISDIR.  */
      if (errno != EPERM && errno != EISDIR)
	return 0;
    }

  if (safer_rmdir (file_name) == 0)
    return 1;

  switch (errno)
    {
    case ENOTDIR:
      return !try_unlink_first && unlinkat (chdir_fd, file_name, 0) == 0;

    case 0:
    case EEXIST:
#if defined ENOTEMPTY && ENOTEMPTY != EEXIST
    case ENOTEMPTY:
#endif
      switch (option)
	{
	case ORDINARY_REMOVE_OPTION:
	  break;

	case WANT_DIRECTORY_REMOVE_OPTION:
	  return -1;

	case RECURSIVE_REMOVE_OPTION:
	  {
	    char *directory = tar_savedir (file_name, 0);
	    char const *entry;
	    size_t entrylen;

	    if (! directory)
	      return 0;

	    for (entry = directory;
		 (entrylen = strlen (entry)) != 0;
		 entry += entrylen + 1)
	      {
		char *file_name_buffer = new_name (file_name, entry);
		int r = remove_any_file (file_name_buffer,
                                         RECURSIVE_REMOVE_OPTION);
		int e = errno;
		free (file_name_buffer);

		if (! r)
		  {
		    free (directory);
		    errno = e;
		    return 0;
		  }
	      }

	    free (directory);
	    return safer_rmdir (file_name) == 0;
	  }
	}
      break;
    }

  return 0;
}