diff --git a/src/nwnss/lsa/lsaXattrUserspace.c b/src/nwnss/lsa/lsaXattrUserspace.c index 4172e00..c3bf30f 100644 --- a/src/nwnss/lsa/lsaXattrUserspace.c +++ b/src/nwnss/lsa/lsaXattrUserspace.c @@ -15,6 +15,7 @@ #include #include +#include #include @@ -119,25 +120,62 @@ NssLsaXattrUserspaceInodePrivate(struct inode *inode) return inode ? (LsaInode_s *)inode->i_private : NULL; } +static const char * +NssLsaXattrUserspaceOtherfsPath(const NssLsaXattrUserspace_s *xattr) +{ + const char *path; + + path = NssUserspaceProviderPath(xattr ? &xattr->provider : NULL); + return path && path[0] != '\0' ? path : NULL; +} + +static int +NssLsaXattrUserspaceOtherfsHostName(const char *name, + char *buffer, + size_t bufferSize) +{ + return NssLsaXattrUserspaceOtherfsName(name, buffer, bufferSize); +} + ssize_t NssLsaXattrUserspaceGet(NssLsaXattrUserspace_s *xattr, const char *name, void *value, size_t size) { + char hostName[256]; + const char *path; + ssize_t result; + if (!xattr || !name) { return -EINVAL; } - if (NssLsaXattrUserspaceGetProvider(xattr) != - NSS_USERSPACE_PROVIDER_NSS_VOLUME) + switch (NssLsaXattrUserspaceGetProvider(xattr)) { - return -ENOTSUP; + case NSS_USERSPACE_PROVIDER_NSS_VOLUME: + return netware_getxattr(NssLsaXattrUserspaceDentry(xattr), + NssLsaXattrUserspaceNssName(name), + value, + size); + case NSS_USERSPACE_PROVIDER_OTHERFS_XATTR: + path = NssLsaXattrUserspaceOtherfsPath(xattr); + if (!path) + { + return -EINVAL; + } + result = NssLsaXattrUserspaceOtherfsHostName(name, + hostName, + sizeof(hostName)); + if (result != 0) + { + return result; + } + result = getxattr(path, hostName, value, size); + return result < 0 ? -errno : result; + default: + return -ENOTSUP; } - return netware_getxattr(NssLsaXattrUserspaceDentry(xattr), - NssLsaXattrUserspaceNssName(name), - value, - size); } ssize_t @@ -146,36 +184,76 @@ NssLsaXattrUserspaceSet(NssLsaXattrUserspace_s *xattr, const void *value, size_t size) { + char hostName[256]; + const char *path; + int result; + if (!xattr || !name) { return -EINVAL; } - if (NssLsaXattrUserspaceGetProvider(xattr) != - NSS_USERSPACE_PROVIDER_NSS_VOLUME) + switch (NssLsaXattrUserspaceGetProvider(xattr)) { - return -ENOTSUP; + case NSS_USERSPACE_PROVIDER_NSS_VOLUME: + return netware_setxattr(NssLsaXattrUserspaceDentry(xattr), + NssLsaXattrUserspaceNssName(name), + value, + size); + case NSS_USERSPACE_PROVIDER_OTHERFS_XATTR: + path = NssLsaXattrUserspaceOtherfsPath(xattr); + if (!path) + { + return -EINVAL; + } + result = NssLsaXattrUserspaceOtherfsHostName(name, + hostName, + sizeof(hostName)); + if (result != 0) + { + return result; + } + result = setxattr(path, hostName, value, size, 0); + return result < 0 ? -errno : result; + default: + return -ENOTSUP; } - return netware_setxattr(NssLsaXattrUserspaceDentry(xattr), - NssLsaXattrUserspaceNssName(name), - value, - size); } int NssLsaXattrUserspaceRemove(NssLsaXattrUserspace_s *xattr, const char *name) { + char hostName[256]; + const char *path; + int result; + if (!xattr || !name) { return -EINVAL; } - if (NssLsaXattrUserspaceGetProvider(xattr) != - NSS_USERSPACE_PROVIDER_NSS_VOLUME) + switch (NssLsaXattrUserspaceGetProvider(xattr)) { - return -ENOTSUP; + case NSS_USERSPACE_PROVIDER_NSS_VOLUME: + return netware_removexattr(NssLsaXattrUserspaceDentry(xattr), + NssLsaXattrUserspaceNssName(name)); + case NSS_USERSPACE_PROVIDER_OTHERFS_XATTR: + path = NssLsaXattrUserspaceOtherfsPath(xattr); + if (!path) + { + return -EINVAL; + } + result = NssLsaXattrUserspaceOtherfsHostName(name, + hostName, + sizeof(hostName)); + if (result != 0) + { + return result; + } + result = removexattr(path, hostName); + return result < 0 ? -errno : result; + default: + return -ENOTSUP; } - return netware_removexattr(NssLsaXattrUserspaceDentry(xattr), - NssLsaXattrUserspaceNssName(name)); } #endif /* NSS_USERSPACE */ diff --git a/tests/nwnss/xattr/CMakeLists.txt b/tests/nwnss/xattr/CMakeLists.txt index a019aa2..67f8e58 100644 --- a/tests/nwnss/xattr/CMakeLists.txt +++ b/tests/nwnss/xattr/CMakeLists.txt @@ -1,3 +1,4 @@ add_executable(test_nwnss_xattr test_nwnss_xattr.c) target_link_libraries(test_nwnss_xattr PRIVATE mars_nwe::nwnss) add_test(NAME nwnss.xattr COMMAND test_nwnss_xattr) +set_tests_properties(nwnss.xattr PROPERTIES SKIP_RETURN_CODE 77) diff --git a/tests/nwnss/xattr/test_nwnss_xattr.c b/tests/nwnss/xattr/test_nwnss_xattr.c index 2be2963..6384943 100644 --- a/tests/nwnss/xattr/test_nwnss_xattr.c +++ b/tests/nwnss/xattr/test_nwnss_xattr.c @@ -3,7 +3,10 @@ #include #include +#include #include +#include +#include #define CHECK(expr) \ do { \ @@ -13,12 +16,103 @@ } \ } while (0) +#define SKIP_CODE 77 + +static int is_xattr_unsupported(int err) +{ + return err == -ENOTSUP || err == -EOPNOTSUPP || err == -ENOSYS || + err == -EPERM || err == -EACCES; +} + +static int make_temp_file(char *path, size_t pathSize) +{ + const char *tmpdir; + int fd; + + tmpdir = getenv("TMPDIR"); + if (!tmpdir || tmpdir[0] == '\0') + { + tmpdir = "."; + } + if (snprintf(path, pathSize, "%s/nwnss-xattr-XXXXXX", tmpdir) < 0 || + strlen(path) >= pathSize) + { + return -ENAMETOOLONG; + } + fd = mkstemp(path); + if (fd < 0) + { + return -errno; + } + close(fd); + return 0; +} + +static int check_otherfs_roundtrip(NssLsaXattrUserspace_s *xattr, + const char *nssName, + const char *expectedHostName, + const char *payload) +{ + char hostName[128]; + char hostValue[128]; + char nssValue[128]; + ssize_t got; + ssize_t result; + + CHECK(NssLsaXattrUserspaceOtherfsName(nssName, + hostName, + sizeof(hostName)) == 0); + CHECK(strcmp(hostName, expectedHostName) == 0); + + result = NssLsaXattrUserspaceSet(xattr, + nssName, + payload, + strlen(payload)); + if (is_xattr_unsupported((int)result)) + { + fprintf(stderr, + "SKIP/WARN: host filesystem does not allow user xattrs on test file\n"); + return SKIP_CODE; + } + CHECK(result == 0); + + memset(hostValue, 0, sizeof(hostValue)); + got = getxattr(NssUserspaceProviderPath(NssLsaXattrUserspaceProvider(xattr)), + expectedHostName, + hostValue, + sizeof(hostValue)); + CHECK(got == (ssize_t)strlen(payload)); + CHECK(memcmp(hostValue, payload, strlen(payload)) == 0); + + memset(nssValue, 0, sizeof(nssValue)); + got = NssLsaXattrUserspaceGet(xattr, + nssName, + nssValue, + sizeof(nssValue)); + CHECK(got == (ssize_t)strlen(payload)); + CHECK(memcmp(nssValue, payload, strlen(payload)) == 0); + + got = NssLsaXattrUserspaceGet(xattr, nssName, NULL, 0); + CHECK(got == (ssize_t)strlen(payload)); + + CHECK(NssLsaXattrUserspaceRemove(xattr, nssName) == 0); + got = getxattr(NssUserspaceProviderPath(NssLsaXattrUserspaceProvider(xattr)), + expectedHostName, + hostValue, + sizeof(hostValue)); + CHECK(got < 0 && errno == ENODATA); + + return 0; +} + int main(void) { NssUserspaceProvider_s provider; NssLsaXattrUserspace_s xattr; VolumeID_t volumeId; char hostName[128]; + char tempPath[4096]; + int result; NssUserspaceProviderInit(&provider); CHECK(NssUserspaceProviderGetKind(&provider) == NSS_USERSPACE_PROVIDER_UNSET); @@ -65,17 +159,49 @@ int main(void) CHECK(strcmp(NssLsaXattrUserspaceNssName("netware.metadata"), "metadata") == 0); - CHECK(NssLsaXattrUserspaceInitOtherfsPath(&xattr, ".") == 0); + CHECK(make_temp_file(tempPath, sizeof(tempPath)) == 0); + result = NssLsaXattrUserspaceInitOtherfsPath(&xattr, tempPath); + if (result != 0) + { + unlink(tempPath); + CHECK(result == 0); + } CHECK(NssLsaXattrUserspaceGetProvider(&xattr) == NSS_USERSPACE_PROVIDER_OTHERFS_XATTR); CHECK(NssLsaXattrUserspaceOtherfsName("netware.trustees", - hostName, - sizeof(hostName)) == 0); + hostName, + sizeof(hostName)) == 0); CHECK(strcmp(hostName, "user.netware.trustees") == 0); - CHECK(NssLsaXattrUserspaceGet(&xattr, - "netware.metadata", - NULL, - 0) == -ENOTSUP); + result = check_otherfs_roundtrip(&xattr, + "netware.metadata", + "user.netware.metadata", + "metadata:v1;rights=rwcemf"); + if (result == SKIP_CODE) + { + unlink(tempPath); + return SKIP_CODE; + } + CHECK(result == 0); + + result = check_otherfs_roundtrip(&xattr, + "metadata", + "user.netware.metadata", + "metadata:v2;name=short"); + CHECK(result == 0); + + result = check_otherfs_roundtrip(&xattr, + "user.netware.metadata", + "user.netware.metadata", + "metadata:v3;direct-host-name"); + CHECK(result == 0); + + result = check_otherfs_roundtrip(&xattr, + "netware.trustees", + "user.netware.trustees", + "trustee:1001:RWCEMF"); + CHECK(result == 0); + + unlink(tempPath); return 0; }