Discussion:
[dev] [PATCH 1/2] find: "-" by itself is a file name
t***@tavianator.com
2018-11-02 02:05:16 UTC
Permalink
From: Tavian Barnes <***@tavianator.com>

See https://savannah.gnu.org/bugs/?15235 for a discussion of why the
POSIX wording implies that "-" by itself is not part of the expression.
---
find.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/find.c b/find.c
index 03889a8..f96c05b 100644
--- a/find.c
+++ b/find.c
@@ -1015,6 +1015,12 @@ usage(void)
eprintf("usage: %s [-H | -L] path ... [expression ...]\n", argv0);
}

+static int
+is_path(const char *arg)
+{
+ return !(arg[0] == '-' && arg[1]) && strcmp(arg, "!") && strcmp(arg, "(");
+}
+
int
main(int argc, char **argv)
{
@@ -1037,7 +1043,7 @@ main(int argc, char **argv)

paths = argv;

- for (; *argv && **argv != '-' && strcmp(*argv, "!") && strcmp(*argv, "("); argv++)
+ for (; *argv && is_path(*argv); argv++)
;

if (!(npaths = argv - paths))
--
2.19.1
t***@tavianator.com
2018-11-02 02:05:17 UTC
Permalink
From: Tavian Barnes <***@tavianator.com>

About -H/-L, POSIX says
If the referenced file does not exist, the file information and type
shall be for the link itself.
so we need to fall back from stat() to lstat() if errno indicates a
broken link.
---
find.c | 17 +++++++++++++++--
1 file changed, 15 insertions(+), 2 deletions(-)

diff --git a/find.c b/find.c
index f96c05b..d907594 100644
--- a/find.c
+++ b/find.c
@@ -223,6 +223,19 @@ static struct {
char print; /* whether we will need -print when parsing */
} gflags;

+static int
+find_stat(const char *path, int is_root, struct stat *st)
+{
+ if (gflags.l || (gflags.h && is_root)) {
+ int ret = stat(path, st);
+ if (ret == 0 || (errno != ENOENT && errno != ENOTDIR)) {
+ return ret;
+ }
+ }
+
+ return lstat(path, st);
+}
+
/*
* Primaries
*/
@@ -660,7 +673,7 @@ get_newer_arg(char *argv[], union extra *extra)
{
struct stat st;

- if (stat(*argv, &st))
+ if (find_stat(*argv, 1, &st))
eprintf("failed to stat '%s':", *argv);

extra->i = st.st_mtime;
@@ -944,7 +957,7 @@ find(char *path, struct findhist *hist)

len = strlen(path) + 2; /* \0 and '/' */

- if ((gflags.l || (gflags.h && !hist) ? stat(path, &st) : lstat(path, &st)) < 0) {
+ if (find_stat(path, !hist, &st) < 0) {
weprintf("failed to stat %s:", path);
return;
}
--
2.19.1
Quentin Rameau
2018-11-02 08:21:50 UTC
Permalink
Hello Tavian,
Post by t***@tavianator.com
See https://savannah.gnu.org/bugs/?15235 for a discussion of why the
POSIX wording implies that "-" by itself is not part of the expression.
I think this was a pedantly wrong interpretation of the standard.

The specification has been reworded since to prevent this:

“The first operand and subsequent operands up to but not including the
first operand that starts with a '-', or is a '!' or a '(', shall be
interpreted as path operands.”

“If the first operand starts with a '-', or is a '!' or a '(', the
behavior is unspecified”

So no, POSIX doesn't say (or imply) that "-" is to be treated as a path.
The implementation is free to chose, then you can't expect
compatibility there and shouldn't rely on that.
Tavian Barnes
2018-11-02 13:21:45 UTC
Permalink
Post by Quentin Rameau
Hello Tavian,
Post by t***@tavianator.com
See https://savannah.gnu.org/bugs/?15235 for a discussion of why the
POSIX wording implies that "-" by itself is not part of the expression.
I think this was a pedantly wrong interpretation of the standard.
It certainly is pedantic.
Post by Quentin Rameau
“The first operand and subsequent operands up to but not including the
first operand that starts with a '-', or is a '!' or a '(', shall be
interpreted as path operands.”
“If the first operand starts with a '-', or is a '!' or a '(', the
behavior is unspecified”
So no, POSIX doesn't say (or imply) that "-" is to be treated as a path.
The implementation is free to chose, then you can't expect
compatibility there and shouldn't rely on that.
My interpretation of the linked thread was that "starts with" is
supposed to mean a strict prefix in POSIX, so "-" doesn't start with
"-". I haven't found anything in the standard that says that
explicitly though. If you'd rather interpret "starts with" to include
exact matches, feel free to drop this patch.
--
Tavian Barnes
Quentin Rameau
2018-11-02 13:46:13 UTC
Permalink
Post by Tavian Barnes
My interpretation of the linked thread was that "starts with" is
supposed to mean a strict prefix in POSIX, so "-" doesn't start with
"-". I haven't found anything in the standard that says that
explicitly though. If you'd rather interpret "starts with" to include
exact matches, feel free to drop this patch.
Actually I think you're right.
I mixed the case of "-" and "!", "[()]".

The distinction seems to be explicitely made between “starts with” and
“is”:

“starts with a '-', or is a '!' or a '('”

And I misread the savannah PR example too.

So in fine, I agree with the patch!

Although,
Post by Tavian Barnes
+ return !(arg[0] == '-' && arg[1]) && strcmp(arg, "!") && strcmp(arg, "(");
Having a negation operator at the start of an expression which does
not negate the whole expression chain is kind of misleading.

Why not:

return strcmp(arg, "-") || && strcmp(arg, "!") && strcmp(arg, "(");
Tavian Barnes
2018-11-02 14:36:42 UTC
Permalink
Post by Quentin Rameau
Post by Tavian Barnes
My interpretation of the linked thread was that "starts with" is
supposed to mean a strict prefix in POSIX, so "-" doesn't start with
"-". I haven't found anything in the standard that says that
explicitly though. If you'd rather interpret "starts with" to include
exact matches, feel free to drop this patch.
Actually I think you're right.
Okay great!
Post by Quentin Rameau
Although,
Post by Tavian Barnes
+ return !(arg[0] == '-' && arg[1]) && strcmp(arg, "!") && strcmp(arg, "(");
Having a negation operator at the start of an expression which does
not negate the whole expression chain is kind of misleading.
Yeah I see what you mean.
Post by Quentin Rameau
return strcmp(arg, "-") || && strcmp(arg, "!") && strcmp(arg, "(");
Not sure what you're recommending here. Maybe

return (arg[0] != '-' || !strcmp(arg, "-")) && strcmp(arg, "!") &&
strcmp(arg, "(");

?
--
Tavian Barnes
Quentin Rameau
2018-11-02 14:47:27 UTC
Permalink
Post by Tavian Barnes
Post by Quentin Rameau
return strcmp(arg, "-") || && strcmp(arg, "!") && strcmp(arg, "(");
Not sure what you're recommending here. Maybe
return (arg[0] != '-' || !strcmp(arg, "-")) && strcmp(arg, "!") &&
strcmp(arg, "(");
?
No, I just left an operator there when rewriting the chain, here's the
corrected one:

return strcmp(arg, "-") || strcmp(arg, "!") && strcmp(arg, "(");
Quentin Rameau
2018-11-02 15:02:49 UTC
Permalink
Post by Quentin Rameau
No, I just left an operator there when rewriting the chain, here's the
return strcmp(arg, "-") || strcmp(arg, "!") && strcmp(arg, "(");
Ah, forget about it, I'm not focused.

return strcmp(arg, "!") && strcmp(arg, "(") || !strcmp(arg, "-");
Loading...