summaryrefslogtreecommitdiffstats
path: root/fsade.c
diff options
context:
space:
mode:
Diffstat (limited to 'fsade.c')
-rw-r--r--fsade.c392
1 files changed, 0 insertions, 392 deletions
diff --git a/fsade.c b/fsade.c
deleted file mode 100644
index 1444cf4..0000000
--- a/fsade.c
+++ /dev/null
@@ -1,392 +0,0 @@
-/****************************************************************************
- * bfs *
- * Copyright (C) 2019-2021 Tavian Barnes <tavianator@tavianator.com> *
- * *
- * Permission to use, copy, modify, and/or distribute this software for any *
- * purpose with or without fee is hereby granted. *
- * *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES *
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF *
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR *
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES *
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN *
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF *
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. *
- ****************************************************************************/
-
-#include "fsade.h"
-#include "bftw.h"
-#include "dir.h"
-#include "dstring.h"
-#include "util.h"
-#include <errno.h>
-#include <fcntl.h>
-#include <stddef.h>
-#include <unistd.h>
-
-#if BFS_CAN_CHECK_ACL
-# include <sys/acl.h>
-#endif
-
-#if BFS_CAN_CHECK_CAPABILITIES
-# include <sys/capability.h>
-#endif
-
-#if BFS_HAS_SYS_EXTATTR
-# include <sys/extattr.h>
-#elif BFS_HAS_SYS_XATTR
-# include <sys/xattr.h>
-#endif
-
-#if BFS_CAN_CHECK_ACL || BFS_CAN_CHECK_CAPABILITIES || BFS_CAN_CHECK_XATTRS
-
-/**
- * Many of the APIs used here don't have *at() variants, but we can try to
- * emulate something similar if /proc/self/fd is available.
- */
-static const char *fake_at(const struct BFTW *ftwbuf) {
- static bool proc_works = true;
- static bool proc_checked = false;
-
- char *path = NULL;
- if (!proc_works || ftwbuf->at_fd == AT_FDCWD) {
- goto fail;
- }
-
- path = dstrprintf("/proc/self/fd/%d/", ftwbuf->at_fd);
- if (!path) {
- goto fail;
- }
-
- if (!proc_checked) {
- proc_checked = true;
- if (xfaccessat(AT_FDCWD, path, F_OK) != 0) {
- proc_works = false;
- goto fail;
- }
- }
-
- if (dstrcat(&path, ftwbuf->at_path) != 0) {
- goto fail;
- }
-
- return path;
-
-fail:
- dstrfree(path);
- return ftwbuf->path;
-}
-
-static void free_fake_at(const struct BFTW *ftwbuf, const char *path) {
- if (path != ftwbuf->path) {
- dstrfree((char *)path);
- }
-}
-
-/**
- * Check if an error was caused by the absence of support or data for a feature.
- */
-static bool is_absence_error(int error) {
- // If the OS doesn't support the feature, it's obviously not enabled for
- // any files
- if (error == ENOTSUP) {
- return true;
- }
-
- // On Linux, ACLs and capabilities are implemented in terms of extended
- // attributes, which report ENODATA/ENOATTR when missing
-
-#ifdef ENODATA
- if (error == ENODATA) {
- return true;
- }
-#endif
-
-#if defined(ENOATTR) && ENOATTR != ENODATA
- if (error == ENOATTR) {
- return true;
- }
-#endif
-
- // On at least FreeBSD and macOS, EINVAL is returned when the requested
- // ACL type is not supported for that file
- if (error == EINVAL) {
- return true;
- }
-
-#if __APPLE__
- // On macOS, ENOENT can also signal that a file has no ACLs
- if (error == ENOENT) {
- return true;
- }
-#endif
-
- return false;
-}
-
-#endif // BFS_CAN_CHECK_ACL || BFS_CAN_CHECK_CAPABILITIES || BFS_CAN_CHECK_XATTRS
-
-#if BFS_CAN_CHECK_ACL
-
-/** Check if a POSIX.1e ACL is non-trivial. */
-static int bfs_check_posix1e_acl(acl_t acl, bool ignore_required) {
- int ret = 0;
-
- acl_entry_t entry;
- for (int status = acl_get_entry(acl, ACL_FIRST_ENTRY, &entry);
-#if __APPLE__
- // POSIX.1e specifies a return value of 1 for success, but macOS
- // returns 0 instead
- status == 0;
-#else
- status > 0;
-#endif
- status = acl_get_entry(acl, ACL_NEXT_ENTRY, &entry)) {
-#if defined(ACL_USER_OBJ) && defined(ACL_GROUP_OBJ) && defined(ACL_OTHER)
- if (ignore_required) {
- acl_tag_t tag;
- if (acl_get_tag_type(entry, &tag) != 0) {
- ret = -1;
- continue;
- }
- if (tag == ACL_USER_OBJ || tag == ACL_GROUP_OBJ || tag == ACL_OTHER) {
- continue;
- }
- }
-#endif
-
- ret = 1;
- break;
- }
-
- return ret;
-}
-
-/** Check if an ACL of the given type is non-trivial. */
-static int bfs_check_acl_type(acl_t acl, acl_type_t type) {
- if (type == ACL_TYPE_DEFAULT) {
- // For directory default ACLs, any entries make them non-trivial
- return bfs_check_posix1e_acl(acl, false);
- }
-
-#if __FreeBSD__
- int trivial;
-
-#if BFS_HAS_FEATURE(memory_sanitizer, false)
- // msan seems to be missing an interceptor for acl_is_trivial_np()
- trivial = 0;
-#endif
-
- if (acl_is_trivial_np(acl, &trivial) < 0) {
- return -1;
- } else if (trivial) {
- return 0;
- } else {
- return 1;
- }
-#else // !__FreeBSD__
- return bfs_check_posix1e_acl(acl, true);
-#endif
-}
-
-int bfs_check_acl(const struct BFTW *ftwbuf) {
- static const acl_type_t acl_types[] = {
-#if __APPLE__
- // macOS gives EINVAL for either of the two standard ACL types,
- // supporting only ACL_TYPE_EXTENDED
- ACL_TYPE_EXTENDED,
-#else
- // The two standard POSIX.1e ACL types
- ACL_TYPE_ACCESS,
- ACL_TYPE_DEFAULT,
-#endif
-
-#ifdef ACL_TYPE_NFS4
- ACL_TYPE_NFS4,
-#endif
- };
- static const size_t n_acl_types = sizeof(acl_types)/sizeof(acl_types[0]);
-
- if (ftwbuf->type == BFS_LNK) {
- return 0;
- }
-
- const char *path = fake_at(ftwbuf);
-
- int ret = -1, error = 0;
- for (size_t i = 0; i < n_acl_types && ret <= 0; ++i) {
- acl_type_t type = acl_types[i];
-
- if (type == ACL_TYPE_DEFAULT && ftwbuf->type != BFS_DIR) {
- // ACL_TYPE_DEFAULT is supported only for directories,
- // otherwise acl_get_file() gives EACCESS
- continue;
- }
-
- acl_t acl = acl_get_file(path, type);
- if (!acl) {
- error = errno;
- if (is_absence_error(error)) {
- ret = 0;
- }
- continue;
- }
-
- ret = bfs_check_acl_type(acl, type);
- error = errno;
- acl_free(acl);
- }
-
- free_fake_at(ftwbuf, path);
- errno = error;
- return ret;
-}
-
-#else // !BFS_CAN_CHECK_ACL
-
-int bfs_check_acl(const struct BFTW *ftwbuf) {
- errno = ENOTSUP;
- return -1;
-}
-
-#endif
-
-#if BFS_CAN_CHECK_CAPABILITIES
-
-int bfs_check_capabilities(const struct BFTW *ftwbuf) {
- if (ftwbuf->type == BFS_LNK) {
- return 0;
- }
-
- int ret = -1, error;
- const char *path = fake_at(ftwbuf);
-
- cap_t caps = cap_get_file(path);
- if (!caps) {
- error = errno;
- if (is_absence_error(error)) {
- ret = 0;
- }
- goto out_path;
- }
-
- // TODO: Any better way to check for a non-empty capability set?
- char *text = cap_to_text(caps, NULL);
- if (!text) {
- error = errno;
- goto out_caps;
- }
- ret = text[0] ? 1 : 0;
-
- error = errno;
- cap_free(text);
-out_caps:
- cap_free(caps);
-out_path:
- free_fake_at(ftwbuf, path);
- errno = error;
- return ret;
-}
-
-#else // !BFS_CAN_CHECK_CAPABILITIES
-
-int bfs_check_capabilities(const struct BFTW *ftwbuf) {
- errno = ENOTSUP;
- return -1;
-}
-
-#endif
-
-#if BFS_CAN_CHECK_XATTRS
-
-int bfs_check_xattrs(const struct BFTW *ftwbuf) {
- const char *path = fake_at(ftwbuf);
- ssize_t len;
-
-#if BFS_HAS_SYS_EXTATTR
- ssize_t (*extattr_list)(const char *, int, void*, size_t) =
- ftwbuf->type == BFS_LNK ? extattr_list_link : extattr_list_file;
-
- len = extattr_list(path, EXTATTR_NAMESPACE_SYSTEM, NULL, 0);
- if (len <= 0) {
- len = extattr_list(path, EXTATTR_NAMESPACE_USER, NULL, 0);
- }
-#elif __APPLE__
- int options = ftwbuf->type == BFS_LNK ? XATTR_NOFOLLOW : 0;
- len = listxattr(path, NULL, 0, options);
-#else
- if (ftwbuf->type == BFS_LNK) {
- len = llistxattr(path, NULL, 0);
- } else {
- len = listxattr(path, NULL, 0);
- }
-#endif
-
- int error = errno;
-
- free_fake_at(ftwbuf, path);
-
- if (len > 0) {
- return 1;
- } else if (len == 0 || is_absence_error(error)) {
- return 0;
- } else if (error == E2BIG) {
- return 1;
- } else {
- errno = error;
- return -1;
- }
-}
-
-int bfs_check_xattr_named(const struct BFTW *ftwbuf, const char *name) {
- const char *path = fake_at(ftwbuf);
- ssize_t len;
-
-#if BFS_HAS_SYS_EXTATTR
- ssize_t (*extattr_get)(const char *, int, const char *, void*, size_t) =
- ftwbuf->type == BFS_LNK ? extattr_get_link : extattr_get_file;
-
- len = extattr_get(path, EXTATTR_NAMESPACE_SYSTEM, name, NULL, 0);
- if (len < 0) {
- len = extattr_get(path, EXTATTR_NAMESPACE_USER, name, NULL, 0);
- }
-#elif __APPLE__
- int options = ftwbuf->type == BFS_LNK ? XATTR_NOFOLLOW : 0;
- len = getxattr(path, name, NULL, 0, 0, options);
-#else
- if (ftwbuf->type == BFS_LNK) {
- len = lgetxattr(path, name, NULL, 0);
- } else {
- len = getxattr(path, name, NULL, 0);
- }
-#endif
-
- int error = errno;
-
- free_fake_at(ftwbuf, path);
-
- if (len >= 0) {
- return 1;
- } else if (is_absence_error(error)) {
- return 0;
- } else if (error == E2BIG) {
- return 1;
- } else {
- errno = error;
- return -1;
- }
-}
-
-#else // !BFS_CAN_CHECK_XATTRS
-
-int bfs_check_xattrs(const struct BFTW *ftwbuf) {
- errno = ENOTSUP;
- return -1;
-}
-
-int bfs_check_xattr_named(const struct BFTW *ftwbuf, const char *name) {
- errno = ENOTSUP;
- return -1;
-}
-
-#endif