* src/copy.h: Change update member from bool to enum.
* src/copy.c: s/interactive == I_ALWAYS_NO/update == UPDATE_NONE_FAIL/;
s/interactive == I_ALWAYS_SKIP/update == UPDATE_NONE/;
s/update/update == UPDATE_OLDER/;
* src/install.c: Init with UPDATE_ALL, rather than false.
* src/cp.c: Likewise. Simply parse -f,-i,-n to x.interactive,
and parse --update to x.update.
* src/mv.c: Likewise.
* tests/cp/cp-i.sh: Add a test case where -n --update -i
honors the --update option, which would previously have been
ignored due to the preceding -n.
struct stat const *dst_sb)
{
affirm (x->move_mode);
- return (x->interactive == I_ALWAYS_NO
- || x->interactive == I_ALWAYS_SKIP
+ return (x->update == UPDATE_NONE
+ || x->update == UPDATE_NONE_FAIL
|| ((x->interactive == I_ASK_USER
|| (x->interactive == I_UNSPECIFIED
&& x->stdin_tty
if (rename_errno == 0
? !x->last_file
: rename_errno != EEXIST
- || (x->interactive != I_ALWAYS_NO && x->interactive != I_ALWAYS_SKIP))
+ || (x->update != UPDATE_NONE && x->update != UPDATE_NONE_FAIL))
{
char const *name = rename_errno == 0 ? dst_name : src_name;
int dirfd = rename_errno == 0 ? dst_dirfd : AT_FDCWD;
{
/* Normally, fill in DST_SB or set NEW_DST so that later code
can use DST_SB if NEW_DST is false. However, don't bother
- doing this when rename_errno == EEXIST and X->interactive is
- I_ALWAYS_NO or I_ALWAYS_SKIP, something that can happen only
- with mv in which case x->update must be false which means
- that even if !NEW_DST the move will be abandoned without
- looking at DST_SB. */
+ doing this when rename_errno == EEXIST and not updating,
+ which means that even if !NEW_DST the move will be abandoned
+ without looking at DST_SB. */
if (! (rename_errno == EEXIST
- && (x->interactive == I_ALWAYS_NO
- || x->interactive == I_ALWAYS_SKIP)))
+ && (x->update == UPDATE_NONE
+ || x->update == UPDATE_NONE_FAIL)))
{
/* Regular files can be created by writing through symbolic
links, but other files cannot. So use stat on the
bool return_val = true;
bool skipped = false;
- if ((x->interactive != I_ALWAYS_NO && x->interactive != I_ALWAYS_SKIP)
+ if ((x->update != UPDATE_NONE && x->update != UPDATE_NONE_FAIL)
&& ! same_file_ok (src_name, &src_sb, dst_dirfd, drelname,
&dst_sb, x, &return_now))
{
return false;
}
- if (x->update && !S_ISDIR (src_mode))
+ if (x->update == UPDATE_OLDER && !S_ISDIR (src_mode))
{
/* When preserving timestamps (but not moving within a file
system), don't worry if the destination timestamp is
*rename_succeeded = true;
skipped = true;
- return_val = x->interactive == I_ALWAYS_SKIP;
+ return_val = x->update == UPDATE_NONE;
}
}
else
{
if (! S_ISDIR (src_mode)
- && (x->interactive == I_ALWAYS_NO
- || x->interactive == I_ALWAYS_SKIP
+ && (x->update == UPDATE_NONE
+ || x->update == UPDATE_NONE_FAIL
|| (x->interactive == I_ASK_USER
&& ! overwrite_ok (x, dst_name, dst_dirfd,
dst_relname, &dst_sb))))
{
skipped = true;
- return_val = x->interactive == I_ALWAYS_SKIP;
+ return_val = x->update == UPDATE_NONE;
}
}
skip:
if (skipped)
{
- if (x->interactive == I_ALWAYS_NO)
+ if (x->update == UPDATE_NONE_FAIL)
error (0, 0, _("not replacing %s"), quoteaf (dst_name));
else if (x->debug)
printf (_("skipped %s\n"), quoteaf (dst_name));
int symlink_err = force_symlinkat (src_link_val, dst_dirfd, dst_relname,
x->unlink_dest_after_failed_open, -1);
- if (0 < symlink_err && x->update && !new_dst && S_ISLNK (dst_sb.st_mode)
+ if (0 < symlink_err && x->update == UPDATE_OLDER
+ && !new_dst && S_ISLNK (dst_sb.st_mode)
&& dst_sb.st_size == strlen (src_link_val))
{
/* See if the destination is already the desired symlink.
/* Always update.. */
UPDATE_ALL,
- /* Update if dest older. */
+ /* Update if (nondirectory) dest has older mtime. */
UPDATE_OLDER,
/* Leave existing files. */
/* This type is used to help mv (via copy.c) distinguish these cases. */
enum Interactive
{
- I_ALWAYS_YES = 1,
- I_ALWAYS_NO, /* Skip and fail. */
- I_ALWAYS_SKIP, /* Skip and ignore. */
- I_ASK_USER,
- I_UNSPECIFIED
+ I_UNSPECIFIED,
+ I_ALWAYS_YES, /* -f. */
+ I_ALWAYS_SKIP, /* -n (Skip and ignore). */
+ I_ASK_USER, /* -i. */
};
/* How to handle symbolic links. */
Create destination directories as usual. */
bool symbolic_link;
- /* If true, do not copy a nondirectory that has an existing destination
- with the same or newer modification time. */
- bool update;
+ /* Control if destination files are replaced. */
+ enum Update_type update;
/* If true, display the names of the files before copying them. */
bool verbose;
/* Not used. */
x->stdin_tty = false;
- x->update = false;
+ x->update = UPDATE_ALL;
x->verbose = false;
x->keep_directory_symlink = false;
char *target_directory = nullptr;
bool no_target_directory = false;
char const *scontext = nullptr;
- bool no_clobber = false;
initialize_main (&argc, &argv);
set_program_name (argv[0]);
break;
case 'i':
- /* -i overrides -n, but not --update={none,none-fail}. */
- if (no_clobber || x.interactive == I_UNSPECIFIED)
- x.interactive = I_ASK_USER;
+ x.interactive = I_ASK_USER;
break;
case 'l':
case 'n':
x.interactive = I_ALWAYS_SKIP;
- no_clobber = true;
- x.update = false;
break;
case 'P':
break;
case 'u':
- if (! no_clobber) /* -n > -u */
- {
- enum Update_type update_opt = UPDATE_OLDER;
- if (optarg)
- update_opt = XARGMATCH ("--update", optarg,
- update_type_string, update_type);
- if (update_opt == UPDATE_ALL)
- {
- /* Default cp operation. */
- x.update = false;
- if (x.interactive != I_ASK_USER)
- x.interactive = I_UNSPECIFIED;
- }
- else if (update_opt == UPDATE_NONE)
- {
- x.update = false;
- x.interactive = I_ALWAYS_SKIP;
- }
- else if (update_opt == UPDATE_NONE_FAIL)
- {
- x.update = false;
- x.interactive = I_ALWAYS_NO;
- }
- else if (update_opt == UPDATE_OLDER)
- {
- x.update = true;
- if (x.interactive != I_ASK_USER)
- x.interactive = I_UNSPECIFIED;
- }
- }
+ x.update = UPDATE_OLDER;
+ if (optarg)
+ x.update = XARGMATCH ("--update", optarg,
+ update_type_string, update_type);
break;
case 'v':
usage (EXIT_FAILURE);
}
+ if (x.interactive == I_ALWAYS_SKIP)
+ x.update = UPDATE_NONE;
+
if (make_backups
- && (x.interactive == I_ALWAYS_SKIP
- || x.interactive == I_ALWAYS_NO))
+ && (x.update == UPDATE_NONE
+ || x.update == UPDATE_NONE_FAIL))
{
error (0, 0,
_("--backup is mutually exclusive with -n or --update=none-fail"));
x->stdin_tty = false;
x->open_dangling_dest_symlink = false;
- x->update = false;
+ x->update = UPDATE_ALL;
x->require_preserve_context = false; /* Not used by install currently. */
x->preserve_security_context = false; /* Whether to copy context from src. */
x->set_security_context = nullptr; /* Whether to set sys default context. */
x->stdin_tty = isatty (STDIN_FILENO);
x->open_dangling_dest_symlink = false;
- x->update = false;
+ x->update = UPDATE_ALL;
x->verbose = false;
x->dest_info = nullptr;
x->src_info = nullptr;
int n_files;
char **file;
bool selinux_enabled = (0 < is_selinux_enabled ());
- bool no_clobber = false;
initialize_main (&argc, &argv);
set_program_name (argv[0]);
version_control_string = optarg;
break;
case 'f':
- /* -f overrides -n, or -i, but not --update={none,none-fail}. */
- if (no_clobber
- || x.interactive == I_ASK_USER
- || x.interactive == I_UNSPECIFIED)
- x.interactive = I_ALWAYS_YES;
+ x.interactive = I_ALWAYS_YES;
break;
case 'i':
- /* -i overrides -n, or -f, but not --update={none,none-fail}. */
- if (no_clobber
- || x.interactive == I_ALWAYS_YES
- || x.interactive == I_UNSPECIFIED)
- x.interactive = I_ASK_USER;
+ x.interactive = I_ASK_USER;
break;
case 'n':
x.interactive = I_ALWAYS_SKIP;
- no_clobber = true;
- x.update = false;
break;
case DEBUG_OPTION:
x.debug = x.verbose = true;
no_target_directory = true;
break;
case 'u':
- if (! no_clobber)
- {
- enum Update_type update_opt = UPDATE_OLDER;
- if (optarg)
- update_opt = XARGMATCH ("--update", optarg,
- update_type_string, update_type);
- if (update_opt == UPDATE_ALL)
- {
- /* Default mv operation. */
- x.update = false;
- if (x.interactive != I_ASK_USER
- && x.interactive != I_ALWAYS_YES)
- x.interactive = I_UNSPECIFIED;
- }
- else if (update_opt == UPDATE_NONE)
- {
- x.update = false;
- x.interactive = I_ALWAYS_SKIP;
- }
- else if (update_opt == UPDATE_NONE_FAIL)
- {
- x.update = false;
- x.interactive = I_ALWAYS_NO;
- }
- else if (update_opt == UPDATE_OLDER)
- {
- x.update = true;
- if (x.interactive != I_ASK_USER
- && x.interactive != I_ALWAYS_YES)
- x.interactive = I_UNSPECIFIED;
- }
- }
+ x.update = UPDATE_OLDER;
+ if (optarg)
+ x.update = XARGMATCH ("--update", optarg,
+ update_type_string, update_type);
break;
case 'v':
x.verbose = true;
for (int i = 0; i < n_files; i++)
strip_trailing_slashes (file[i]);
+ if (x.interactive == I_ALWAYS_SKIP)
+ x.update = UPDATE_NONE;
+
if (make_backups
&& (x.exchange
- || x.interactive == I_ALWAYS_SKIP
- || x.interactive == I_ALWAYS_NO))
+ || x.update == UPDATE_NONE
+ || x.update == UPDATE_NONE_FAIL))
{
error (0, 0,
_("cannot combine --backup with "
# Likewise, but coreutils 9.3 - 9.5 incorrectly ignored the update option
cp -v --update=none -i new old 2>/dev/null >out8 </dev/null || fail=1
compare /dev/null out8 || fail=1
+# Likewise, but coreutils 9.3 - 9.5 incorrectly ignored the update option
+cp -v -n --update=none -i new old 2>/dev/null >out8 </dev/null || fail=1
+compare /dev/null out8 || fail=1
Exit $fail