Bug 226166

Summary: [PATCH] fts(3): setting FTS_FOLLOW for children does not work as expected when FTS_NOCHDIR is set
Product: Base System Reporter: Jan Kokemüller <jan.kokemueller>
Component: binAssignee: freebsd-bugs (Nobody) <bugs>
Status: New ---    
Severity: Affects Some People CC: cem
Priority: --- Keywords: patch
Version: CURRENT   
Hardware: Any   
OS: Any   
Attachments:
Description Flags
patch to fix FTS_FOLLOW when set on entries returned by fts_children() none

Description Jan Kokemüller 2018-02-24 13:11:01 UTC
Created attachment 190957 [details]
patch to fix FTS_FOLLOW when set on entries returned by fts_children()

Reading the fts(3) man page something like the example below should work. This sets FTS_FOLLOW on a child named 'symlink' which is a symlink to another folder. fts_read will now recurse into this folder, even though FTS_PHYSICAL is set. Right now it won't recurse, however, when FTS_NOCHDIR is also set.

The problem is a stale fts_accpath. This leads to fts_stat() calling stat on the wrong file. The attached patch attempts to fix this by switching the order of the fts_stat() and the fts_accpath update.



#include <err.h>
#include <fts.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

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

	fts = fts_open(fts_args, FTS_PHYSICAL | FTS_NOCHDIR, NULL);
	if (!fts) {
		err(1, "fts");
	}

	while ((ftsent = fts_read(fts))) {
		fprintf(stderr, "got file: %s\n", ftsent->fts_path);

		children = fts_children(fts, 0);

		for (FTSENT *child = children; child;
		     child = child->fts_link) {
			if (!strcmp("symlink", child->fts_name)) {
				if (fts_set(fts, child, FTS_FOLLOW)) {
					err(1, "fts_set");
				}
			}
		}
	}

	if (fts_close(fts) < 0) {
		warn("fts_close");
	}
}