* Fix FTS_NOCHDIR behavior on empty directory.
* Add -a option (archive mode, equivalent to -RpP)
* Add -l option (create hard links instead of copying)
* Add -x option (FS mount points are not traversed)
* Preserve file flags on symlinks on cp -Rp
* Don't copy socket anyway after "xxx is a socket (not copied)"
* Avoid division-by-zero situations
* make -r synonym for -R but maintain -r behavior with -L
Taken-from: FreeBSD (multiple commits)
https://bugs.dragonflybsd.org/issues/2443
+.\"-
.\" Copyright (c) 1989, 1990, 1993, 1994
.\" The Regents of the University of California. All rights reserved.
.\"
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
-.\" 3. All advertising materials mentioning features or use of this software
-.\" must display the following acknowledgement:
-.\" This product includes software developed by the University of
-.\" California, Berkeley and its contributors.
.\" 4. Neither the name of the University nor the names of its contributors
.\" may be used to endorse or promote products derived from this software
.\" without specific prior written permission.
.\" SUCH DAMAGE.
.\"
.\" @(#)cp.1 8.3 (Berkeley) 4/18/94
-.\" $FreeBSD: src/bin/cp/cp.1,v 1.33 2005/02/25 00:40:46 trhodes Exp $
-.\" $DragonFly: src/bin/cp/cp.1,v 1.6 2005/08/01 01:49:16 swildner Exp $
+.\" $FreeBSD$
.\"
-.Dd February 23, 2005
+.Dd November 15, 2012
.Dt CP 1
.Os
.Sh NAME
.Op Fl H | Fl L | Fl P
.Oc
.Op Fl f | i | n
-.Op Fl pv
+.Op Fl alpvx
.Ar source_file target_file
.Nm
.Oo
.Op Fl H | Fl L | Fl P
.Oc
.Op Fl f | i | n
-.Op Fl pv
+.Op Fl alpvx
.Ar source_file ... target_directory
.Sh DESCRIPTION
In the first synopsis form, the
or
.Xr pax 1
instead.
+.It Fl a
+Archive mode.
+Same as
+.Fl RpP .
.It Fl f
For each existing destination pathname, remove it and
create a new file, without prompting for confirmation
or
.Fl n
options.)
+.It Fl l
+Create hard links to regular files in a hierarchy instead of copying.
.It Fl n
Do not overwrite an existing file.
(The
Cause
.Nm
to be verbose, showing files as they are copied.
+.It Fl x
+File system mount points are not traversed.
.El
.Pp
For each destination file that already exists, its contents are
argument for
.Xr stty 1 )
signal, the current input and output file and the percentage complete
-will be written to standard error.
+will be written to the standard output.
.Sh EXIT STATUS
.Ex -std
.Sh COMPATIBILITY
utility had a
.Fl r
option.
-This implementation supports that option, however, its use is strongly
-discouraged, as it does not correctly copy special files, symbolic links
-or fifo's.
+This implementation supports that option, however, its behavior
+is different from historical
+.Dx
+behavior.
+Use of this option
+is strongly discouraged as the behavior is
+implementation-dependent.
+In
+.Dx ,
+.Fl r
+is a synonym for
+.Fl RL
+and works the same unless modified by other flags.
+Historical implementations
+of
+.Fl r
+differ as they copy special files as normal
+files while recreating a hierarchy.
.Pp
The
.Fl v
-/*
+/*-
* Copyright (c) 1988, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
- *
- * @(#) Copyright (c) 1988, 1993, 1994 The Regents of the University of California. All rights reserved.
- * @(#)cp.c 8.2 (Berkeley) 4/1/94
- * $FreeBSD: src/bin/cp/cp.c,v 1.51 2005/01/10 08:39:21 imp Exp $ $
- * $DragonFly: src/bin/cp/cp.c,v 1.12 2006/06/19 12:07:50 corecode Exp $
*/
/*
*--(p).p_end = 0; \
}
-PATH_T to = { to.p_path, to.p_path, "" };
+static char emptystring[] = "";
+
+PATH_T to = { to.p_path, emptystring, "" };
-int fflag, iflag, nflag, pflag, vflag;
+int fflag, iflag, lflag, nflag, pflag, vflag;
static int Rflag, rflag;
volatile sig_atomic_t info;
enum op { FILE_TO_FILE, FILE_TO_DIR, DIR_TO_DNE };
-static int copy (char **, enum op, int);
+static int copy(char *[], enum op, int);
static int mastercmp (const FTSENT * const *, const FTSENT * const *);
static void siginfo (int);
int
-main(int argc, char **argv)
+main(int argc, char *argv[])
{
struct stat to_stat, tmp_stat;
enum op type;
- int Hflag, Lflag, Pflag, ch, has_trailing_slash, r, fts_options;
+ int Hflag, Lflag, Pflag, ch, fts_options, r, have_trailing_slash;
char *target;
+ fts_options = FTS_NOCHDIR | FTS_PHYSICAL;
Hflag = Lflag = Pflag = 0;
- while ((ch = getopt(argc, argv, "HLPRfinprv")) != -1)
+ while ((ch = getopt(argc, argv, "HLPRafilnprvx")) != -1)
switch (ch) {
case 'H':
Hflag = 1;
case 'R':
Rflag = 1;
break;
+ case 'a':
+ Pflag = 1;
+ pflag = 1;
+ Rflag = 1;
+ Hflag = Lflag = 0;
+ break;
case 'f':
fflag = 1;
iflag = nflag = 0;
iflag = 1;
fflag = nflag = 0;
break;
+ case 'l':
+ lflag = 1;
+ break;
case 'n':
nflag = 1;
fflag = iflag = 0;
pflag = 1;
break;
case 'r':
- rflag = 1;
+ rflag = Lflag = 1;
+ Hflag = Pflag = 0;
break;
case 'v':
vflag = 1;
break;
+ case 'x':
+ fts_options |= FTS_XDEV;
+ break;
default:
usage();
break;
if (argc < 2)
usage();
- fts_options = FTS_NOCHDIR | FTS_PHYSICAL;
- if (rflag) {
- if (Rflag)
- errx(1,
- "the -R and -r options may not be specified together.");
- if (Hflag || Lflag || Pflag)
- errx(1,
- "the -H, -L, and -P options may not be specified with the -r option.");
- fts_options &= ~FTS_PHYSICAL;
- fts_options |= FTS_LOGICAL;
- }
+ if (Rflag && rflag)
+ errx(1, "the -R and -r options may not be specified together");
+ if (rflag)
+ Rflag = 1;
if (Rflag) {
if (Hflag)
fts_options |= FTS_COMFOLLOW;
fts_options &= ~FTS_PHYSICAL;
fts_options |= FTS_LOGICAL | FTS_COMFOLLOW;
}
- signal(SIGINFO, siginfo);
+ (void)signal(SIGINFO, siginfo);
/* Save the target base in "to". */
target = argv[--argc];
if (strlcpy(to.p_path, target, sizeof(to.p_path)) >= sizeof(to.p_path))
errx(1, "%s: name too long", target);
to.p_end = to.p_path + strlen(to.p_path);
- if (to.p_path == to.p_end) {
+ if (to.p_path == to.p_end) {
*to.p_end++ = '.';
*to.p_end = 0;
}
- has_trailing_slash = (to.p_end[-1] == '/');
- if (has_trailing_slash)
+ have_trailing_slash = (to.p_end[-1] == '/');
+ if (have_trailing_slash)
STRIP_TRAILING_SLASH(to);
to.target_end = to.p_end;
/*
* Case (1). Target is not a directory.
*/
- if (argc > 1) {
- usage();
- exit(1);
- }
+ if (argc > 1)
+ errx(1, "%s is not a directory", to.p_path);
+
/*
* Need to detect the case:
* cp -R dir foo
* the initial mkdir().
*/
if (r == -1) {
- if (rflag || (Rflag && (Lflag || Hflag)))
+ if (Rflag && (Lflag || Hflag))
stat(*argv, &tmp_stat);
else
lstat(*argv, &tmp_stat);
- if (S_ISDIR(tmp_stat.st_mode) && (Rflag || rflag))
+ if (S_ISDIR(tmp_stat.st_mode) && Rflag)
type = DIR_TO_DNE;
else
type = FILE_TO_FILE;
} else
type = FILE_TO_FILE;
- if (has_trailing_slash && type == FILE_TO_FILE) {
+ if (have_trailing_slash && type == FILE_TO_FILE) {
if (r == -1)
- errx(1, "directory %s does not exist", to.p_path);
+ errx(1, "directory %s does not exist",
+ to.p_path);
else
errx(1, "%s is not a directory", to.p_path);
}
}
static int
-copy(char **argv, enum op type, int fts_options)
+copy(char *argv[], enum op type, int fts_options)
{
struct stat to_stat;
FTS *ftsp;
FTSENT *curr;
- int base, dne, badcp, nlen, rval;
+ int base = 0, dne, badcp, rval;
+ size_t nlen;
char *p, *target_mid;
mode_t mask, mode;
*/
mask = ~umask(0777);
umask(~mask);
- base = 0;
if ((ftsp = fts_open(argv, fts_options, mastercmp)) == NULL)
- err(1, NULL);
+ err(1, "fts_open");
for (badcp = rval = 0; (curr = fts_read(ftsp)) != NULL; badcp = 0) {
switch (curr->fts_info) {
case FTS_NS:
warnx("%s: directory causes a cycle", curr->fts_path);
rval = 1;
continue;
+ default:
+ ;
}
/*
* If we are in case (2) or (3) above, we need to append the
- * source name to the target name.
- */
+ * source name to the target name.
+ */
if (type != FILE_TO_FILE) {
/*
* Need to remember the roots of traversals to create
rval = 1;
continue;
}
- strncat(target_mid, p, nlen);
+ (void)strncat(target_mid, p, nlen);
to.p_end = target_mid + nlen;
*to.p_end = 0;
STRIP_TRAILING_SLASH(to);
to.p_path, curr->fts_path);
rval = 1;
if (S_ISDIR(curr->fts_statp->st_mode))
- fts_set(ftsp, curr, FTS_SKIP);
+ (void)fts_set(ftsp, curr, FTS_SKIP);
continue;
}
if (!S_ISDIR(curr->fts_statp->st_mode) &&
S_ISDIR(to_stat.st_mode)) {
- warnx("cannot overwrite directory %s with non-directory %s",
+ warnx("cannot overwrite directory %s with "
+ "non-directory %s",
to.p_path, curr->fts_path);
rval = 1;
continue;
}
break;
case S_IFDIR:
- if (!Rflag && !rflag) {
+ if (!Rflag) {
warnx("%s is a directory (not copied).",
curr->fts_path);
- fts_set(ftsp, curr, FTS_SKIP);
+ (void)fts_set(ftsp, curr, FTS_SKIP);
badcp = rval = 1;
break;
}
badcp = rval = 1;
}
break;
+ case S_IFSOCK:
+ warnx("%s is a socket (not copied).",
+ curr->fts_path);
+ break;
case S_IFIFO:
if (Rflag) {
if (copy_fifo(curr->fts_statp, !dne))
break;
}
if (vflag && !badcp)
- printf("%s -> %s\n", curr->fts_path, to.p_path);
+ (void)printf("%s -> %s\n", curr->fts_path, to.p_path);
}
if (errno)
err(1, "fts_read");
}
static void
-siginfo(int notused __unused)
+siginfo(int sig __unused)
{
info = 1;
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
* SUCH DAMAGE.
*
* @(#)extern.h 8.2 (Berkeley) 4/1/94
- * $FreeBSD: src/bin/cp/extern.h,v 1.19 2004/04/06 20:06:44 markm $
- * $DragonFly: src/bin/cp/extern.h,v 1.5 2005/02/28 23:15:35 corecode Exp $
+ * $FreeBSD$
*/
typedef struct {
} PATH_T;
extern PATH_T to;
-extern int fflag, iflag, nflag, pflag, vflag;
+extern int fflag, iflag, lflag, nflag, pflag, vflag;
extern volatile sig_atomic_t info;
__BEGIN_DECLS
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
- *
- * @(#)utils.c 8.3 (Berkeley) 4/1/94
- * $FreeBSD: src/bin/cp/utils.c,v 1.45 2005/02/09 17:37:37 ru Exp $
- * $DragonFly: src/bin/cp/utils.c,v 1.12 2008/09/05 03:16:55 y0netan1 Exp $
*/
#include <sys/param.h>
#include <unistd.h>
#include "extern.h"
-#define cp_pct(x,y) (int)(100.0 * (double)(x) / (double)(y))
-#define YESNO "(y/n [n]) "
+#define cp_pct(x, y) ((y == 0) ? 0 : (int)(100.0 * (x) / (y)))
+
int
copy_file(const FTSENT *entp, int dne)
{
static char buf[MAXBSIZE];
struct stat *fs;
- int ch, checkch, from_fd, rval, to_fd;
- size_t rcount, wcount, wresid;
+ ssize_t wcount, rcount;
+ size_t wresid;
off_t wtotal;
+ int ch, checkch, from_fd = 0, rval, to_fd = 0;
char *bufp;
#ifdef VM_AND_BUFFER_CACHE_SYNCHRONIZED
char *p;
* modified by the umask.)
*/
if (!dne) {
+#define YESNO "(y/n [n]) "
if (nflag) {
if (vflag)
printf("%s not overwritten\n", to.p_path);
- close(from_fd);
+ (void)close(from_fd);
return (0);
} else if (iflag) {
- fprintf(stderr, "overwrite %s? %s",
+ (void)fprintf(stderr, "overwrite %s? %s",
to.p_path, YESNO);
checkch = ch = getchar();
while (ch != '\n' && ch != EOF)
ch = getchar();
if (checkch != 'y' && checkch != 'Y') {
- close(from_fd);
- fprintf(stderr, "not overwritten\n");
+ (void)close(from_fd);
+ (void)fprintf(stderr, "not overwritten\n");
return (1);
}
}
if (fflag) {
/* remove existing destination file name,
* create a new file */
- unlink(to.p_path);
- to_fd = open(to.p_path, O_WRONLY | O_TRUNC | O_CREAT,
- fs->st_mode & ~(S_ISUID | S_ISGID));
- } else
- /* overwrite existing destination file name */
- to_fd = open(to.p_path, O_WRONLY | O_TRUNC, 0);
- } else
- to_fd = open(to.p_path, O_WRONLY | O_TRUNC | O_CREAT,
- fs->st_mode & ~(S_ISUID | S_ISGID));
+ (void)unlink(to.p_path);
+ if (!lflag)
+ to_fd = open(to.p_path, O_WRONLY | O_TRUNC | O_CREAT,
+ fs->st_mode & ~(S_ISUID | S_ISGID));
+ } else {
+ if (!lflag)
+ /* overwrite existing destination file name */
+ to_fd = open(to.p_path, O_WRONLY | O_TRUNC, 0);
+ }
+ } else {
+ if (!lflag)
+ to_fd = open(to.p_path, O_WRONLY | O_TRUNC | O_CREAT,
+ fs->st_mode & ~(S_ISUID | S_ISGID));
+ }
if (to_fd == -1) {
warn("%s", to.p_path);
- close(from_fd);
+ (void)close(from_fd);
return (1);
}
rval = 0;
+ if (!lflag) {
/*
- * Mmap and write if less than 8M (the limit is so we don't totally
- * trash memory on big files. This is really a minor hack, but it
- * wins some CPU back.
+ * Mmap and write if less than 8M (the limit is so we don't totally
+ * trash memory on big files. This is really a minor hack, but it
+ * wins some CPU back.
+ * Some filesystems, such as smbnetfs, don't support mmap,
+ * so this is a best-effort attempt.
*/
#ifdef VM_AND_BUFFER_CACHE_SYNCHRONIZED
- if (S_ISREG(fs->st_mode) && fs->st_size > 0 &&
- fs->st_size <= 8 * 1048576) {
- if ((p = mmap(NULL, (size_t)fs->st_size, PROT_READ,
- MAP_SHARED, from_fd, (off_t)0)) == MAP_FAILED) {
- warn("%s", entp->fts_path);
- rval = 1;
- } else {
+ if (S_ISREG(fs->st_mode) && fs->st_size > 0 &&
+ fs->st_size <= 8 * 1024 * 1024 &&
+ (p = mmap(NULL, (size_t)fs->st_size, PROT_READ,
+ MAP_SHARED, from_fd, (off_t)0)) != MAP_FAILED) {
wtotal = 0;
for (bufp = p, wresid = fs->st_size; ;
- bufp += wcount, wresid -= wcount) {
+ bufp += wcount, wresid -= (size_t)wcount) {
wcount = write(to_fd, bufp, wresid);
- if ((ssize_t)wcount == -1)
+ if (wcount <= 0)
break;
wtotal += wcount;
if (info) {
info = 0;
- fprintf(stderr,
+ (void)fprintf(stderr,
"%s -> %s %3d%%\n",
entp->fts_path, to.p_path,
cp_pct(wtotal, fs->st_size));
}
- if (wcount >= wresid || wcount == 0)
+ if (wcount >= (ssize_t)wresid)
break;
}
- if (wcount != wresid) {
+ if (wcount != (ssize_t)wresid) {
warn("%s", to.p_path);
rval = 1;
}
warn("%s", entp->fts_path);
rval = 1;
}
- }
- } else
+ } else
#endif
- {
- wtotal = 0;
- while ((ssize_t)(rcount = read(from_fd, buf, MAXBSIZE)) > 0) {
- for (bufp = buf, wresid = rcount; ;
- bufp += wcount, wresid -= wcount) {
- wcount = write(to_fd, bufp, wresid);
- if ((ssize_t)wcount == -1)
- break;
- wtotal += wcount;
- if (info) {
- info = 0;
- fprintf(stderr,
- "%s -> %s %3d%%\n",
- entp->fts_path, to.p_path,
- cp_pct(wtotal, fs->st_size));
+ {
+ wtotal = 0;
+ while ((rcount = read(from_fd, buf, MAXBSIZE)) > 0) {
+ for (bufp = buf, wresid = rcount; ;
+ bufp += wcount, wresid -= wcount) {
+ wcount = write(to_fd, bufp, wresid);
+ if (wcount <= 0)
+ break;
+ wtotal += wcount;
+ if (info) {
+ info = 0;
+ (void)fprintf(stderr,
+ "%s -> %s %3d%%\n",
+ entp->fts_path, to.p_path,
+ cp_pct(wtotal, fs->st_size));
+ }
+ if (wcount >= (ssize_t)wresid)
+ break;
}
- if (wcount >= wresid || wcount == 0)
+ if (wcount != (ssize_t)wresid) {
+ warn("%s", to.p_path);
+ rval = 1;
break;
+ }
}
- if (wcount != wresid) {
- warn("%s", to.p_path);
+ if (rcount < 0) {
+ warn("%s", entp->fts_path);
rval = 1;
- break;
}
}
- if ((ssize_t)rcount == -1) {
- warn("%s", entp->fts_path);
+ } else {
+ if (link(entp->fts_path, to.p_path)) {
+ warn("%s", to.p_path);
rval = 1;
}
}
* to remove it if we created it and its length is 0.
*/
- if (pflag && setfile(fs, to_fd))
- rval = 1;
- close(from_fd);
- if (close(to_fd)) {
- warn("%s", to.p_path);
- rval = 1;
+ if (!lflag) {
+ if (pflag && setfile(fs, to_fd))
+ rval = 1;
+ if (close(to_fd)) {
+ warn("%s", to.p_path);
+ rval = 1;
+ }
}
+
+ (void)close(from_fd);
+
return (rval);
}
copy_link(const FTSENT *p, int exists)
{
int len;
- char linkname[PATH_MAX];
+ char llink[PATH_MAX];
- if ((len = readlink(p->fts_path, linkname, sizeof(linkname) - 1)) == -1) {
+ if ((len = readlink(p->fts_path, llink, sizeof(llink) - 1)) == -1) {
warn("readlink: %s", p->fts_path);
return (1);
}
- linkname[len] = '\0';
+ llink[len] = '\0';
if (exists && unlink(to.p_path)) {
warn("unlink: %s", to.p_path);
return (1);
}
- if (symlink(linkname, to.p_path)) {
- warn("symlink: %s", linkname);
+ if (symlink(llink, to.p_path)) {
+ warn("symlink: %s", llink);
return (1);
}
return (pflag ? setfile(p->fts_statp, -1) : 0);
rval = 1;
}
if (fdval ? fstat(fd, &ts) :
- (islink ? lstat(to.p_path, &ts) : stat(to.p_path, &ts))) {
+ (islink ? lstat(to.p_path, &ts) : stat(to.p_path, &ts)))
gotstat = 0;
- } else {
+ else {
gotstat = 1;
ts.st_mode &= S_ISUID | S_ISGID | S_ISVTX |
S_IRWXU | S_IRWXG | S_IRWXO;
if (!gotstat || fs->st_flags != ts.st_flags)
if (fdval ?
fchflags(fd, fs->st_flags) :
- (islink ? (errno = 0) :
+ (islink ? lchflags(to.p_path, fs->st_flags) :
chflags(to.p_path, fs->st_flags))) {
warn("chflags: %s", to.p_path);
rval = 1;
void
usage(void)
{
- fprintf(stderr, "%s\n%s\n",
-"usage: cp [-R [-H | -L | -P]] [-f | -i | -n] [-pv] source_file target_file",
-" cp [-R [-H | -L | -P]] [-f | -i | -n] [-pv] source_file ... "
+
+ (void)fprintf(stderr, "%s\n%s\n",
+"usage: cp [-R [-H | -L | -P]] [-f | -i | -n] [-alpvx] source_file target_file",
+" cp [-R [-H | -L | -P]] [-f | -i | -n] [-alpvx] source_file ... "
"target_directory");
exit(EX_USAGE);
}
* @(#)fts.c 8.6 (Berkeley) 8/14/94
* $OpenBSD: fts.c,v 1.22 1999/10/03 19:22:22 millert Exp $
* $FreeBSD: src/lib/libc/gen/fts.c,v 1.30 2009/03/04 03:30:21 das Exp $
- * $DragonFly: src/lib/libc/gen/fts.c,v 1.7 2005/11/13 00:07:42 swildner Exp $
*/
#include "namespace.h"
}
/* Allocate/initialize the stream. */
- if ((priv = malloc(sizeof(*priv))) == NULL)
+ if ((priv = calloc(1, sizeof(*priv))) == NULL)
return (NULL);
- memset(priv, 0, sizeof(*priv));
sp = &priv->ftsp_fts;
sp->fts_compar = compar;
sp->fts_options = options;
* If not changing directories, reset the path back to original
* state.
*/
- if (ISSET(FTS_NOCHDIR)) {
- if (len == sp->fts_pathlen || nitems == 0)
- --cp;
- *cp = '\0';
- }
+ if (ISSET(FTS_NOCHDIR))
+ sp->fts_path[cur->fts_pathlen] = '\0';
/*
* If descended after called from fts_children or after called from