summaryrefslogtreecommitdiffstats
path: root/bftw.c
diff options
context:
space:
mode:
authorTavian Barnes <tavianator@tavianator.com>2017-08-12 18:12:13 -0400
committerTavian Barnes <tavianator@tavianator.com>2017-08-12 18:12:13 -0400
commitacd7f7ed437793e7c67ecd869cfac32a87c1ec52 (patch)
treeabfb1561c90aca00362fb0f99b8a8da4a70fe08a /bftw.c
parent01a754bc5572103f9a49242d756dc04b0e86bb6e (diff)
downloadbfs-acd7f7ed437793e7c67ecd869cfac32a87c1ec52.tar.xz
Unify broken symlink handling
Rather than open-code the fallback logic for broken symlinks everywhere it's needed, introduce a new xfstatat() utility function that performs the fallback automatically. Using xfstatat() consistently fixes a few bugs, including cases where broken symlinks are given as arguments to predicates like -samefile.
Diffstat (limited to 'bftw.c')
-rw-r--r--bftw.c22
1 files changed, 6 insertions, 16 deletions
diff --git a/bftw.c b/bftw.c
index ce3a567..02e7adb 100644
--- a/bftw.c
+++ b/bftw.c
@@ -551,15 +551,12 @@ static void bftw_queue_destroy(struct bftw_queue *queue) {
/** Call stat() and use the results. */
static int ftwbuf_stat(struct BFTW *ftwbuf, struct stat *sb) {
- int ret = fstatat(ftwbuf->at_fd, ftwbuf->at_path, sb, ftwbuf->at_flags);
- if (ret != 0) {
- return ret;
+ int ret = xfstatat(ftwbuf->at_fd, ftwbuf->at_path, sb, &ftwbuf->at_flags);
+ if (ret == 0) {
+ ftwbuf->statbuf = sb;
+ ftwbuf->typeflag = mode_to_typeflag(sb->st_mode);
}
-
- ftwbuf->statbuf = sb;
- ftwbuf->typeflag = mode_to_typeflag(sb->st_mode);
-
- return 0;
+ return ret;
}
/**
@@ -837,14 +834,7 @@ static void bftw_init_buffers(struct bftw_state *state, const struct dirent *de)
|| ftwbuf->typeflag == BFTW_UNKNOWN
|| (ftwbuf->typeflag == BFTW_LNK && follow)
|| (ftwbuf->typeflag == BFTW_DIR && (detect_cycles || xdev))) {
- int ret = ftwbuf_stat(ftwbuf, &state->statbuf);
- if (ret != 0 && follow && (errno == ENOENT || errno == ENOTDIR)) {
- // Could be a broken symlink, retry without following
- ftwbuf->at_flags = AT_SYMLINK_NOFOLLOW;
- ret = ftwbuf_stat(ftwbuf, &state->statbuf);
- }
-
- if (ret != 0) {
+ if (ftwbuf_stat(ftwbuf, &state->statbuf) != 0) {
bftw_set_error(state, errno);
return;
}