diff --git a/bin/cp/cp.1 b/bin/cp/cp.1 --- a/bin/cp/cp.1 +++ b/bin/cp/cp.1 @@ -184,6 +184,18 @@ 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 diff --git a/bin/cp/cp.c b/bin/cp/cp.c --- a/bin/cp/cp.c +++ b/bin/cp/cp.c @@ -71,7 +71,7 @@ #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 @@ { "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 @@ case 'x': fts_options |= FTS_XDEV; break; + case SORT_OPT: + Sflag = true; + break; default: usage(); } @@ -284,6 +288,12 @@ &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 @@ } 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; diff --git a/bin/cp/tests/cp_test.sh b/bin/cp/tests/cp_test.sh --- a/bin/cp/tests/cp_test.sh +++ b/bin/cp/tests/cp_test.sh @@ -657,7 +657,7 @@ 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 @@ 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