cp: Add an option to visit sources in order.
This adds a --sort option which makes cp pass a comparison function to FTS, ensuring that sources are visited and traversed in a predictable order. This will help make certain test cases more reliable. Sponsored by: Klara, Inc. Reviewed by: kevans Differential Revision: https://reviews.freebsd.org/D51214
This commit is contained in:
+12
@@ -184,6 +184,18 @@ If the source file has both its set-user-ID and set-group-ID bits on,
|
||||
and either the user ID or group ID cannot be preserved, neither
|
||||
the set-user-ID nor set-group-ID bits are preserved in the copy's
|
||||
permissions.
|
||||
.It Fl -sort
|
||||
Visit and traverse sources in (non-localized) lexicographical order.
|
||||
Normally,
|
||||
.Nm
|
||||
visits the sources in the order they were listed on the command line,
|
||||
and if recursing, traverses their contents in whichever order they
|
||||
were returned in by the kernel, which may be the order in which they
|
||||
were created, lexicographical order, or something else entirely.
|
||||
With
|
||||
.Fl -sort ,
|
||||
the sources are both visited and traversed in lexicographical order.
|
||||
This is mostly useful for testing.
|
||||
.It Fl s , Fl -symbolic-link
|
||||
Create symbolic links to regular files in a hierarchy instead of copying.
|
||||
.It Fl v , Fl -verbose
|
||||
|
||||
+12
-2
@@ -71,7 +71,7 @@ static char dot[] = ".";
|
||||
#define END(buf) (buf + sizeof(buf))
|
||||
PATH_T to = { .dir = -1, .end = to.path };
|
||||
bool Nflag, fflag, iflag, lflag, nflag, pflag, sflag, vflag;
|
||||
static bool Hflag, Lflag, Pflag, Rflag, rflag;
|
||||
static bool Hflag, Lflag, Pflag, Rflag, rflag, Sflag;
|
||||
volatile sig_atomic_t info;
|
||||
|
||||
enum op { FILE_TO_FILE, FILE_TO_DIR, DIR_TO_DNE };
|
||||
@@ -96,6 +96,7 @@ static const struct option long_opts[] =
|
||||
{ "symbolic-link", no_argument, NULL, 's' },
|
||||
{ "verbose", no_argument, NULL, 'v' },
|
||||
{ "one-file-system", no_argument, NULL, 'x' },
|
||||
{ "sort", no_argument, NULL, SORT_OPT },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
@@ -167,6 +168,9 @@ main(int argc, char *argv[])
|
||||
case 'x':
|
||||
fts_options |= FTS_XDEV;
|
||||
break;
|
||||
case SORT_OPT:
|
||||
Sflag = true;
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
@@ -284,6 +288,12 @@ main(int argc, char *argv[])
|
||||
&to_stat)));
|
||||
}
|
||||
|
||||
static int
|
||||
ftscmp(const FTSENT * const *a, const FTSENT * const *b)
|
||||
{
|
||||
return (strcmp((*a)->fts_name, (*b)->fts_name));
|
||||
}
|
||||
|
||||
static int
|
||||
copy(char *argv[], enum op type, int fts_options, struct stat *root_stat)
|
||||
{
|
||||
@@ -327,7 +337,7 @@ copy(char *argv[], enum op type, int fts_options, struct stat *root_stat)
|
||||
}
|
||||
|
||||
level = FTS_ROOTLEVEL;
|
||||
if ((ftsp = fts_open(argv, fts_options, NULL)) == NULL)
|
||||
if ((ftsp = fts_open(argv, fts_options, Sflag ? ftscmp : NULL)) == NULL)
|
||||
err(1, "fts_open");
|
||||
for (badcp = rval = 0;
|
||||
(curr = fts_read(ftsp)) != NULL;
|
||||
|
||||
@@ -657,7 +657,7 @@ unrdir_body()
|
||||
atf_check \
|
||||
-s exit:1 \
|
||||
-e match:"^cp: src/b: Permission denied" \
|
||||
cp -R src dst
|
||||
cp -R --sort src dst
|
||||
atf_check test -d dst/a
|
||||
atf_check cmp src/a/f dst/a/f
|
||||
atf_check test -d dst/b
|
||||
@@ -681,7 +681,7 @@ unrfile_body()
|
||||
atf_check \
|
||||
-s exit:1 \
|
||||
-e match:"^cp: src/b: Permission denied" \
|
||||
cp -R src dst
|
||||
cp -R --sort src dst
|
||||
atf_check test -d dst
|
||||
atf_check cmp src/a dst/a
|
||||
atf_check test ! -e dst/b
|
||||
|
||||
Reference in New Issue
Block a user