mirror of
https://git.freebsd.org/src.git
synced 2026-01-11 19:57:22 +00:00
fts: Add FTS_COMFOLLOWDIR and FTS_NOSTAT_TYPE.
MFC after: never Relnotes: yes Sponsored by: Klara, Inc. Reviewed by: kevans, imp Differential Revision: https://reviews.freebsd.org/D50233
This commit is contained in:
parent
bdc2ed1cf4
commit
da2025a0e8
3 changed files with 64 additions and 9 deletions
|
|
@ -65,7 +65,11 @@ typedef struct {
|
|||
#define FTS_SEEDOT 0x000020 /* return dot and dot-dot */
|
||||
#define FTS_XDEV 0x000040 /* don't cross devices */
|
||||
#define FTS_WHITEOUT 0x000080 /* return whiteout information */
|
||||
#define FTS_OPTIONMASK 0x0000ff /* valid user option mask */
|
||||
/* 0x0100 is FTS_NAMEONLY below */
|
||||
/* 0x0200 was previously FTS_STOP */
|
||||
#define FTS_COMFOLLOWDIR 0x00400 /* like COMFOLLOW but directories only */
|
||||
#define FTS_NOSTAT_TYPE 0x000800 /* like NOSTAT but use d_type */
|
||||
#define FTS_OPTIONMASK 0x000cff /* valid user option mask */
|
||||
|
||||
/* valid only for fts_children() */
|
||||
#define FTS_NAMEONLY 0x000100 /* child names only */
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@
|
|||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.Dd April 17, 2025
|
||||
.Dd May 7, 2025
|
||||
.Dt FTS 3
|
||||
.Os
|
||||
.Sh NAME
|
||||
|
|
@ -394,6 +394,10 @@ This option causes any symbolic link specified as a root path to be
|
|||
followed immediately whether or not
|
||||
.Dv FTS_LOGICAL
|
||||
is also specified.
|
||||
.It Dv FTS_COMFOLLOWDIR
|
||||
This option is similar to
|
||||
.Dv FTS_COMFOLLOW ,
|
||||
but only follows symbolic links to directories.
|
||||
.It Dv FTS_LOGICAL
|
||||
This option causes the
|
||||
.Nm
|
||||
|
|
@ -449,6 +453,15 @@ field to
|
|||
and leave the contents of the
|
||||
.Fa statp
|
||||
field undefined.
|
||||
.It Dv FTS_NOSTAT_TYPE
|
||||
This option is similar to
|
||||
.Dv FTS_NOSTAT ,
|
||||
but attempts to populate
|
||||
.Fa fts_info
|
||||
based on information from the
|
||||
.Fa d_type
|
||||
field of
|
||||
.Vt struct dirent .
|
||||
.It Dv FTS_PHYSICAL
|
||||
This option causes the
|
||||
.Nm
|
||||
|
|
@ -820,6 +833,13 @@ functions were introduced in
|
|||
principally to provide for alternative interfaces to the
|
||||
.Nm
|
||||
functionality using different data structures.
|
||||
Blocks support and the
|
||||
.Dv FTS_COMFOLLOWDIR
|
||||
and
|
||||
.Dv FTS_NOSTAT
|
||||
options were added in
|
||||
.Fx 15.0
|
||||
based on similar functionality in macOS.
|
||||
.Sh BUGS
|
||||
The
|
||||
.Fn fts_open
|
||||
|
|
|
|||
|
|
@ -126,6 +126,10 @@ __fts_open(FTS *sp, char * const *argv)
|
|||
if (ISSET(FTS_LOGICAL))
|
||||
SET(FTS_NOCHDIR);
|
||||
|
||||
/* NOSTAT_TYPE implies NOSTAT */
|
||||
if (ISSET(FTS_NOSTAT_TYPE))
|
||||
SET(FTS_NOSTAT);
|
||||
|
||||
/*
|
||||
* Start out with 1K of path space, and enough, in any case,
|
||||
* to hold the user's paths.
|
||||
|
|
@ -149,7 +153,9 @@ __fts_open(FTS *sp, char * const *argv)
|
|||
p->fts_level = FTS_ROOTLEVEL;
|
||||
p->fts_parent = parent;
|
||||
p->fts_accpath = p->fts_name;
|
||||
p->fts_info = fts_stat(sp, p, ISSET(FTS_COMFOLLOW), -1);
|
||||
p->fts_info = fts_stat(sp, p,
|
||||
ISSET(FTS_COMFOLLOWDIR) ? -1 : ISSET(FTS_COMFOLLOW),
|
||||
-1);
|
||||
|
||||
/* Command-line "." and ".." are real directories. */
|
||||
if (p->fts_info == FTS_DOT)
|
||||
|
|
@ -904,6 +910,25 @@ mem1: saved_errno = errno;
|
|||
p->fts_info == FTS_DC || p->fts_info == FTS_DOT))
|
||||
--nlinks;
|
||||
}
|
||||
if (p->fts_info == FTS_NSOK && ISSET(FTS_NOSTAT_TYPE)) {
|
||||
switch (dp->d_type) {
|
||||
case DT_FIFO:
|
||||
case DT_CHR:
|
||||
case DT_BLK:
|
||||
case DT_SOCK:
|
||||
p->fts_info = FTS_DEFAULT;
|
||||
break;
|
||||
case DT_REG:
|
||||
p->fts_info = FTS_F;
|
||||
break;
|
||||
case DT_LNK:
|
||||
p->fts_info = FTS_SL;
|
||||
break;
|
||||
case DT_WHT:
|
||||
p->fts_info = FTS_W;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* We walk in directory order so "ls -f" doesn't get upset. */
|
||||
p->fts_link = NULL;
|
||||
|
|
@ -980,7 +1005,7 @@ fts_stat(FTS *sp, FTSENT *p, int follow, int dfd)
|
|||
dev_t dev;
|
||||
ino_t ino;
|
||||
struct stat *sbp, sb;
|
||||
int saved_errno;
|
||||
int ret, saved_errno;
|
||||
const char *path;
|
||||
|
||||
if (dfd == -1) {
|
||||
|
|
@ -1003,19 +1028,25 @@ fts_stat(FTS *sp, FTSENT *p, int follow, int dfd)
|
|||
}
|
||||
|
||||
/*
|
||||
* If doing a logical walk, or application requested FTS_FOLLOW, do
|
||||
* a stat(2). If that fails, check for a non-existent symlink. If
|
||||
* fail, set the errno from the stat call.
|
||||
* If doing a logical walk, or caller requested FTS_COMFOLLOW, do
|
||||
* a full stat(2). If that fails, do an lstat(2) to check for a
|
||||
* non-existent symlink. If that fails, set the errno from the
|
||||
* stat(2) call.
|
||||
*
|
||||
* As a special case, if stat(2) succeeded but the target is not a
|
||||
* directory and follow is negative (indicating FTS_COMFOLLOWDIR
|
||||
* rather than FTS_COMFOLLOW), we also revert to lstat(2).
|
||||
*/
|
||||
if (ISSET(FTS_LOGICAL) || follow) {
|
||||
if (fstatat(dfd, path, sbp, 0)) {
|
||||
if ((ret = fstatat(dfd, path, sbp, 0)) != 0 ||
|
||||
(follow < 0 && !S_ISDIR(sbp->st_mode))) {
|
||||
saved_errno = errno;
|
||||
if (fstatat(dfd, path, sbp, AT_SYMLINK_NOFOLLOW)) {
|
||||
p->fts_errno = saved_errno;
|
||||
goto err;
|
||||
}
|
||||
errno = 0;
|
||||
if (S_ISLNK(sbp->st_mode))
|
||||
if (ret != 0 && S_ISLNK(sbp->st_mode))
|
||||
return (FTS_SLNONE);
|
||||
}
|
||||
} else if (fstatat(dfd, path, sbp, AT_SYMLINK_NOFOLLOW)) {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue