summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTavian Barnes <tavianator@tavianator.com>2024-01-03 17:17:35 -0500
committerTavian Barnes <tavianator@tavianator.com>2024-01-04 14:42:36 -0500
commit45fb1d952c3b262278a3b22e9c7d60cca19a5407 (patch)
tree500f3e4d2288c427669c9fe62dafac64d6e53533
parentd874481987c381fd572a6f3c43840c50111a9554 (diff)
downloadbfs-45fb1d952c3b262278a3b22e9c7d60cca19a5407.tar.xz
Work around DragonFly BSD kernel bug
DragonFly's x86_64 assembly implementation of copyinstr() checks the wrong pointer when deciding whether to return EFAULT or ENAMETOOLONG, causing it to always return EFAULT for overlong paths. Work around it by treating EFAULT the same as ENAMETOOLONG on DragonFly. Link: https://twitter.com/tavianator/status/1742991411203485713
-rw-r--r--src/bftw.c14
-rw-r--r--tests/xtouch.c6
2 files changed, 19 insertions, 1 deletions
diff --git a/src/bftw.c b/src/bftw.c
index 0b74cd9..355cb54 100644
--- a/src/bftw.c
+++ b/src/bftw.c
@@ -739,10 +739,22 @@ static int bftw_file_open(struct bftw_state *state, struct bftw_file *file, cons
}
int fd = bftw_file_openat(state, file, base, at_path);
- if (fd >= 0 || errno != ENAMETOOLONG) {
+ if (fd >= 0) {
return fd;
}
+ switch (errno) {
+ case ENAMETOOLONG:
+#if __DragonFly__
+ // https://twitter.com/tavianator/status/1742991411203485713
+ case EFAULT:
+#endif
+ break;
+
+ default:
+ return -1;
+ }
+
// Handle ENAMETOOLONG by manually traversing the path component-by-component
struct bftw_list parents;
SLIST_INIT(&parents);
diff --git a/tests/xtouch.c b/tests/xtouch.c
index 260a3a3..ed8bbee 100644
--- a/tests/xtouch.c
+++ b/tests/xtouch.c
@@ -70,13 +70,19 @@ static int open_parent(const struct args *args, const char **path) {
switch (errno) {
case ENAMETOOLONG:
+#if __DragonFly__
+ // https://twitter.com/tavianator/status/1742991411203485713
+ case EFAULT:
+#endif
break;
+
case ENOENT:
if (args->flags & CREATE_PARENTS) {
break;
} else {
goto err;
}
+
default:
goto err;
}