readonly_fd_test.c [plain text]
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <paths.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/acl.h>
#include <sys/attr.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/xattr.h>
#include <unistd.h>
#include "readonly_fd_test.h"
#include "test_utils.h"
static
bool test_readonly_fd_metadata(const char *basedir)
{
char filename[] = ".readonly-ops-XXXXXX";
bool created = false;
bool success = true;
int dirfd = -1;
int tmpfd = -1;
int fd = -1;
acl_t acl = NULL;
static const char test_name[] = "readonly_fd_metadata";
printf("START [%s]\n", test_name);
assert_with_errno((dirfd = open(basedir, O_RDONLY | O_DIRECTORY)) != -1);
assert_with_errno((tmpfd = mkstempsat_np(dirfd, filename, 0)) != -1);
created = true;
assert_with_errno((fd = openat(dirfd, filename, O_RDONLY)) != -1);
close(tmpfd);
tmpfd = -1;
const char data[] = "failure";
assert(write(fd, data, sizeof(data) - 1) == -1);
const uid_t uid = geteuid();
const gid_t gid = getegid();
assert_no_err(fchown(fd, uid, gid));
assert_no_err(fchmod(fd, 0644));
assert_no_err(fchmod(fd, 0600));
assert_no_err(fchflags(fd, UF_HIDDEN));
const time_t mtime = 978307200;
const time_t atime = mtime + 1;
struct timeval matimes_usec[] = {{mtime, 0}, {atime, 0}};
assert_no_err(futimes(fd, matimes_usec));
struct attrlist attrlist = {
.bitmapcount = ATTR_BIT_MAP_COUNT,
.commonattr = ATTR_CMN_MODTIME | ATTR_CMN_ACCTIME,
};
struct {
struct timespec mtime;
struct timespec atime;
} matimes_nsec = {{mtime, 0}, {atime, 0}};
assert_no_err(fsetattrlist(fd, &attrlist, &matimes_nsec, sizeof(matimes_nsec), 0));
static const char key[] = "local.test-xattr";
static const char value[] = "local.test-xattr.value";
assert_no_err(fsetxattr(fd, key, value, sizeof(value)-1, 0, 0));
assert_no_err(fremovexattr(fd, key, 0));
assert_with_errno((acl = acl_init(1)) != NULL);
assert_no_err(acl_set_fd(fd, acl));
if (success) {
printf("PASS [%s]\n", test_name);
} else {
printf("FAIL [%s]\n", test_name);
}
if (acl) {
acl_free(acl);
}
if (fd != -1) {
close(fd);
}
if (tmpfd != -1) {
close(tmpfd);
}
if (created) {
unlinkat(dirfd, filename, 0);
}
if (dirfd != -1) {
close(dirfd);
}
return success;
}
bool do_readonly_fd_test(const char *apfs_test_directory, size_t block_size __unused)
{
bool success = true;
success = success && test_readonly_fd_metadata(apfs_test_directory);
return !success; }