#include <TargetConditionals.h>
#if TARGET_OS_EMBEDDED
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/mman.h>
#include <string.h>
#include <sys/attr.h>
#include <sys/stat.h>
#include <sys/sysctl.h>
#include <System/sys/fsgetpath.h>
#include <hfs/hfs_fsctl.h>
#include "hfs-tests.h"
#include "test-utils.h"
TEST(list_ids, .run_as_root = true)
#define MAX_FILES 100
#define KB *1024
#define F_RECYCLE 84
static struct attrs {
uint32_t len;
uint64_t file_id;
uint32_t dp_flags;
} __attribute__((aligned(4), packed)) attrs[MAX_FILES];
static char *path[MAX_FILES];
static int fd[MAX_FILES];
static uint32_t max_ids = 1000000;
static uint32_t max_ids_per_iter = 262144;
int run_list_ids(__unused test_ctx_t *ctx)
{
struct statfs sfs;
assert(statfs("/private/var", &sfs) == 0);
if (strcmp(sfs.f_fstypename, "hfs")) {
printf("list_ids needs hfs on the data partition.\n");
return 0;
}
unsigned i;
uint32_t *file_ids = malloc(4 * max_ids);
uint32_t count = 0;
bzero(file_ids, 4 * max_ids);
struct listxattrid_cp listxattrid_file_ids = {
.flags = (LSXCP_PROT_CLASS_A | LSXCP_PROT_CLASS_B
| LSXCP_PROT_CLASS_C | LSXCP_UNROLLED_KEYS),
};
do {
listxattrid_file_ids.count = max_ids_per_iter;
listxattrid_file_ids.fileid = file_ids + count;
assert_no_err(fsctl("/private/var", HFSIOC_LISTXATTRID_CP, &listxattrid_file_ids, 0));
count += listxattrid_file_ids.count;
assert(count < max_ids);
} while (count == max_ids_per_iter);
void *buf = malloc(1 KB);
memset(buf, 0x25, 1 KB);
for (unsigned i = 0; i < MAX_FILES; i ++) {
asprintf(&path[i], "/private/var/get-matched_listid.data.%u", getpid()+i);
unlink(path[i]);
assert_with_errno((fd[i] = open(path[i], O_RDWR | O_TRUNC | O_CREAT, 0666)) >= 0);
check_io(write(fd[i], buf, 1 KB), 1 KB);
assert_no_err(fcntl(fd[i], F_SETPROTECTIONCLASS, 2));
struct attrlist attrlist = {
.bitmapcount = ATTR_BIT_MAP_COUNT,
.commonattr = ATTR_CMN_FILEID | ATTR_CMN_DATA_PROTECT_FLAGS,
};
assert_no_err(fgetattrlist(fd[i], &attrlist, &attrs[i], sizeof(attrs), 0));
assert((attrs[i].dp_flags & 0x1f) == 2);
}
bool release_build = false;
if (fcntl(fd[0], F_RECYCLE)) {
assert_equal_int(errno, ENOTTY);
release_build = true;
}
if (release_build)
goto exit;
for (unsigned i = 0; i < MAX_FILES; i ++) {
hfs_key_roll_args_t args;
args.api_version = HFS_KR_API_LATEST_VERSION;
args.operation = HFS_KR_OP_SET_INFO;
args.key_revision = 0x0200;
args.key_os_version = CP_OS_VERS_PRE_71;
assert_no_err(ffsctl(fd[i], HFSIOC_KEY_ROLL, &args, 0));
args.operation = HFS_KR_OP_STATUS;
assert_no_err(ffsctl(fd[i], HFSIOC_KEY_ROLL, &args, 0));
assert(args.done == -1
&& args.key_revision == 0x0200
&& args.key_os_version == CP_OS_VERS_PRE_71);
}
max_ids_per_iter = 48;
count = 0;
bzero(file_ids, 4 * max_ids);
struct cp_listids list_file_ids = {
.api_version = CPLIDS_API_VERSION_1,
.flags = CPLID_MAX_OS_VERSION | CPLID_PROT_CLASS_B,
.max_key_os_version = CP_OS_VERS_71,
};
do {
list_file_ids.count = max_ids_per_iter;
list_file_ids.file_ids = file_ids + count;
if (fsctl("/private/var", HFSIOC_CP_LIST_IDS, &list_file_ids, 0) < 0) {
assert_with_errno(errno == EINTR);
count = 0;
bzero(list_file_ids.state, sizeof(list_file_ids.state));
continue;
}
count += list_file_ids.count;
assert(count < max_ids);
} while (list_file_ids.count == max_ids_per_iter);
assert(count == MAX_FILES);
statfs("/private/var", &sfs);
for (i = 0; i < count; i++) {
char path_name[PATH_MAX];
if (fsgetpath(path_name, sizeof(path), &sfs.f_fsid,
(uint64_t)file_ids[i]) < 0) {
assert_with_errno(errno == ENOENT);
continue;
}
assert(file_ids[i] == attrs[i].file_id);
}
exit:
free(buf);
free(file_ids);
for (i = 0; i < MAX_FILES; i++) {
assert_no_err(close(fd[i]));
if (path[i]) {
unlink(path[i]);
free(path[i]);
}
}
return 0;
}
#endif // TARGET_OS_EMBEDDED