|  | @@ -91,18 +91,21 @@ extr_init (void)
 | 
											
												
													
														|  |  static void
 |  |  static void
 | 
											
												
													
														|  |  set_mode (char *file_name, struct stat *stat_info)
 |  |  set_mode (char *file_name, struct stat *stat_info)
 | 
											
												
													
														|  |  {
 |  |  {
 | 
											
												
													
														|  | -  /* We ought to force permission when -k is not selected, because if the
 |  | 
 | 
											
												
													
														|  | 
 |  | +  /* Do nothing unless we are restoring the original permissions.
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +     We must force permission when -k and -U are not selected, because if the
 | 
											
												
													
														|  |       file already existed, open or creat would save the permission bits from
 |  |       file already existed, open or creat would save the permission bits from
 | 
											
												
													
														|  |       the previously created file, ignoring the ones we specified.
 |  |       the previously created file, ignoring the ones we specified.
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -     But with -k selected, we know *we* created this file, so the mode
 |  | 
 | 
											
												
													
														|  | 
 |  | +     But with -k or -U selected, we know *we* created this file, so the mode
 | 
											
												
													
														|  |       bits were set by our open.  If the file has abnormal mode bits, we must
 |  |       bits were set by our open.  If the file has abnormal mode bits, we must
 | 
											
												
													
														|  |       chmod since writing or chown has probably reset them.  If the file is
 |  |       chmod since writing or chown has probably reset them.  If the file is
 | 
											
												
													
														|  |       normal, we merely skip the chmod.  This works because we did umask (0)
 |  |       normal, we merely skip the chmod.  This works because we did umask (0)
 | 
											
												
													
														|  |       when -p, so umask will have left the specified mode alone.  */
 |  |       when -p, so umask will have left the specified mode alone.  */
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -  if (!keep_old_files_option
 |  | 
 | 
											
												
													
														|  | -      || (stat_info->st_mode & (S_ISUID | S_ISGID | S_ISVTX)))
 |  | 
 | 
											
												
													
														|  | 
 |  | +  if ((we_are_root || same_permissions_option)
 | 
											
												
													
														|  | 
 |  | +      && ((!keep_old_files_option && !unlink_first_option)
 | 
											
												
													
														|  | 
 |  | +	  || (stat_info->st_mode & (S_ISUID | S_ISGID | S_ISVTX))))
 | 
											
												
													
														|  |      if (chmod (file_name, ~current_umask & stat_info->st_mode) < 0)
 |  |      if (chmod (file_name, ~current_umask & stat_info->st_mode) < 0)
 | 
											
												
													
														|  |        ERROR ((0, errno, _("%s: Cannot change mode to %04lo"),
 |  |        ERROR ((0, errno, _("%s: Cannot change mode to %04lo"),
 | 
											
												
													
														|  |  	      file_name,
 |  |  	      file_name,
 | 
											
										
											
												
													
														|  | @@ -281,6 +284,25 @@ make_directories (char *file_name)
 | 
											
												
													
														|  |    return did_something;		/* tell them to retry if we made one */
 |  |    return did_something;		/* tell them to retry if we made one */
 | 
											
												
													
														|  |  }
 |  |  }
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | 
 |  | +/*--------------------------------------------------------------------.
 | 
											
												
													
														|  | 
 |  | +| Unlink the destination, if we are supposed to do so.		      |
 | 
											
												
													
														|  | 
 |  | +| Return zero if extraction should not proceed.			      |
 | 
											
												
													
														|  | 
 |  | +`--------------------------------------------------------------------*/
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +static int
 | 
											
												
													
														|  | 
 |  | +unlink_destination (char const *file_name)
 | 
											
												
													
														|  | 
 |  | +{
 | 
											
												
													
														|  | 
 |  | +  if (unlink_first_option
 | 
											
												
													
														|  | 
 |  | +      && !remove_any_file (file_name, recursive_unlink_option)
 | 
											
												
													
														|  | 
 |  | +      && errno != ENOENT)
 | 
											
												
													
														|  | 
 |  | +    {
 | 
											
												
													
														|  | 
 |  | +      ERROR ((0, errno, _("Cannot remove %s"), file_name));
 | 
											
												
													
														|  | 
 |  | +      return 0;
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  return 1;
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  |  /*--------------------------------------------------------------------.
 |  |  /*--------------------------------------------------------------------.
 | 
											
												
													
														|  |  | Attempt repairing what went wrong with the extraction.  Delete an   |
 |  |  | Attempt repairing what went wrong with the extraction.  Delete an   |
 | 
											
												
													
														|  |  | already existing file or create missing intermediate directories.   |
 |  |  | already existing file or create missing intermediate directories.   |
 | 
											
										
											
												
													
														|  | @@ -294,10 +316,10 @@ maybe_recoverable (char *file_name)
 | 
											
												
													
														|  |    switch (errno)
 |  |    switch (errno)
 | 
											
												
													
														|  |      {
 |  |      {
 | 
											
												
													
														|  |      case EEXIST:
 |  |      case EEXIST:
 | 
											
												
													
														|  | -      /* Attempt deleting an existing file.  However, with -k, just stay
 |  | 
 | 
											
												
													
														|  | 
 |  | +      /* Attempt deleting an existing file.  However, with -k or -U, just stay
 | 
											
												
													
														|  |  	 quiet.  */
 |  |  	 quiet.  */
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -      if (keep_old_files_option)
 |  | 
 | 
											
												
													
														|  | 
 |  | +      if (keep_old_files_option || unlink_first_option)
 | 
											
												
													
														|  |  	return 0;
 |  |  	return 0;
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |        return remove_any_file (file_name, 0);
 |  |        return remove_any_file (file_name, 0);
 | 
											
										
											
												
													
														|  | @@ -541,7 +563,7 @@ Removing leading `/' from absolute path names in the archive")));
 | 
											
												
													
														|  |        /* FIXME: deal with protection issues.  */
 |  |        /* FIXME: deal with protection issues.  */
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |      again_file:
 |  |      again_file:
 | 
											
												
													
														|  | -      openflag = (keep_old_files_option ?
 |  | 
 | 
											
												
													
														|  | 
 |  | +      openflag = (keep_old_files_option || unlink_first_option ?
 | 
											
												
													
														|  |  		  O_BINARY | O_NDELAY | O_WRONLY | O_CREAT | O_EXCL :
 |  |  		  O_BINARY | O_NDELAY | O_WRONLY | O_CREAT | O_EXCL :
 | 
											
												
													
														|  |  		  O_BINARY | O_NDELAY | O_WRONLY | O_CREAT | O_TRUNC)
 |  |  		  O_BINARY | O_NDELAY | O_WRONLY | O_CREAT | O_TRUNC)
 | 
											
												
													
														|  |  	| ((typeflag == GNUTYPE_SPARSE) ? 0 : O_APPEND);
 |  |  	| ((typeflag == GNUTYPE_SPARSE) ? 0 : O_APPEND);
 | 
											
										
											
												
													
														|  | @@ -561,8 +583,15 @@ Removing leading `/' from absolute path names in the archive")));
 | 
											
												
													
														|  |  	  goto extract_file;
 |  |  	  goto extract_file;
 | 
											
												
													
														|  |  	}
 |  |  	}
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -      if (unlink_first_option)
 |  | 
 | 
											
												
													
														|  | -	remove_any_file (CURRENT_FILE_NAME, recursive_unlink_option);
 |  | 
 | 
											
												
													
														|  | 
 |  | +      if (!unlink_destination (CURRENT_FILE_NAME))
 | 
											
												
													
														|  | 
 |  | +	{
 | 
											
												
													
														|  | 
 |  | +	  if (current_header->oldgnu_header.isextended)
 | 
											
												
													
														|  | 
 |  | +	    skip_extended_headers ();
 | 
											
												
													
														|  | 
 |  | +	  skip_file (current_stat.st_size);
 | 
											
												
													
														|  | 
 |  | +	  if (backup_option)
 | 
											
												
													
														|  | 
 |  | +	    undo_last_backup ();
 | 
											
												
													
														|  | 
 |  | +	  break;
 | 
											
												
													
														|  | 
 |  | +	}
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  #if O_CTG
 |  |  #if O_CTG
 | 
											
												
													
														|  |        /* Contiguous files (on the Masscomp) have to specify the size in
 |  |        /* Contiguous files (on the Masscomp) have to specify the size in
 | 
											
										
											
												
													
														|  | @@ -696,9 +725,9 @@ Removing leading `/' from absolute path names in the archive")));
 | 
											
												
													
														|  |        if (to_stdout_option)
 |  |        if (to_stdout_option)
 | 
											
												
													
														|  |  	break;
 |  |  	break;
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -#ifdef S_ISLNK
 |  | 
 | 
											
												
													
														|  | -      if (unlink_first_option)
 |  | 
 | 
											
												
													
														|  | -	remove_any_file (CURRENT_FILE_NAME, recursive_unlink_option);
 |  | 
 | 
											
												
													
														|  | 
 |  | +#ifdef HAVE_SYMLINK
 | 
											
												
													
														|  | 
 |  | +      if (!unlink_destination (CURRENT_FILE_NAME))
 | 
											
												
													
														|  | 
 |  | +	break;
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |        while (status = symlink (current_link_name, CURRENT_FILE_NAME),
 |  |        while (status = symlink (current_link_name, CURRENT_FILE_NAME),
 | 
											
												
													
														|  |  	     status != 0)
 |  |  	     status != 0)
 | 
											
										
											
												
													
														|  | @@ -723,7 +752,7 @@ Removing leading `/' from absolute path names in the archive")));
 | 
											
												
													
														|  |  	}
 |  |  	}
 | 
											
												
													
														|  |        break;
 |  |        break;
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -#else /* not S_ISLNK */
 |  | 
 | 
											
												
													
														|  | 
 |  | +#else
 | 
											
												
													
														|  |        {
 |  |        {
 | 
											
												
													
														|  |  	static int warned_once = 0;
 |  |  	static int warned_once = 0;
 | 
											
												
													
														|  |  
 |  |  
 | 
											
										
											
												
													
														|  | @@ -736,14 +765,14 @@ Attempting extraction of symbolic links as hard links")));
 | 
											
												
													
														|  |        }
 |  |        }
 | 
											
												
													
														|  |        /* Fall through.  */
 |  |        /* Fall through.  */
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -#endif /* not S_ISLNK */
 |  | 
 | 
											
												
													
														|  | 
 |  | +#endif
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |      case LNKTYPE:
 |  |      case LNKTYPE:
 | 
											
												
													
														|  |        if (to_stdout_option)
 |  |        if (to_stdout_option)
 | 
											
												
													
														|  |  	break;
 |  |  	break;
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -      if (unlink_first_option)
 |  | 
 | 
											
												
													
														|  | -	remove_any_file (CURRENT_FILE_NAME, recursive_unlink_option);
 |  | 
 | 
											
												
													
														|  | 
 |  | +      if (!unlink_destination (CURRENT_FILE_NAME))
 | 
											
												
													
														|  | 
 |  | +	break;
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |      again_link:
 |  |      again_link:
 | 
											
												
													
														|  |        {
 |  |        {
 | 
											
										
											
												
													
														|  | @@ -789,8 +818,8 @@ Attempting extraction of symbolic links as hard links")));
 | 
											
												
													
														|  |        if (to_stdout_option)
 |  |        if (to_stdout_option)
 | 
											
												
													
														|  |  	break;
 |  |  	break;
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -      if (unlink_first_option)
 |  | 
 | 
											
												
													
														|  | -	remove_any_file (CURRENT_FILE_NAME, recursive_unlink_option);
 |  | 
 | 
											
												
													
														|  | 
 |  | +      if (!unlink_destination (CURRENT_FILE_NAME))
 | 
											
												
													
														|  | 
 |  | +	break;
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |        status = mknod (CURRENT_FILE_NAME, current_stat.st_mode,
 |  |        status = mknod (CURRENT_FILE_NAME, current_stat.st_mode,
 | 
											
												
													
														|  |  		      current_stat.st_rdev);
 |  |  		      current_stat.st_rdev);
 | 
											
										
											
												
													
														|  | @@ -808,13 +837,13 @@ Attempting extraction of symbolic links as hard links")));
 | 
											
												
													
														|  |        break;
 |  |        break;
 | 
											
												
													
														|  |  #endif
 |  |  #endif
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -#ifdef S_ISFIFO
 |  | 
 | 
											
												
													
														|  | 
 |  | +#if HAVE_MKFIFO || defined mkfifo
 | 
											
												
													
														|  |      case FIFOTYPE:
 |  |      case FIFOTYPE:
 | 
											
												
													
														|  |        if (to_stdout_option)
 |  |        if (to_stdout_option)
 | 
											
												
													
														|  |  	break;
 |  |  	break;
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -      if (unlink_first_option)
 |  | 
 | 
											
												
													
														|  | -	remove_any_file (CURRENT_FILE_NAME, recursive_unlink_option);
 |  | 
 | 
											
												
													
														|  | 
 |  | +      if (!unlink_destination (CURRENT_FILE_NAME))
 | 
											
												
													
														|  | 
 |  | +	break;
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |        while (status = mkfifo (CURRENT_FILE_NAME, current_stat.st_mode),
 |  |        while (status = mkfifo (CURRENT_FILE_NAME, current_stat.st_mode),
 | 
											
												
													
														|  |  	     status != 0)
 |  |  	     status != 0)
 |