Compare commits

...

26 Commits
v9.2 ... v9.3

Author SHA1 Message Date
Pádraig Brady
f386722dc0 version 9.3
* NEWS: Record release date.
2023-04-18 15:08:11 +01:00
Pádraig Brady
d81094dc7b tests: avoid allocation checks on ZFS
* tests/du/basic.sh: Allocation of files was seen to change
asynchronously on ZFS, so avoid allocation comparisons there.
2023-04-16 16:11:20 +01:00
Pádraig Brady
cf91b9d62c tests: tty-eof: fix various issues
* tests/misc/tty-eof.pl: Ensure we don't erroneously
skip commands with parameters.
Comment as to why cut(1) is treated differently.
Adjust expect calls to not wait needlessly for cut output.
2023-04-14 00:02:22 +01:00
Pádraig Brady
daa1e4f557 tests: avoid dependence on file layout for cp sparse check
* tests/cp/sparse-2.sh: Don't depend on the copy taking
<= allocation of the source.  Instead leverage --debug
to check that zero detection is being enabled.
2023-04-13 20:19:18 +01:00
Pádraig Brady
854c90ecc0 copy: --debug: indicate if NUL detection is used with SEEK_HOLE
* src/copy.c (sparse_copy): With --sparse=always we also detect
NULs in extents we're copying, so indicate this with --debug.
2023-04-13 20:19:09 +01:00
Paul Eggert
cc95246ee2 doc: update re 32-bit builds
* README-install: Mention how to build on 32-bit-only hosts.
This builds on a previous patch by Pádraig Brady.
2023-04-10 11:56:43 -07:00
Pádraig Brady
ae4dace2ec build: fix _Noreturn compilation failure
Fix a build failure seen on gcc 3.4 on Solaris 10 at least.

* src/crctab.c: Ensure we include config.h for all compilation units.
This is now required for new _Noreturn usage in gnulib for stdint.h.
* src/cksum.c: Update generation code to ensure config.h included.
* cfg.mk: Remove crctab.c exclusion from the config.h check.
2023-04-10 19:45:14 +01:00
Pádraig Brady
09ded7049b tests: avoid non portable brace expansion
* tests/cp/backup-dir.sh: Avoid non portable brace expansion
which is not supported by FreeBSD or Solaris shells at least.
2023-04-10 18:54:19 +01:00
Paul Eggert
ffd62ab92c maint: require support for post-2038 timestamps
* bootstrap.conf (gnulib_modules): Replace year2038 with
year2038-required.
2023-04-09 19:21:55 -07:00
Paul Eggert
6f91c2eac3 build: update gnulib submodule to latest 2023-04-09 19:21:55 -07:00
Pádraig Brady
ce630dfc7e wc: ensure we update file offset
* src/wc.c (wc): Update the offset when not reading,
and do read if we can't update the offset.
* tests/misc/wc-proc.sh: Add a test case.
* NEWS: Mention the bug fix.
Fixes https://bugs.gnu.org/61300
2023-04-08 12:19:40 +01:00
Pádraig Brady
f6c21f6d3a cp,mv: issue "skipped" messages when skipping files
* NEWS: Mention the change in behavior to issue a "not replaced"
error diagnostic with -n, and the "skipped" message with -v.
* src/copy.c (copy_internal): Adjust to output the "skipped" messages
depending on -i, -n, -u.
* tests/cp/cp-i.sh: Adjust accordingly.
* tests/mv/mv-n.sh: Likewise.
2023-04-08 12:11:58 +01:00
Pádraig Brady
db28af406f cp,mv: add --update=none to always skip existing files
Add --update=none which is equivalent to the --no-clobber behavior
from before coreutils 9.2.  I.e. existing files are unconditionally
skipped, and them not being replaced does not affect the exit status.

* src/copy.h [enum Update_type]: A new type to support parameters
to the --update command line option.
[enum Interactive]: Add I_ALWAYS_SKIP.
* src/copy.c: Treat I_ALWAYS_SKIP like I_ALWAYS_NO (-n),
except that we don't fail when skipping.
* src/system.h (emit_update_parameters_note): A new function
to output the description of the new --update parameters.
* src/cp.c (main): Parse --update arguments, ensuring that
-n takes precedence if specified.
(usage): Describe the new option.  Also allude that
-u is related in the -n description.
* src/mv.c: Accept the new --update parameters and
update usage() accordingly.
* doc/coreutils.texi (cp invocation): Describe the new --update
parameters.  Also reference --update from the --no-clobber description.
(mv invocation): Likewise.
* tests/mv/update.sh: Test the new parameters.
* NEWS: Mention the new feature.
Addresses https://bugs.gnu.org/62572
2023-04-08 12:11:50 +01:00
Pádraig Brady
5891d28ede cp: fix --backup with subdirectories
* gnulib: Reference the latest gnulib including the
fix to the backupfile module in commit 94496522.
* tests/cp/backup-dir.sh: Add a test to ensure
we rename appropriately when backing up through subdirs.
* NEWS: Mention the bug fix.
Fixes https://bugs.gnu.org/62607
2023-04-04 12:00:11 +01:00
Pádraig Brady
17c31a73f1 tests: tee: avoid false failure due to fifo usage
* tests/misc/tee.sh: Call cleanup_ in all cases to ensure
there are no overlapping interactions on the fifo that
might impact later parts of the test.  This was seen to
cause issue with dash on musl libc.
Addresses https://bugs.gnu.org/62542
2023-03-31 11:58:53 +01:00
Pádraig Brady
5e170ff0b8 tests: adjust csplit VM limit
* tests/misc/csplit-heap.sh: More memory is required to avoid
a false failure on some systems.  Noticed with musl libc
with bash as the shell.  This is confirmed to still easily
trigger with the original memory leak being tested.
Addresses https://bugs.gnu.org/62542
2023-03-31 11:58:53 +01:00
Pádraig Brady
7ad749886c wc: diagnose overflow of total counts
* src/wc.c (wc): Use INT_ADD_WRAPV() to detect overflow.
(main): Upon overflow, saturate the total, print a diagnostic,
and set exit status.
* tests/misc/wc-total.sh: Add a test case, which operates
on BTRFS and 64 bit systems at least.
Reported at https://bugs.debian.org/1027100
2023-03-31 11:58:49 +01:00
Pádraig Brady
a9bd274616 dircolors: diagnose read errors
* NEWS: Mention the fix.
* src/dircolors.c: Fail upon read error from getline().
* tests/misc/dircolors.sh: Add a new test.
* tests/local.mk: Reference the new test.
2023-03-28 14:24:29 +01:00
Pádraig Brady
a4525de1ef tests: add a test case for the previous date fix
* NEWS: Also mention this bug fix.
* tests/misc/date-f.sh: Add a new test.
* tests/local.mk: Reference the new test.
2023-03-28 13:40:43 +01:00
Paul Eggert
9c5e542fd1 date: diagnose -f read errors
* src/date.c (batch_convert): Diagnose read errors, fixing Bug#62497.
2023-03-28 01:53:06 -07:00
Paul Eggert
6272817de0 cp: clarify commentary
* src/copy.c: Make comments a bit clearer.
2023-03-25 13:20:16 -07:00
Pádraig Brady
093a8b4bfa copy: fix --reflink=auto to fallback in more cases
On restricted systems like android or some containers,
FICLONE could return EPERM, EACCES, or ENOTTY,
which would have induced the command to fail to copy
rather than falling back to a more standard copy.

* src/copy.c (is_terminal_failure): A new function refactored
from handle_clone_fail().
(is_CLONENOTSUP): Merge in the handling of EACCES, ENOTTY, EPERM
as they also pertain to determination of whether cloning is supported
if we ever use this function in that context.
(handle_clone_fail): Use is_terminal_failure() in all cases,
so that we assume a terminal failure in less errno cases.
* NEWS: Mention the bug fix.
Addresses https://bugs.gnu.org/62404
2023-03-24 13:12:51 +00:00
Pádraig Brady
55456b95d8 doc: add a NEWS entry for the previous fix
* NEWS: Mention the previous cksum --check fix.
2023-03-24 12:52:13 +00:00
Pádraig Brady
76f2fb6271 cksum: fix reporting of failed checks
This applies to all checksumming utilities,
where we incorrectly report all subsequent files as checking 'OK'
once any file has passed a digest check.
The exit status was not impacted, only the printed status.

* src/digest.c (digest_check): Use the correct state variable
to determine if the _current_ file has passed or not.
* tests/misc/md5sum.pl: Add a test case.
Fixes https://bugs.gnu.org/62403
2023-03-23 12:36:53 +00:00
Nick Alcock
eeabb11eb6 tests: skip some parts of tests/misc/tee.sh if run as root
Similarly to the fix to tests/rmdir/ignore.sh in c0e5f8c59,
tee should not be expected to fail when run with read-only outputs
when run as root.

* tests/misc/tee.sh: Add uid_is_privileged_ guard around test for
read-only outputs.
2023-03-21 16:15:18 +00:00
Pádraig Brady
bdda9adb38 maint: post-release administrivia
* NEWS: Add header line for next release.
* .prev-version: Record previous version.
* cfg.mk (old_NEWS_hash): Auto-update.
2023-03-20 14:08:46 +00:00
33 changed files with 523 additions and 124 deletions

View File

@@ -1 +1 @@
9.1
9.2

50
NEWS
View File

@@ -1,5 +1,55 @@
GNU coreutils NEWS -*- outline -*-
* Noteworthy changes in release 9.3 (2023-04-18) [stable]
** Bug fixes
cp --reflink=auto (the default), mv, and install
will again fall back to a standard copy in more cases.
Previously copies could fail with permission errors on
more restricted systems like android or containers etc.
[bug introduced in coreutils-9.2]
cp --recursive --backup will again operate correctly.
Previousy it may have issued "File exists" errors when
it failed to appropriately rename files being replaced.
[bug introduced in coreutils-9.2]
date --file and dircolors will now diagnose a failure to read a file.
Previously they would have silently ignored the failure.
[This bug was present in "the beginning".]
md5sum --check again correctly prints the status of each file checked.
Previously the status for files was printed as 'OK' once any file had passed.
This also applies to cksum, sha*sum, and b2sum.
[bug introduced in coreutils-9.2]
wc will now diagnose if any total counts have overflowed.
[This bug was present in "the beginning".]
`wc -c` will again correctly update the read offset of inputs.
Previously it deduced the size of inputs while leaving the offset unchanged.
[bug introduced in coreutils-8.27]
Coreutils programs no longer fail for timestamps past the year 2038
on obsolete configurations with 32-bit signed time_t, because the
build procedure now rejects these configurations.
[This bug was present in "the beginning".]
** Changes in behavior
'cp -n' and 'mv -n' now issue an error diagnostic if skipping a file,
to correspond with -n inducing a nonzero exit status as of coreutils 9.2.
Similarly 'cp -v' and 'mv -v' will output a message for each file skipped
due to -n, -i, or -u.
** New features
cp and mv now support --update=none to always skip existing files
in the destination, while not affecting the exit status.
This is equivalent to the --no-clobber behavior from before v9.2.
* Noteworthy changes in release 9.2 (2023-03-20) [stable]
** Bug fixes

View File

@@ -54,13 +54,13 @@ all mention of "[$(EXEEXT)" from src/Makefile.
32 bit time_t build failures
------------------------
On systems where it's determined that 64 bit time_t is supported
(indicated by touch -t <some time after 2038>), but that coreutils
would be built with a narrower time_t, the build will fail.
This can be allowed by passing TIME_T_32_BIT_OK=yes to configure,
or avoided by enabling 64 bit builds. For example GCC on AIX defaults
to 32 bit, and to enable the 64 bit ABI one can use:
./configure CFLAGS=-maix64 LDFLAGs=-maix64 AR='ar -X64'
Although 32-bit builds fail if that forces time_t to be 32 bits, this
can be fixed by using 64-bit builds. For example, on AIX where GCC
defaults to 32 bits, one can use "./configure CC='gcc -maix64' AR='ar
-X64'"; similarly, on Solaris one can configure with CC='gcc -m64'.
If all else fails one can configure with ac_year2038_required=no;
however, this will mishandle timestamps after 2038, and please file
bug reports for any such situations.
*************************************************

View File

@@ -318,7 +318,7 @@ gnulib_modules="
xstrtol-error
xstrtold
xstrtoumax
year2038
year2038-required
yesno
"

4
cfg.mk
View File

@@ -49,7 +49,7 @@ export VERBOSE = yes
# 4914152 9e
export XZ_OPT = -8e
old_NEWS_hash = ffba6793067438bae569f42acb4c5ab9
old_NEWS_hash = 72a8f8283d3c9daef72e06be5bb52734
# Add an exemption for sc_makefile_at_at_check.
_makefile_at_at_check_exceptions = ' && !/^cu_install_prog/ && !/dynamic-dep/'
@@ -844,7 +844,7 @@ exclude_file_name_regexp--sc_trailing_blank = \
exclude_file_name_regexp--sc_system_h_headers = \
^src/((die|system|copy|chown-core|find-mount-point)\.h|make-prime-list\.c)$$
_src = (crctab|false|lbracket|ls-(dir|ls|vdir)|tac-pipe|uname-(arch|uname))
_src = (false|lbracket|ls-(dir|ls|vdir)|tac-pipe|uname-(arch|uname))
_gl_src = (xdecto.max|cl-strtold)
exclude_file_name_regexp--sc_require_config_h_first = \
(^lib/buffer-lcm\.c|gl/lib/$(_gl_src)\.c|src/$(_src)\.c)$$

View File

@@ -9236,9 +9236,9 @@ results in an error message on systems that do not support symbolic links.
@optNoTargetDirectory
@item -u
@itemx --update
@itemx --update[=@var{which}]
@opindex -u
@opindex --update
@opindex --update[=@var{which}]
@cindex newer files, copying only
Do not copy a non-directory that has an existing destination with the
same or newer modification timestamp; instead, silently skip the file
@@ -9254,6 +9254,26 @@ for example), that will take precedence; consequently, depending on the
order that files are processed from the source, newer files in the destination
may be replaced, to mirror hard links in the source.
@macro whichUpdate
@var{which} gives more control over which existing files in the
destination are replaced, and its value can be one of the following:
@table @samp
@item all
This is the default operation when an @option{--update} option is not specified,
and results in all existing files in the destination being replaced.
@item none
This is similar to the @option{--no-clobber} option, in that no files in the
destination are replaced, but also skipping a file does not induce a failure.
@item older
This is the default operation when @option{--update} is specified, and results
in files being replaced if they're older than the corresponding source file.
@end table
@end macro
@whichUpdate
@item -v
@itemx --verbose
@opindex -v
@@ -10165,6 +10185,8 @@ of its permissions, and fail if the response is not affirmative.
Do not overwrite an existing file; silently fail instead.
@mvOptsIfn
This option is mutually exclusive with @option{-b} or @option{--backup} option.
See also the @option{--update=none} option which will
skip existing files but not fail.
@item --no-copy
@opindex --no-copy
@@ -10188,6 +10210,8 @@ same source and destination.
This option is ignored if the @option{-n} or @option{--no-clobber}
option is also specified.
@whichUpdate
@item -v
@itemx --verbose
@opindex -v

2
gnulib

Submodule gnulib updated: f17d397771...4b60490554

View File

@@ -116,8 +116,9 @@ main (void)
}
}
printf ("#include <stdint.h>\n\n");
printf ("uint_fast32_t const crctab[8][256] = {\n");
printf ("#include <config.h>\n");
printf ("#include <stdint.h>\n");
printf ("\nuint_fast32_t const crctab[8][256] = {\n");
for (int y = 0; y < 8; y++)
{
printf ("{\n 0x%08x", crctab[y][0]);

View File

@@ -146,6 +146,7 @@ enum copy_debug_val
COPY_DEBUG_NO,
COPY_DEBUG_YES,
COPY_DEBUG_EXTERNAL,
COPY_DEBUG_EXTERNAL_INTERNAL,
COPY_DEBUG_AVOIDED,
COPY_DEBUG_UNSUPPORTED,
};
@@ -179,6 +180,7 @@ copy_debug_sparse_string (enum copy_debug_val debug_val)
case COPY_DEBUG_NO: return "no";
case COPY_DEBUG_YES: return "zeros";
case COPY_DEBUG_EXTERNAL: return "SEEK_HOLE";
case COPY_DEBUG_EXTERNAL_INTERNAL: return "SEEK_HOLE + zeros";
default: return "unknown";
}
}
@@ -278,15 +280,28 @@ create_hole (int fd, char const *name, bool punch_holes, off_t size)
}
/* Whether the errno from FICLONE, or copy_file_range
indicates operation is not supported for this file or file system. */
/* Whether an errno value ERR, set by FICLONE or copy_file_range,
indicates that the copying operation has terminally failed, even
though it was invoked correctly (so that, e.g, EBADF cannot occur)
and even though !is_CLONENOTSUP (ERR). */
static bool
is_terminal_error (int err)
{
return err == EIO || err == ENOMEM || err == ENOSPC || err == EDQUOT;
}
/* Similarly, whether ERR indicates that the copying operation is not
supported or allowed for this file or process, even though the
operation was invoked correctly. */
static bool
is_CLONENOTSUP (int err)
{
return err == ENOSYS || is_ENOTSUP (err)
return err == ENOSYS || err == ENOTTY || is_ENOTSUP (err)
|| err == EINVAL || err == EBADF
|| err == EXDEV || err == ETXTBSY;
|| err == EXDEV || err == ETXTBSY
|| err == EPERM || err == EACCES;
}
@@ -312,6 +327,8 @@ sparse_copy (int src_fd, int dest_fd, char **abuf, size_t buf_size,
if (copy_debug.sparse_detection == COPY_DEBUG_UNKNOWN)
copy_debug.sparse_detection = hole_size ? COPY_DEBUG_YES : COPY_DEBUG_NO;
else if (hole_size && copy_debug.sparse_detection == COPY_DEBUG_EXTERNAL)
copy_debug.sparse_detection = COPY_DEBUG_EXTERNAL_INTERNAL;
/* If not looking for holes, use copy_file_range if functional,
but don't use if reflink disallowed as that may be implicit. */
@@ -339,20 +356,18 @@ sparse_copy (int src_fd, int dest_fd, char **abuf, size_t buf_size,
{
copy_debug.offload = COPY_DEBUG_UNSUPPORTED;
if (is_CLONENOTSUP (errno))
break;
/* copy_file_range might not be enabled in seccomp filters,
so retry with a standard copy. EPERM can also occur
for immutable files, but that would only be in the edge case
where the file is made immutable after creating/truncating,
/* Consider operation unsupported only if no data copied.
For example, EPERM could occur if copy_file_range not enabled
in seccomp filters, so retry with a standard copy. EPERM can
also occur for immutable files, but that would only be in the
edge case where the file is made immutable after creating,
in which case the (more accurate) error is still shown. */
if (errno == EPERM && *total_n_read == 0)
if (*total_n_read == 0 && is_CLONENOTSUP (errno))
break;
/* ENOENT was seen sometimes across CIFS shares, resulting in
no data being copied, but subsequent standard copies succeed. */
if (errno == ENOENT && *total_n_read == 0)
if (*total_n_read == 0 && errno == ENOENT)
break;
if (errno == EINTR)
@@ -1168,21 +1183,18 @@ fd_has_acl (int fd)
Return FALSE if it's a terminal failure for this file. */
static bool
handle_clone_fail (int dst_dirfd, char const* dst_relname,
char const* src_name, char const* dst_name,
handle_clone_fail (int dst_dirfd, char const *dst_relname,
char const *src_name, char const *dst_name,
int dest_desc, bool new_dst, enum Reflink_type reflink_mode)
{
/* If the clone operation is creating the destination,
then don't try and cater for all non transient file system errors,
and instead only cater for specific transient errors. */
bool transient_failure;
if (dest_desc < 0) /* currently for fclonefileat(). */
transient_failure = errno == EIO || errno == ENOMEM
|| errno == ENOSPC || errno == EDQUOT;
else /* currently for FICLONE. */
transient_failure = ! is_CLONENOTSUP (errno);
/* When the clone operation fails, report failure only with errno values
known to mean trouble when the clone is supported and called properly.
Do not report failure merely because !is_CLONENOTSUP (errno),
as systems may yield oddball errno values here with FICLONE,
and is_CLONENOTSUP is not appropriate for fclonefileat. */
bool report_failure = is_terminal_error (errno);
if (reflink_mode == REFLINK_ALWAYS || transient_failure)
if (reflink_mode == REFLINK_ALWAYS || report_failure)
error (0, errno, _("failed to clone %s from %s"),
quoteaf_n (0, dst_name), quoteaf_n (1, src_name));
@@ -1190,14 +1202,14 @@ handle_clone_fail (int dst_dirfd, char const* dst_relname,
but cloned no data. */
if (new_dst /* currently not for fclonefileat(). */
&& reflink_mode == REFLINK_ALWAYS
&& ((! transient_failure) || lseek (dest_desc, 0, SEEK_END) == 0)
&& ((! report_failure) || lseek (dest_desc, 0, SEEK_END) == 0)
&& unlinkat (dst_dirfd, dst_relname, 0) != 0 && errno != ENOENT)
error (0, errno, _("cannot remove %s"), quoteaf (dst_name));
if (! transient_failure)
if (! report_failure)
copy_debug.reflink = COPY_DEBUG_UNSUPPORTED;
if (reflink_mode == REFLINK_ALWAYS || transient_failure)
if (reflink_mode == REFLINK_ALWAYS || report_failure)
return false;
return true;
@@ -2053,6 +2065,7 @@ abandon_move (const struct cp_options *x,
{
assert (x->move_mode);
return (x->interactive == I_ALWAYS_NO
|| x->interactive == I_ALWAYS_SKIP
|| ((x->interactive == I_ASK_USER
|| (x->interactive == I_UNSPECIFIED
&& x->stdin_tty
@@ -2226,7 +2239,8 @@ copy_internal (char const *src_name, char const *dst_name,
if (rename_errno == 0
? !x->last_file
: rename_errno != EEXIST || x->interactive != I_ALWAYS_NO)
: rename_errno != EEXIST
|| (x->interactive != I_ALWAYS_NO && x->interactive != I_ALWAYS_SKIP))
{
char const *name = rename_errno == 0 ? dst_name : src_name;
int dirfd = rename_errno == 0 ? dst_dirfd : AT_FDCWD;
@@ -2280,7 +2294,9 @@ copy_internal (char const *src_name, char const *dst_name,
if (nonexistent_dst <= 0)
{
if (! (rename_errno == EEXIST && x->interactive == I_ALWAYS_NO))
if (! (rename_errno == EEXIST
&& (x->interactive == I_ALWAYS_NO
|| x->interactive == I_ALWAYS_SKIP)))
{
/* Regular files can be created by writing through symbolic
links, but other files cannot. So use stat on the
@@ -2321,8 +2337,10 @@ copy_internal (char const *src_name, char const *dst_name,
if (rename_errno == EEXIST)
{
bool return_now = false;
bool return_val = true;
bool skipped = false;
if (x->interactive != I_ALWAYS_NO
if ((x->interactive != I_ALWAYS_NO && x->interactive != I_ALWAYS_SKIP)
&& ! same_file_ok (src_name, &src_sb, dst_dirfd, drelname,
&dst_sb, x, &return_now))
{
@@ -2373,7 +2391,8 @@ copy_internal (char const *src_name, char const *dst_name,
}
}
return true;
skipped = true;
goto skip;
}
}
@@ -2392,21 +2411,38 @@ copy_internal (char const *src_name, char const *dst_name,
doesn't end up removing the source file. */
if (rename_succeeded)
*rename_succeeded = true;
return false;
skipped = true;
return_val = x->interactive == I_ALWAYS_SKIP;
}
}
else
{
if (! S_ISDIR (src_mode)
&& (x->interactive == I_ALWAYS_NO
|| x->interactive == I_ALWAYS_SKIP
|| (x->interactive == I_ASK_USER
&& ! overwrite_ok (x, dst_name, dst_dirfd,
dst_relname, &dst_sb))))
return false;
{
skipped = true;
return_val = x->interactive == I_ALWAYS_SKIP;
}
}
skip:
if (skipped)
{
if (x->verbose)
printf (_("skipped %s\n"), quoteaf (dst_name));
else if (x->interactive == I_ALWAYS_NO)
error (0, 0, _("not replacing %s"), quoteaf (dst_name));
return_now = true;
}
if (return_now)
return true;
return return_val;
if (!S_ISDIR (dst_sb.st_mode))
{

View File

@@ -57,11 +57,25 @@ enum Reflink_type
REFLINK_ALWAYS
};
/* Control how existing destination files are updated. */
enum Update_type
{
/* Always update.. */
UPDATE_ALL,
/* Update if dest older. */
UPDATE_OLDER,
/* Leave existing files. */
UPDATE_NONE,
};
/* This type is used to help mv (via copy.c) distinguish these cases. */
enum Interactive
{
I_ALWAYS_YES = 1,
I_ALWAYS_NO,
I_ALWAYS_NO, /* Skip and fail. */
I_ALWAYS_SKIP, /* Skip and ignore. */
I_ASK_USER,
I_UNSPECIFIED
};

View File

@@ -102,6 +102,16 @@ static enum Reflink_type const reflink_type[] =
};
ARGMATCH_VERIFY (reflink_type_string, reflink_type);
static char const *const update_type_string[] =
{
"all", "none", "older", NULL
};
static enum Update_type const update_type[] =
{
UPDATE_ALL, UPDATE_NONE, UPDATE_OLDER,
};
ARGMATCH_VERIFY (update_type_string, update_type);
static struct option const long_opts[] =
{
{"archive", no_argument, NULL, 'a'},
@@ -129,7 +139,7 @@ static struct option const long_opts[] =
{"suffix", required_argument, NULL, 'S'},
{"symbolic-link", no_argument, NULL, 's'},
{"target-directory", required_argument, NULL, 't'},
{"update", no_argument, NULL, 'u'},
{"update", optional_argument, NULL, 'u'},
{"verbose", no_argument, NULL, 'v'},
{GETOPT_SELINUX_CONTEXT_OPTION_DECL},
{GETOPT_HELP_OPTION_DECL},
@@ -182,8 +192,10 @@ Copy SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY.\n\
-L, --dereference always follow symbolic links in SOURCE\n\
"), stdout);
fputs (_("\
-n, --no-clobber do not overwrite an existing file (overrides\n\
a previous -i option)\n\
-n, --no-clobber do not overwrite an existing file (overrides a\n\
-u or previous -i option). See also --update\n\
"), stdout);
fputs (_("\
-P, --no-dereference never follow symbolic links in SOURCE\n\
"), stdout);
fputs (_("\
@@ -212,10 +224,14 @@ Copy SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY.\n\
-T, --no-target-directory treat DEST as a normal file\n\
"), stdout);
fputs (_("\
-u, --update copy only when the SOURCE file is newer\n\
than the destination file or when the\n\
destination file is missing\n\
--update[=UPDATE] control which existing files are updated;\n\
UPDATE={all,none,older(default)}. See below\n\
-u equivalent to --update[=older]\n\
"), stdout);
fputs (_("\
-v, --verbose explain what is being done\n\
"), stdout);
fputs (_("\
-x, --one-file-system stay on this file system\n\
"), stdout);
fputs (_("\
@@ -242,6 +258,7 @@ selected by --sparse=auto. Specify --sparse=always to create a sparse DEST\n\
file whenever the SOURCE file contains a long enough sequence of zero bytes.\n\
Use --sparse=never to inhibit creation of sparse files.\n\
"), stdout);
emit_update_parameters_note ();
fputs (_("\
\n\
When --reflink[=always] is specified, perform a lightweight copy, where the\n\
@@ -1103,7 +1120,30 @@ main (int argc, char **argv)
break;
case 'u':
x.update = true;
if (optarg == NULL)
x.update = true;
else if (x.interactive != I_ALWAYS_NO) /* -n takes precedence. */
{
enum Update_type update_opt;
update_opt = XARGMATCH ("--update", optarg,
update_type_string, update_type);
if (update_opt == UPDATE_ALL)
{
/* Default cp operation. */
x.update = false;
x.interactive = I_UNSPECIFIED;
}
else if (update_opt == UPDATE_NONE)
{
x.update = false;
x.interactive = I_ALWAYS_SKIP;
}
else if (update_opt == UPDATE_OLDER)
{
x.update = true;
x.interactive = I_UNSPECIFIED;
}
}
break;
case 'v':

View File

@@ -1,3 +1,4 @@
#include <config.h>
#include <stdint.h>
uint_fast32_t const crctab[8][256] = {

View File

@@ -368,7 +368,9 @@ batch_convert (char const *input_filename, char const *format,
ssize_t line_length = getline (&line, &buflen, in_stream);
if (line_length < 0)
{
/* FIXME: detect/handle error here. */
if (ferror (in_stream))
die (EXIT_FAILURE, errno, _("%s: read error"),
quotef (input_filename));
break;
}

View File

@@ -1254,14 +1254,14 @@ digest_check (char const *checkfile_name)
if (!status_only)
{
if ( ! matched_checksums || ! quiet)
if (! match || ! quiet)
{
if (needs_escape)
putchar ('\\');
print_filename (filename, needs_escape);
}
if ( ! matched_checksums)
if (! match)
printf (": %s\n", _("FAILED"));
else if (!quiet)
printf (": %s\n", _("OK"));

View File

@@ -298,6 +298,11 @@ dc_parse_stream (FILE *fp, char const *filename)
{
if (getline (&input_line, &input_line_size, fp) <= 0)
{
if (ferror (fp))
{
error (0, errno, _("%s: read error"), quotef (filename));
ok = false;
}
free (input_line);
break;
}

View File

@@ -24,6 +24,7 @@
#include <selinux/label.h>
#include "system.h"
#include "argmatch.h"
#include "backupfile.h"
#include "copy.h"
#include "cp-hash.h"
@@ -53,6 +54,16 @@ enum
STRIP_TRAILING_SLASHES_OPTION
};
static char const *const update_type_string[] =
{
"all", "none", "older", NULL
};
static enum Update_type const update_type[] =
{
UPDATE_ALL, UPDATE_NONE, UPDATE_OLDER,
};
ARGMATCH_VERIFY (update_type_string, update_type);
static struct option const long_options[] =
{
{"backup", optional_argument, NULL, 'b'},
@@ -66,7 +77,7 @@ static struct option const long_options[] =
{"strip-trailing-slashes", no_argument, NULL, STRIP_TRAILING_SLASHES_OPTION},
{"suffix", required_argument, NULL, 'S'},
{"target-directory", required_argument, NULL, 't'},
{"update", no_argument, NULL, 'u'},
{"update", optional_argument, NULL, 'u'},
{"verbose", no_argument, NULL, 'v'},
{GETOPT_HELP_OPTION_DECL},
{GETOPT_VERSION_OPTION_DECL},
@@ -277,15 +288,20 @@ If you specify more than one of -i, -f, -n, only the final one takes effect.\n\
fputs (_("\
-t, --target-directory=DIRECTORY move all SOURCE arguments into DIRECTORY\n\
-T, --no-target-directory treat DEST as a normal file\n\
-u, --update move only when the SOURCE file is newer\n\
than the destination file or when the\n\
destination file is missing\n\
"), stdout);
fputs (_("\
--update[=UPDATE] control which existing files are updated;\n\
UPDATE={all,none,older(default)}. See below\n\
-u equivalent to --update[=older]\n\
"), stdout);
fputs (_("\
-v, --verbose explain what is being done\n\
-Z, --context set SELinux security context of destination\n\
file to default type\n\
"), stdout);
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
emit_update_parameters_note ();
emit_backup_suffix_note ();
emit_ancillary_info (PROGRAM_NAME);
}
@@ -358,7 +374,30 @@ main (int argc, char **argv)
no_target_directory = true;
break;
case 'u':
x.update = true;
if (optarg == NULL)
x.update = true;
else if (x.interactive != I_ALWAYS_NO) /* -n takes precedence. */
{
enum Update_type update_opt;
update_opt = XARGMATCH ("--update", optarg,
update_type_string, update_type);
if (update_opt == UPDATE_ALL)
{
/* Default mv operation. */
x.update = false;
x.interactive = I_UNSPECIFIED;
}
else if (update_opt == UPDATE_NONE)
{
x.update = false;
x.interactive = I_ALWAYS_SKIP;
}
else if (update_opt == UPDATE_OLDER)
{
x.update = true;
x.interactive = I_UNSPECIFIED;
}
}
break;
case 'v':
x.verbose = true;

View File

@@ -608,6 +608,21 @@ Otherwise, units default to 1024 bytes (or 512 if POSIXLY_CORRECT is set).\n\
"), program);
}
static inline void
emit_update_parameters_note (void)
{
fputs (_("\
\n\
UPDATE controls which existing files in the destination are replaced.\n\
'all' is the default operation when an --update option is not specified,\n\
and results in all existing files in the destination being replaced.\n\
'none' is similar to the --no-clobber option, in that no files in the\n\
destination are replaced, but also skipped files do not induce a failure.\n\
'older' is the default operation when --update is specified, and results\n\
in files being replaced if they're older than the corresponding source file.\n\
"), stdout);
}
static inline void
emit_backup_suffix_note (void)
{

View File

@@ -78,6 +78,10 @@ static uintmax_t total_lines;
static uintmax_t total_words;
static uintmax_t total_chars;
static uintmax_t total_bytes;
static uintmax_t total_lines_overflow;
static uintmax_t total_words_overflow;
static uintmax_t total_chars_overflow;
static uintmax_t total_bytes_overflow;
static uintmax_t max_line_length;
/* Which counts to print. */
@@ -446,7 +450,10 @@ wc (int fd, char const *file_x, struct fstatus *fstatus, off_t current_pos)
beyond the end of the file. As in the example above. */
bytes = end_pos < current_pos ? 0 : end_pos - current_pos;
skip_read = true;
if (bytes && 0 <= lseek (fd, bytes, SEEK_CUR))
skip_read = true;
else
bytes = 0;
}
else
{
@@ -703,10 +710,16 @@ wc (int fd, char const *file_x, struct fstatus *fstatus, off_t current_pos)
if (total_mode != total_only)
write_counts (lines, words, chars, bytes, linelength, file_x);
total_lines += lines;
total_words += words;
total_chars += chars;
total_bytes += bytes;
if (INT_ADD_WRAPV (total_lines, lines, &total_lines))
total_lines_overflow = true;
if (INT_ADD_WRAPV (total_words, words, &total_words))
total_words_overflow = true;
if (INT_ADD_WRAPV (total_chars, chars, &total_chars))
total_chars_overflow = true;
if (INT_ADD_WRAPV (total_bytes, bytes, &total_bytes))
total_bytes_overflow = true;
if (linelength > max_line_length)
max_line_length = linelength;
@@ -1022,9 +1035,36 @@ main (int argc, char **argv)
if (total_mode != total_never
&& (total_mode != total_auto || 1 < argv_iter_n_args (ai)))
write_counts (total_lines, total_words, total_chars, total_bytes,
max_line_length,
total_mode != total_only ? _("total") : NULL);
{
if (total_lines_overflow)
{
total_lines = UINTMAX_MAX;
error (0, EOVERFLOW, _("total lines"));
ok = false;
}
if (total_words_overflow)
{
total_words = UINTMAX_MAX;
error (0, EOVERFLOW, _("total words"));
ok = false;
}
if (total_chars_overflow)
{
total_chars = UINTMAX_MAX;
error (0, EOVERFLOW, _("total characters"));
ok = false;
}
if (total_bytes_overflow)
{
total_bytes = UINTMAX_MAX;
error (0, EOVERFLOW, _("total bytes"));
ok = false;
}
write_counts (total_lines, total_words, total_chars, total_bytes,
max_line_length,
total_mode != total_only ? _("total") : NULL);
}
argv_iter_free (ai);

View File

@@ -1,5 +1,5 @@
#!/bin/sh
# Ensure that cp -b doesn't back up directories.
# Ensure that cp -b handles directories appropriately
# Copyright (C) 2006-2023 Free Software Foundation, Inc.
@@ -29,4 +29,10 @@ cp -ab x y || fail=1
test -d y/x || fail=1
test -d y/x~ && fail=1
# Bug 62607.
# This would fail to backup using rename, and thus fail to replace the file
mkdir -p src/foo dst/foo || framework_failure_
touch src/foo/bar dst/foo/bar || framework_failure_
cp --recursive --backup src/* dst || fail=1
Exit $fail

View File

@@ -28,12 +28,14 @@ echo n | returns_ 1 cp -iR a b 2>/dev/null || fail=1
# test miscellaneous combinations of -f -i -n parameters
touch c d || framework_failure_
echo "'c' -> 'd'" > out_copy
> out_empty
echo "'c' -> 'd'" > out_copy || framework_failure_
echo "skipped 'd'" > out_skip || framework_failure_
echo "cp: not replacing 'd'" > err_skip || framework_failure_
touch out_empty || framework_failure_
# ask for overwrite, answer no
echo n | returns_ 1 cp -vi c d 2>/dev/null > out1 || fail=1
compare out1 out_empty || fail=1
compare out1 out_skip || fail=1
# ask for overwrite, answer yes
echo y | cp -vi c d 2>/dev/null > out2 || fail=1
@@ -45,6 +47,11 @@ compare out3 out_copy || fail=1
# -n wins over -i
echo y | returns_ 1 cp -vin c d 2>/dev/null > out4 || fail=1
compare out4 out_skip || fail=1
# -n wins over -i non verbose
echo y | returns_ 1 cp -in c d 2>err4 > out4 || fail=1
compare err4 err_skip || fail=1
compare out4 out_empty || fail=1
# ask for overwrite, answer yes
@@ -53,11 +60,11 @@ compare out5 out_copy || fail=1
# do not ask, prevent from overwrite
echo n | returns_ 1 cp -vfn c d 2>/dev/null > out6 || fail=1
compare out6 out_empty || fail=1
compare out6 out_skip || fail=1
# do not ask, prevent from overwrite
echo n | returns_ 1 cp -vnf c d 2>/dev/null > out7 || fail=1
compare out7 out_empty || fail=1
compare out7 out_skip || fail=1
# options --backup and --no-clobber are mutually exclusive
returns_ 1 cp -bn c d 2>/dev/null || fail=1

View File

@@ -17,7 +17,7 @@
# along with this program. If not, see <https://www.gnu.org/licenses/>.
. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
print_ver_ cp stat dd
print_ver_ cp dd
touch sparse_chk
seek_data_capable_ sparse_chk \
@@ -44,18 +44,8 @@ printf x > k || framework_failure_
dd bs=1k seek=1 of=k count=255 < /dev/zero || framework_failure_
# cp should detect the all-zero blocks and convert some of them to holes.
# How many it detects/converts currently depends on io_blksize.
# Currently, on my F14/ext4 desktop, this K file starts off with size 256KiB,
# (note that the K in the preceding test starts off with size 4KiB).
# cp from coreutils-8.9 with --sparse=always reduces the size to 32KiB.
cp --reflink=never --sparse=always k k2 || fail=1
if test $(stat -c %b k2) -ge $(stat -c %b k); then
# If not sparse, then double check by creating with dd
# as we're not guaranteed that seek will create a hole.
# apfs on darwin 19.2.0 for example was seen to not to create holes < 16MiB.
hole_size=$(stat -c %o k2) || framework_failure_
dd if=k of=k2.dd bs=$hole_size conv=sparse || framework_failure_
test $(stat -c %b k2) -eq $(stat -c %b k2.dd) || fail=1
fi
cp --debug --reflink=never --sparse=always k k2 >cp.out || fail=1
cmp k k2 || fail=1
grep 'sparse detection: .*zeros' cp.out || { cat cp.out; fail=1; }
Exit $fail

View File

@@ -59,7 +59,9 @@ compare exp out || fail=1
# Perform this test only if "." is on a local file system.
# Otherwise, it would fail e.g., on an NFS-mounted Solaris ZFS file system.
if is_local_dir_ .; then
# Also skip local ZFS as that was seen to fail intermittently
# (perhaps due to async compression affecting allocations)
if is_local_dir_ . && ! df -T -t zfs .; then
rm -f out exp
du --block-size=$B -a d | sort -r -k2,2 > out || fail=1
echo === >> out

View File

@@ -302,9 +302,11 @@ all_tests = \
tests/misc/csplit-io-err.sh \
tests/misc/csplit-suppress-matched.pl \
tests/misc/date-debug.sh \
tests/misc/date-f.sh \
tests/misc/date-sec.sh \
tests/misc/date-tz.sh \
tests/misc/dircolors.pl \
tests/misc/dircolors.sh \
tests/misc/dirname.pl \
tests/misc/env-null.sh \
tests/misc/env-S.pl \

View File

@@ -25,7 +25,7 @@ vm=$(get_min_ulimit_v_ csplit -z f %n%1) \
|| skip_ "this shell lacks ulimit support"
(
ulimit -v $(($vm + 1000)) \
ulimit -v $(($vm + 4000)) \
&& { yes | head -n2500000; echo n; } | csplit -z - %n%1
) || fail=1

29
tests/misc/date-f.sh Executable file
View File

@@ -0,0 +1,29 @@
#!/bin/sh
# Verify -f processing
# Copyright (C) 2023 Free Software Foundation, Inc.
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
print_ver_ date
# Make sure date fails when it can't read input
# (the current directory in this case)
if ! cat . >/dev/null; then
# can't read() directories
returns_ 1 date -f . || fail=1
fi
Exit $fail

28
tests/misc/dircolors.sh Executable file
View File

@@ -0,0 +1,28 @@
#!/bin/sh
# Copyright (C) 2023 Free Software Foundation, Inc.
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
print_ver_ dircolors
# Make sure dircolors fails when it can't read input
# (the current directory in this case)
if ! cat . >/dev/null; then
# can't read() directories
returns_ 1 dircolors . || fail=1
fi
Exit $fail

View File

@@ -101,6 +101,16 @@ my @Tests =
. "md5sum: WARNING: 1 line is improperly formatted\n"
. "md5sum: WARNING: 2 computed checksums did NOT match\n"},
{EXIT=> 1}],
# Ensure we use appropriate state to track failures (broken in 9.2)
['check-multifail-state', '--check', '--warn',
{IN=>{'f.md5' =>
"$degenerate f\n"
. "$degenerate g\n"
. "$degenerate f\n" }},
{AUX=> {f=> ''}}, {AUX=> {g=> 'a'}},
{OUT=>"f: OK\ng: FAILED\nf: OK\n"},
{ERR=>"md5sum: WARNING: 1 computed checksum did NOT match\n"},
{EXIT=> 1}],
# The sha1sum and md5sum drivers share a lot of code.
# Ensure that md5sum does *not* share the part that makes
# sha1sum accept BSD format.

View File

@@ -79,9 +79,11 @@ test -f tee.exited || fail=1 ;;
esac
# Test with unwriteable files
touch file.ro || framework_failure_
chmod a-w file.ro || framework_failure_
returns_ 1 tee -p </dev/null file.ro || fail=1
if ! uid_is_privileged_; then # root does not get EPERM.
touch file.ro || framework_failure_
chmod a-w file.ro || framework_failure_
returns_ 1 tee -p </dev/null file.ro || fail=1
fi
mkfifo_or_skip_ fifo
@@ -97,7 +99,7 @@ dd count=20 bs=100K if=/dev/zero status=none |
dd count=0 oflag=nonblock status=none
tee || { cleanup_; touch tee.fail; }
} >fifo
test -f tee.fail && fail=1
test -f tee.fail && fail=1 || cleanup_
# Ensure tee honors --output-error modes
read_fifo() { timeout 10 dd count=1 if=fifo of=/dev/null status=none & }

View File

@@ -69,15 +69,19 @@ $@
{
my $exp = new Expect;
$exp->log_user(0);
$ENV{built_programs} =~ /\b$cmd\b/ || next;
my $cmd_name = (split(' ', $cmd))[0];
$ENV{built_programs} =~ /\b$cmd_name\b/ || next;
$exp->spawn("$cmd 2> $stderr")
or (warn "$ME: cannot run '$cmd': $!\n"), $fail=1, next;
# No input for cut -f2.
# Test cut in a different mode, even though it supports the standard flow
# Ensure that it exits with no input as it used to not do so
$cmd =~ /^cut/
or $exp->send("a b\n");
$exp->send("\cD"); # This is Control-D. FIXME: what if that's not EOF?
$exp->expect (0, '-re', "^a b\\r?\$");
my $found = $exp->expect (1, '-re', "^.+\$");
$cmd =~ /^cut/
or $exp->expect (0, '-re', "^a b\\r?\$");
$cmd =~ /^cut/
or my $found = $exp->expect (1, '-re', "^.+\$");
$found and warn "F: $found: " . $exp->exp_match () . "\n";
$exp->expect(10, 'eof');
# Expect no output from cut, since we gave it no input.

View File

@@ -42,6 +42,18 @@ cat <<\EOF > exp
EOF
compare exp out || fail=1
# Ensure we update the offset even when not reading,
# which wasn't the case from coreutils-8.27 to coreutils-9.2
{ wc -c; wc -c; } < no_read > out || fail=1
{ wc -c; wc -c; } < do_read >> out || fail=1
cat <<\EOF > exp
2
0
1048576
0
EOF
compare exp out || fail=1
# Ensure we don't read too much when reading,
# as was the case on 32 bit systems
# from coreutils-8.24 to coreutils-9.1

View File

@@ -18,6 +18,8 @@
. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
print_ver_ wc
require_sparse_support_ # for 'truncate --size=$BIG'
getlimits_
printf '%s\n' '2' > 2b || framework_failure_
printf '%s\n' '2 words' > 2w || framework_failure_
@@ -40,4 +42,19 @@ compare exp out || fail=1
wc --total=always 2b > out || fail=1
test "$(wc -l < out)" = 2 || fail=1
if truncate -s 2E big; then
if test "$UINTMAX_MAX" = '18446744073709551615'; then
# Ensure overflow is diagnosed
returns_ 1 wc --total=only -c big big big big big big big big \
> out || fail=1
# Ensure total is saturated
printf '%s\n' "$UINTMAX_MAX" > exp || framework_failure_
compare exp out || fail=1
# Ensure overflow is ignored if totals not shown
wc --total=never -c big big big big big big big big || fail=1
fi
fi
Exit $fail

View File

@@ -23,12 +23,14 @@ print_ver_ mv
# test miscellaneous combinations of -f -i -n parameters
touch a b || framework_failure_
echo "renamed 'a' -> 'b'" > out_move
echo "skipped 'b'" > out_skip || framework_failure_
echo "mv: not replacing 'b'" > err_skip || framework_failure_
> out_empty
# ask for overwrite, answer no
touch a b || framework_failure_
echo n | returns_ 1 mv -vi a b 2>/dev/null > out1 || fail=1
compare out1 out_empty || fail=1
compare out1 out_skip || fail=1
# ask for overwrite, answer yes
touch a b || framework_failure_
@@ -38,17 +40,23 @@ compare out2 out_move || fail=1
# -n wins (as the last option)
touch a b || framework_failure_
echo y | returns_ 1 mv -vin a b 2>/dev/null > out3 || fail=1
compare out3 out_skip || fail=1
# -n wins (non verbose)
touch a b || framework_failure_
echo y | returns_ 1 mv -in a b 2>err3 > out3 || fail=1
compare out3 out_empty || fail=1
compare err3 err_skip || fail=1
# -n wins (as the last option)
touch a b || framework_failure_
echo y | returns_ 1 mv -vfn a b 2>/dev/null > out4 || fail=1
compare out4 out_empty || fail=1
compare out4 out_skip || fail=1
# -n wins (as the last option)
touch a b || framework_failure_
echo y | returns_ 1 mv -vifn a b 2>/dev/null > out5 || fail=1
compare out5 out_empty || fail=1
compare out5 out_skip || fail=1
# options --backup and --no-clobber are mutually exclusive
touch a || framework_failure_

View File

@@ -19,11 +19,13 @@
. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
print_ver_ cp mv
echo old > old || framework_failure_
touch -d yesterday old || framework_failure_
echo new > new || framework_failure_
test_reset() {
echo old > old || framework_failure_
touch -d yesterday old || framework_failure_
echo new > new || framework_failure_
}
test_reset
for interactive in '' -i; do
for cp_or_mv in cp mv; do
# This is a no-op, with no prompt.
@@ -36,19 +38,32 @@ for interactive in '' -i; do
done
done
# This will actually perform the rename.
mv --update new old || fail=1
test -f new && fail=1
case "$(cat old)" in new) ;; *) fail=1 ;; esac
# These should perform the rename / copy
for update_option in '--update' '--update=older' '--update=all' \
'--update=none --update=all'; do
test_reset
mv $update_option new old || fail=1
test -f new && fail=1
case "$(cat old)" in new) ;; *) fail=1 ;; esac
# Restore initial conditions.
echo old > old || framework_failure_
touch -d yesterday old || fail=1
echo new > new || framework_failure_
test_reset
cp $update_option new old || fail=1
case "$(cat old)" in new) ;; *) fail=1 ;; esac
case "$(cat new)" in new) ;; *) fail=1 ;; esac
done
# This will actually perform the copy.
cp --update new old || fail=1
case "$(cat old)" in new) ;; *) fail=1 ;; esac
case "$(cat new)" in new) ;; *) fail=1 ;; esac
# These should not perform the rename / copy
for update_option in '--update=none' \
'--update=all --update=none'; do
test_reset
mv $update_option new old || fail=1
case "$(cat new)" in new) ;; *) fail=1 ;; esac
case "$(cat old)" in old) ;; *) fail=1 ;; esac
test_reset
cp $update_option new old || fail=1
case "$(cat new)" in new) ;; *) fail=1 ;; esac
case "$(cat old)" in old) ;; *) fail=1 ;; esac
done
Exit $fail