Use p->fts_level instead of unsuccessfully trying to keep track of the

level ourself.  We failed for unreadable directories.  E.g.,
`mtree -d -f /etc/mtree/BSD.usr.dist -p /usr' run by `nobody' was
confused after it couldn't descend into /usr/games/hide.  It looked
for /usr/include and subsequent directories in /usr/games.

Don't search for `extra' files when the spec depth is less than the
fts level.  The spec depth isn't incremented for leaf nodes because
that would give a NULL level pointer and make it inconvenient to go
back to the parent level.  Leaf nodes are built for directories that
are empty in the spec.  Since they are empty in the spec, all files
in them are extra.  The search looked for files one spec level
too high, so for `mtree -d -f /etc/mtree/BSD.usr.dist -p /usr',
obj/sbin matched ./sbin and wasn't considered extra, so it was
descended into and lots of bogus extra things in it were found.
This was harmful for `mtree -U' (as reported in pr623) and worse
for `mtree -r'.

Use rmdir(), not unlink(), to remove `extra' directories.  unlink()
succeeds for root but unlinking directories normally damages the
file system.

Report `fts_errno' instead of `errno' when the former applies.
This commit is contained in:
bde 1995-07-24 02:52:42 +00:00
parent cf2df4eb6c
commit 8bbc5ddb9f

View File

@ -74,7 +74,7 @@ vwalk()
register FTS *t;
register FTSENT *p;
register NODE *ep, *level;
int ftsdepth, specdepth, rval;
int specdepth, rval;
char *argv[2];
argv[0] = ".";
@ -82,15 +82,13 @@ vwalk()
if ((t = fts_open(argv, ftsoptions, NULL)) == NULL)
err("fts_open: %s", strerror(errno));
level = root;
ftsdepth = specdepth = rval = 0;
specdepth = rval = 0;
while ((p = fts_read(t))) {
switch(p->fts_info) {
case FTS_D:
++ftsdepth;
break;
case FTS_DP:
--ftsdepth;
if (specdepth > ftsdepth) {
if (specdepth > p->fts_level) {
for (level = level->parent; level->prev;
level = level->prev);
--specdepth;
@ -100,13 +98,15 @@ vwalk()
case FTS_ERR:
case FTS_NS:
(void)fprintf(stderr, "mtree: %s: %s\n",
RP(p), strerror(errno));
RP(p), strerror(p->fts_errno));
continue;
default:
if (dflag)
continue;
}
if (specdepth != p->fts_level)
goto extra;
for (ep = level; ep; ep = ep->next)
if ((ep->flags & F_MAGIC &&
!fnmatch(ep->name, p->fts_name, FNM_PATHNAME)) ||
@ -126,10 +126,12 @@ vwalk()
if (ep)
continue;
extra:
if (!eflag) {
(void)printf("extra: %s", RP(p));
if (rflag) {
if (unlink(p->fts_accpath)) {
if ((S_ISDIR(p->fts_statp->st_mode)
? rmdir : unlink)(p->fts_accpath)) {
(void)printf(", not removed: %s",
strerror(errno));
} else