Skip to content

Commit a662fda

Browse files
committed
parse: Only process the last -files0-from
GNU find intentionally makes later -files0-from options override earlier ones, for symmetry with similar features like du --files0-from. Change bfs to match. Link: https://savannah.gnu.org/bugs/?66965
1 parent b1fe972 commit a662fda

14 files changed

Lines changed: 168 additions & 61 deletions

src/parse.c

Lines changed: 68 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,6 @@ struct bfs_parser {
8484
enum use_color use_color;
8585
/** Whether a -print action is implied. */
8686
bool implicit_print;
87-
/** Whether the default root "." should be used. */
88-
bool implicit_root;
8987
/** Whether the expression has started. */
9088
bool expr_started;
9189
/** Whether an information option like -help or -version was passed. */
@@ -105,6 +103,8 @@ struct bfs_parser {
105103
const struct bfs_expr *mount_expr;
106104
/** An "-xdev" expression, if any. */
107105
const struct bfs_expr *xdev_expr;
106+
/** A "-files0-from" expression, if any. */
107+
const struct bfs_expr *files0_expr;
108108
/** An expression that consumes stdin, if any. */
109109
const struct bfs_expr *stdin_expr;
110110

@@ -427,7 +427,6 @@ static int parse_root(struct bfs_parser *parser, const char *path) {
427427
return -1;
428428
}
429429

430-
parser->implicit_root = false;
431430
return 0;
432431
}
433432

@@ -1351,51 +1350,14 @@ static struct bfs_expr *parse_files0_from(struct bfs_parser *parser, int arg1, i
13511350
return NULL;
13521351
}
13531352

1354-
const char *from = expr->argv[1];
1355-
1356-
FILE *file;
1357-
if (strcmp(from, "-") == 0) {
1358-
if (!consume_stdin(parser, expr)) {
1359-
return NULL;
1360-
}
1361-
file = stdin;
1362-
} else {
1363-
file = xfopen(from, O_RDONLY | O_CLOEXEC);
1364-
}
1365-
if (!file) {
1366-
parse_expr_error(parser, expr, "%s.\n", errstr());
1367-
return NULL;
1368-
}
1369-
1370-
while (true) {
1371-
char *path = xgetdelim(file, '\0');
1372-
if (!path) {
1373-
if (errno) {
1374-
goto fail;
1375-
} else {
1376-
break;
1377-
}
1378-
}
1379-
1380-
int ret = parse_root(parser, path);
1381-
free(path);
1382-
if (ret != 0) {
1383-
goto fail;
1384-
}
1385-
}
1386-
1387-
if (file != stdin) {
1388-
fclose(file);
1389-
}
1390-
1391-
parser->implicit_root = false;
1353+
// For compatibility with GNU find,
1354+
//
1355+
// bfs -files0-from a -files0-from b
1356+
//
1357+
// should *only* use b, not a. So stash the expression here and only
1358+
// process the last one at the end of parsing.
1359+
parser->files0_expr = expr;
13921360
return expr;
1393-
1394-
fail:
1395-
if (file != stdin) {
1396-
fclose(file);
1397-
}
1398-
return NULL;
13991361
}
14001362

14011363
/**
@@ -3546,6 +3508,55 @@ static struct bfs_expr *parse_expr(struct bfs_parser *parser) {
35463508
return expr;
35473509
}
35483510

3511+
/** Handle -files0-from after parsing. */
3512+
static int parse_files0_roots(struct bfs_parser *parser) {
3513+
const struct bfs_expr *expr = parser->files0_expr;
3514+
const char *from = expr->argv[1];
3515+
3516+
FILE *file;
3517+
if (strcmp(from, "-") == 0) {
3518+
if (!consume_stdin(parser, expr)) {
3519+
return -1;
3520+
}
3521+
file = stdin;
3522+
} else {
3523+
file = xfopen(from, O_RDONLY | O_CLOEXEC);
3524+
}
3525+
if (!file) {
3526+
parse_expr_error(parser, expr, "%s.\n", errstr());
3527+
return -1;
3528+
}
3529+
3530+
while (true) {
3531+
char *path = xgetdelim(file, '\0');
3532+
if (!path) {
3533+
if (errno) {
3534+
goto fail;
3535+
} else {
3536+
break;
3537+
}
3538+
}
3539+
3540+
int ret = parse_root(parser, path);
3541+
free(path);
3542+
if (ret != 0) {
3543+
goto fail;
3544+
}
3545+
}
3546+
3547+
if (file != stdin) {
3548+
fclose(file);
3549+
}
3550+
3551+
return 0;
3552+
3553+
fail:
3554+
if (file != stdin) {
3555+
fclose(file);
3556+
}
3557+
return -1;
3558+
}
3559+
35493560
/**
35503561
* Parse the top-level expression.
35513562
*/
@@ -3571,6 +3582,16 @@ static struct bfs_expr *parse_whole_expr(struct bfs_parser *parser) {
35713582
return NULL;
35723583
}
35733584

3585+
if (parser->files0_expr) {
3586+
if (parse_files0_roots(parser) != 0) {
3587+
return NULL;
3588+
}
3589+
} else if (ctx->npaths == 0) {
3590+
if (parse_root(parser, ".") != 0) {
3591+
return NULL;
3592+
}
3593+
}
3594+
35743595
if (parser->implicit_print) {
35753596
const struct bfs_expr *limit = parser->limit_expr;
35763597
if (limit) {
@@ -3842,7 +3863,6 @@ struct bfs_ctx *bfs_parse_cmdline(int argc, char *argv[]) {
38423863
.stdout_tty = stdout_tty,
38433864
.use_color = use_color,
38443865
.implicit_print = true,
3845-
.implicit_root = true,
38463866
.just_info = false,
38473867
.excluding = false,
38483868
.last_arg = NULL,
@@ -3879,12 +3899,6 @@ struct bfs_ctx *bfs_parse_cmdline(int argc, char *argv[]) {
38793899
goto fail;
38803900
}
38813901

3882-
if (ctx->npaths == 0 && parser.implicit_root) {
3883-
if (parse_root(&parser, ".") != 0) {
3884-
goto fail;
3885-
}
3886-
}
3887-
38883902
if ((ctx->flags & BFTW_FOLLOW_ALL) && !ctx->unique) {
38893903
// We need bftw() to detect cycles unless -unique does it for us
38903904
ctx->flags |= BFTW_DETECT_CYCLES;

tests/bfs/files0_from_stdin_twice.sh

Lines changed: 0 additions & 1 deletion
This file was deleted.

tests/gnu/files0_from_empty.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
! printf "\0" | invoke_bfs -files0-from -
1+
! printf '\0' | invoke_bfs -files0-from -
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,2 @@
1-
basic/c
2-
basic/c/d
31
basic/g
42
basic/g/h

tests/gnu/files0_from_ok.sh

Lines changed: 0 additions & 1 deletion
This file was deleted.

tests/gnu/files0_from_stdin_ok.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
! printf 'basic\0' | invoke_bfs -files0-from - -ok echo {} \;
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
2+
3+
4+
5+
6+
/j
7+
/j
8+
!
9+
!-
10+
!-/e
11+
!-/e
12+
!/d
13+
!/d
14+
(
15+
(-
16+
(-/c
17+
(-/c
18+
(/b
19+
(/b
20+
)
21+
)/g
22+
)/g
23+
*
24+
*/m
25+
*/m
26+
,
27+
,/f
28+
,/f
29+
-
30+
-/a
31+
-/a
32+
...
33+
.../h
34+
.../h
35+
/n
36+
/n
37+
[
38+
[/k
39+
[/k
40+
\
41+
\/i
42+
\/i
43+
{
44+
{/l
45+
{/l
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
FILE="$TMP/$TEST.in"
2+
cd weirdnames
3+
invoke_bfs -mindepth 1 -fprintf "$FILE" "%P\0"
4+
yes | bfs_diff -files0-from - -ok printf '%s\n' {} \; -files0-from "$FILE"
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
2+
3+
4+
5+
6+
/j
7+
/j
8+
!
9+
!-
10+
!-/e
11+
!-/e
12+
!/d
13+
!/d
14+
(
15+
(-
16+
(-/c
17+
(-/c
18+
(/b
19+
(/b
20+
)
21+
)/g
22+
)/g
23+
*
24+
*/m
25+
*/m
26+
,
27+
,/f
28+
,/f
29+
-
30+
-/a
31+
-/a
32+
...
33+
.../h
34+
.../h
35+
/n
36+
/n
37+
[
38+
[/k
39+
[/k
40+
\
41+
\/i
42+
\/i
43+
{
44+
{/l
45+
{/l

0 commit comments

Comments
 (0)