From c6769208d4c7c774982fbb76afad0d95a6e4c9e8 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Fri, 24 May 2019 23:26:43 -0400 Subject: fsade: Fix ACL detection on macOS --- Makefile | 2 +- fsade.c | 39 ++++++++++++++++++++++++++++---------- tests.sh | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++++---------- 3 files changed, 86 insertions(+), 21 deletions(-) diff --git a/Makefile b/Makefile index f37c4ba..ed7be9e 100644 --- a/Makefile +++ b/Makefile @@ -56,7 +56,7 @@ LOCAL_LDFLAGS += -Wl,--as-needed LOCAL_LDLIBS += -lacl -lcap -lattr -lrt # These libraries are not built with msan, so disable them -MSAN_CFLAGS := -DBFS_HAS_SYS_ACL=0 -DBFS_HAS_SYS_CAPABILITY=0 -DBFS_HAS_SYS_XATTRS=0 +MSAN_CFLAGS := -DBFS_HAS_SYS_ACL=0 -DBFS_HAS_SYS_CAPABILITY=0 -DBFS_HAS_SYS_XATTR=0 endif ALL_CPPFLAGS = $(LOCAL_CPPFLAGS) $(CPPFLAGS) diff --git a/fsade.c b/fsade.c index 822fbd1..8f8f8b1 100644 --- a/fsade.c +++ b/fsade.c @@ -104,6 +104,13 @@ static bool is_absence_error(int error) { } #endif +#if __APPLE__ + // On macOS, ENOENT can also signal that a file has no ACLs + if (error == ENOENT) { + return true; + } +#endif + return false; } @@ -125,7 +132,13 @@ static int bfs_check_acl_type(const char *path, acl_type_t type) { 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) acl_tag_t tag; @@ -153,22 +166,28 @@ int bfs_check_acl(const struct BFTW *ftwbuf) { const char *path = fake_at(ftwbuf); - int error = 0; - int ret = bfs_check_acl_type(path, ACL_TYPE_ACCESS); - if (ret < 0) { - error = errno; - } + int error = ENOTSUP; + int ret = -1; - if (ret <= 0 && ftwbuf->typeflag == BFTW_DIR) { - ret = bfs_check_acl_type(path, ACL_TYPE_DEFAULT); +#if __APPLE__ + // macOS gives EINVAL for either of the two standard ACL types, + // supporting only ACL_TYPE_EXTENDED + if (ret <= 0) { + ret = bfs_check_acl_type(path, ACL_TYPE_EXTENDED); if (ret < 0) { error = errno; } } - -#ifdef ACL_TYPE_EXTENDED +#else if (ret <= 0) { - ret = bfs_check_acl_type(path, ACL_TYPE_EXTENDED); + ret = bfs_check_acl_type(path, ACL_TYPE_ACCESS); + if (ret < 0) { + error = errno; + } + } + + if (ret <= 0 && ftwbuf->typeflag == BFTW_DIR) { + ret = bfs_check_acl_type(path, ACL_TYPE_DEFAULT); if (ret < 0) { error = errno; } diff --git a/tests.sh b/tests.sh index 75319d7..fd8d4a1 100755 --- a/tests.sh +++ b/tests.sh @@ -2313,12 +2313,18 @@ function test_xtype_bind_mount() { function test_acl() { rm -rf scratch/* - if ! invoke_bfs scratch -acl 2>/dev/null; then + if ! invoke_bfs scratch -quit -acl 2>/dev/null; then return 0 fi touch scratch/{normal,acl} - setfacl -m "u:$(id -un):rw" scratch/acl + + if [ "$(uname)" = "Darwin" ]; then + chmod +a "$(id -un) allow read,write" scratch/acl + else + setfacl -m "u:$(id -un):rw" scratch/acl + fi + ln -s acl scratch/link bfs_diff scratch -acl @@ -2327,12 +2333,18 @@ function test_acl() { function test_L_acl() { rm -rf scratch/* - if ! invoke_bfs scratch -acl 2>/dev/null; then + if ! invoke_bfs scratch -quit -acl 2>/dev/null; then return 0 fi touch scratch/{normal,acl} - setfacl -m "u:$(id -un):rw" scratch/acl + + if [ "$(uname)" = "Darwin" ]; then + chmod +a "$(id -un) allow read,write" scratch/acl + else + setfacl -m "u:$(id -un):rw" scratch/acl + fi + ln -s acl scratch/link bfs_diff -L scratch -acl @@ -2340,6 +2352,11 @@ function test_L_acl() { function test_capable() { rm -rf scratch/* + + if ! invoke_bfs scratch -quit -capable 2>/dev/null; then + return 0 + fi + touch scratch/{normal,capable} sudo setcap all+ep scratch/capable ln -s capable scratch/link @@ -2349,6 +2366,11 @@ function test_capable() { function test_L_capable() { rm -rf scratch/* + + if ! invoke_bfs scratch -quit -capable 2>/dev/null; then + return 0 + fi + touch scratch/{normal,capable} sudo setcap all+ep scratch/capable ln -s capable scratch/link @@ -2358,24 +2380,48 @@ function test_L_capable() { function test_xattr() { rm -rf scratch/* + + if ! invoke_bfs scratch -quit -xattr 2>/dev/null; then + return 0 + fi + touch scratch/{normal,xattr} - # Linux tmpfs doesn't support the user.* namespace, so we use the security.* - # namespace, which is writable by root and readable by others - sudo setfattr -n security.bfs_test scratch/xattr ln -s xattr scratch/link ln -s normal scratch/xattr_link - sudo setfattr -h -n security.bfs_test scratch/xattr_link + + if [ "$(uname)" = "Darwin" ]; then + xattr -w bfs_test true scratch/xattr + xattr -s -w bfs_test true scratch/xattr_link + else + # Linux tmpfs doesn't support the user.* namespace, so we use the security.* + # namespace, which is writable by root and readable by others + sudo setfattr -n security.bfs_test scratch/xattr + sudo setfattr -h -n security.bfs_test scratch/xattr_link + fi bfs_diff scratch -xattr } function test_L_xattr() { rm -rf scratch/* + + if ! invoke_bfs scratch -quit -xattr 2>/dev/null; then + return 0 + fi + touch scratch/{normal,xattr} - sudo setfattr -n security.bfs_test scratch/xattr ln -s xattr scratch/link ln -s normal scratch/xattr_link - sudo setfattr -h -n security.bfs_test scratch/xattr_link + + if [ "$(uname)" = "Darwin" ]; then + xattr -w bfs_test true scratch/xattr + xattr -s -w bfs_test true scratch/xattr_link + else + # Linux tmpfs doesn't support the user.* namespace, so we use the security.* + # namespace, which is writable by root and readable by others + sudo setfattr -n security.bfs_test scratch/xattr + sudo setfattr -h -n security.bfs_test scratch/xattr_link + fi bfs_diff -L scratch -xattr } -- cgit v1.2.3