commit 3dc1dc04a5ecf97ba3ce3f8c103c73bcfe00e31e from: Stefan Sperling via: Thomas Adam date: Mon Sep 27 06:40:44 2021 UTC for portability, handle errno variations upon open(2) failure with O_NOFOLLOW Problem pointed out by naddy for FreeBSD -portable. Discussed with millert, thomas adam, and naddy. commit - ace90326f82adffc32a25213124922899e849771 commit + 3dc1dc04a5ecf97ba3ce3f8c103c73bcfe00e31e blob - c4e5c1824c875392b7ef1495c9256b3f8f5c84d6 blob + ddcebec4e3d857a20d7894579e2d4ee08bbf0fe9 --- got/got.c +++ got/got.c @@ -4394,7 +4394,7 @@ print_diff(void *arg, unsigned char status, unsigned c if (dirfd != -1) { fd = openat(dirfd, de_name, O_RDONLY | O_NOFOLLOW); if (fd == -1) { - if (errno != ELOOP) { + if (!got_err_open_nofollow_on_symlink()) { err = got_error_from_errno2("openat", abspath); goto done; @@ -4407,7 +4407,7 @@ print_diff(void *arg, unsigned char status, unsigned c } else { fd = open(abspath, O_RDONLY | O_NOFOLLOW); if (fd == -1) { - if (errno != ELOOP) { + if (!got_err_open_nofollow_on_symlink()) { err = got_error_from_errno2("open", abspath); goto done; blob - 4e87ec59462a265ba7b4c932db9772fbd93373c1 blob + 63f4fa74abf23dd8211a43333dd555ccf57acd6d --- include/got_error.h +++ include/got_error.h @@ -429,3 +429,9 @@ const struct got_error *got_error_path(const char *, i * additional arguments. */ const struct got_error *got_error_fmt(int, const char *, ...); + +/* + * Check whether open(2) with O_NOFOLLOW failed on a symlink. + * This must be called directly after open(2) because it uses errno! + */ +int got_err_open_nofollow_on_symlink(void); blob - 62a1719e317f17da42a7802c245017926889d142 blob + 7771a0b6aa35dd88d61d89d337613f8c62f6da75 --- lib/error.c +++ lib/error.c @@ -274,3 +274,22 @@ got_error_fmt(int code, const char *fmt, ...) abort(); } + +int +got_err_open_nofollow_on_symlink(void) +{ + /* + * Check whether open(2) with O_NOFOLLOW failed on a symlink. + * Posix mandates ELOOP and OpenBSD follows it. Others return + * different error codes. We carry this workaround to help the + * portable version a little. + */ + return (errno == ELOOP +#ifdef EMLINK + || errno == EMLINK +#endif +#ifdef EFTYPE + || errno == EFTYPE +#endif + ); +} blob - 2d3f2ac0339c7d159f40426028eb11947353a4f1 blob + 26749965b1904cf8d808d8157bf204b30403deae --- lib/object_create.c +++ lib/object_create.c @@ -129,7 +129,7 @@ got_object_blob_file_create(struct got_object_id **id, fd = open(ondisk_path, O_RDONLY | O_NOFOLLOW); if (fd == -1) { - if (errno != ELOOP) + if (!got_err_open_nofollow_on_symlink()) return got_error_from_errno2("open", ondisk_path); if (lstat(ondisk_path, &sb) == -1) { blob - acf42c1ab053024ca6b05a987842225c8dd06846 blob + a3e841f3fe4b794959a4b3b7a60de73abf4e6dd0 --- lib/worktree.c +++ lib/worktree.c @@ -1282,7 +1282,7 @@ replace_existing_symlink(int *did_something, const cha */ fd = open(ondisk_path, O_RDWR | O_EXCL | O_NOFOLLOW); if (fd == -1) { - if (errno != ELOOP) + if (!got_err_open_nofollow_on_symlink()) return got_error_from_errno2("open", ondisk_path); /* We are updating an existing on-disk symlink. */ @@ -1779,9 +1779,10 @@ get_file_status(unsigned char *status, struct stat *sb } } else { fd = open(abspath, O_RDONLY | O_NOFOLLOW); - if (fd == -1 && errno != ENOENT && errno != ELOOP) + if (fd == -1 && errno != ENOENT && + !got_err_open_nofollow_on_symlink()) return got_error_from_errno2("open", abspath); - else if (fd == -1 && errno == ELOOP) { + else if (fd == -1 && got_err_open_nofollow_on_symlink()) { if (lstat(abspath, sb) == -1) return got_error_from_errno2("lstat", abspath); } else if (fd == -1 || fstat(fd, sb) == -1) { @@ -3765,7 +3766,7 @@ worktree_status(struct got_worktree *worktree, const c fd = open(ondisk_path, O_RDONLY | O_NOFOLLOW | O_DIRECTORY); if (fd == -1) { if (errno != ENOTDIR && errno != ENOENT && errno != EACCES && - errno != ELOOP) + !got_err_open_nofollow_on_symlink()) err = got_error_from_errno2("open", ondisk_path); else { if (!no_ignores) { @@ -4471,7 +4472,7 @@ create_patched_content(char **path_outfile, int revers if (dirfd2 != -1) { fd2 = openat(dirfd2, de_name2, O_RDONLY | O_NOFOLLOW); if (fd2 == -1) { - if (errno != ELOOP) { + if (!got_err_open_nofollow_on_symlink()) { err = got_error_from_errno2("openat", path2); goto done; } @@ -4485,7 +4486,7 @@ create_patched_content(char **path_outfile, int revers } else { fd2 = open(path2, O_RDONLY | O_NOFOLLOW); if (fd2 == -1) { - if (errno != ELOOP) { + if (!got_err_open_nofollow_on_symlink()) { err = got_error_from_errno2("open", path2); goto done; }