kern/134513: [patch] fts(3) FTS_NOCHDIR misbehavior with empty directory

Jaakko Heinonen jh at saunalahti.fi
Wed May 13 17:10:02 UTC 2009


>Number:         134513
>Category:       kern
>Synopsis:       [patch] fts(3) FTS_NOCHDIR misbehavior with empty directory
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Wed May 13 17:10:01 UTC 2009
>Closed-Date:
>Last-Modified:
>Originator:     Jaakko Heinonen
>Release:        FreeBSD 7.2-RELEASE / 8.0-CURRENT
>Organization:
>Environment:
FreeBSD 8.0-CURRENT r191987

>Description:
If you give an initial path name for fts_open() with trailing slash fts(3)
will strip the slash in post-order visit although the fts(3) manual page
states that the FTSENT structure will be unchanged from pre-order visit.
This happens only when the directory is empty and FTS_NOCHDIR option is used.

See also PR bin/133907.

>How-To-Repeat:
$ cc -Wall -Wextra -O ftstest.c -o ftstest
(Compile the test program below.)
$ mkdir x
$ ./ftstest x/
level: 0 path: x/ info: 1
level: 0 path: x info: 6
(Notice missing trailing slash in post-order.)

%%%
#include <sys/stat.h>
#include <sys/types.h>

#include <fts.h>
#include <stdio.h>

int
main(int argc, char **argv)
{
	FTS *fts;
	FTSENT *ftsent;
	char *fts_argv[] = {".", NULL};

	if (argc == 2)
		fts_argv[0] = argv[1];

	fts = fts_open(fts_argv, FTS_NOCHDIR | FTS_PHYSICAL, NULL);

	while ((ftsent = fts_read(fts)) != NULL) {
		printf("level: %ld path: %s info: %d\n",
		    (long)ftsent->fts_level,
		    ftsent->fts_path,
		    ftsent->fts_info);
	}

	fts_close(fts);

	return (0);
}
%%%

>Fix:
--- fts-NOCHDIR-trailing-slash.diff begins here ---
Index: lib/libc/gen/fts.3
===================================================================
--- lib/libc/gen/fts.3	(revision 191911)
+++ lib/libc/gen/fts.3	(working copy)
@@ -195,7 +195,7 @@ which was not specified as a file name t
 .Dv FTS_SEEDOT ) .
 .It Dv FTS_DP
 A directory being visited in post-order.
-The contents of the
+The other fields of the
 .Vt FTSENT
 structure will be unchanged from when
 it was returned in pre-order, i.e., with the
Index: lib/libc/gen/fts.c
===================================================================
--- lib/libc/gen/fts.c	(revision 191911)
+++ lib/libc/gen/fts.c	(working copy)
@@ -836,11 +836,8 @@ mem1:				saved_errno = errno;
 	 * 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
--- fts-NOCHDIR-trailing-slash.diff ends here ---

The patch also clarifies the manual page. fts_info info field has always
different value in post-order. Thus it's not exactly true that the structure
will be unchanged.


>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the freebsd-bugs mailing list