Files
erofs-freebsd-out-tree/tests/g3_vfs_probe.c
T
2026-08-13 10:44:59 +02:00

209 lines
5.4 KiB
C

#define _POSIX_C_SOURCE 200809L
#include <sys/stat.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
static int
parse_errno(const char *text)
{
char *end;
long value;
errno = 0;
value = strtol(text, &end, 0);
if (errno != 0 || *text == '\0' || *end != '\0' || value <= 0 ||
value > 255)
errx(2, "invalid errno: %s", text);
return ((int)value);
}
static int
run_operation(const char *operation, const char *path)
{
struct stat sb;
int fd;
if (strcmp(operation, "stat") == 0)
return (stat(path, &sb));
if (strcmp(operation, "lstat") == 0)
return (lstat(path, &sb));
if (strcmp(operation, "open-read") == 0) {
fd = open(path, O_RDONLY);
if (fd < 0)
return (-1);
return (close(fd));
}
if (strcmp(operation, "open-rdwr") == 0) {
fd = open(path, O_RDWR);
if (fd < 0)
return (-1);
return (close(fd));
}
if (strcmp(operation, "access-read") == 0)
return (access(path, R_OK));
if (strcmp(operation, "access-write") == 0)
return (access(path, W_OK));
if (strcmp(operation, "access-exec") == 0)
return (access(path, X_OK));
if (strcmp(operation, "chmod") == 0)
return (chmod(path, 0777));
if (strcmp(operation, "chown") == 0)
return (chown(path, 65534, 65534));
if (strcmp(operation, "truncate") == 0)
return (truncate(path, 0));
if (strcmp(operation, "create") == 0) {
fd = open(path, O_WRONLY | O_CREAT | O_EXCL, 0600);
if (fd < 0)
return (-1);
if (close(fd) != 0)
return (-1);
return (unlink(path));
}
errx(2, "unknown operation: %s", operation);
}
static void
expect_result(const char *operation, const char *path, int expected_errno)
{
int error, result;
errno = 0;
result = run_operation(operation, path);
error = errno;
if (expected_errno == 0) {
if (result != 0)
errx(1, "%s %s returned errno %d (%s)", operation, path,
error, strerror(error));
printf("op=%s result=success errno=0\n", operation);
return;
}
if (result == 0)
errx(1, "%s %s unexpectedly succeeded", operation, path);
if (error != expected_errno)
errx(1, "%s %s returned errno %d (%s), expected %d", operation,
path, error, strerror(error), expected_errno);
printf("op=%s result=error errno=%d message=%s\n", operation,
error, strerror(error));
}
static long
checked_pathconf(const char *path, int name, const char *label, int *errorp)
{
long value;
errno = 0;
value = pathconf(path, name);
*errorp = value == -1 ? errno : 0;
if (*errorp != 0)
printf("%s=error:%d ", label, *errorp);
else
printf("%s=%ld ", label, value);
return (value);
}
static void
show_pathconf(const char *path)
{
int chown_error, filesizebits_error, link_error, name_error,
no_trunc_error, path_error;
long chown_restricted, filesizebits, link_max, name_max, no_trunc,
path_max;
name_max = checked_pathconf(path, _PC_NAME_MAX, "name_max",
&name_error);
path_max = checked_pathconf(path, _PC_PATH_MAX, "path_max",
&path_error);
filesizebits = checked_pathconf(path, _PC_FILESIZEBITS, "filesizebits",
&filesizebits_error);
link_max = checked_pathconf(path, _PC_LINK_MAX, "link_max",
&link_error);
no_trunc = checked_pathconf(path, _PC_NO_TRUNC, "no_trunc",
&no_trunc_error);
chown_restricted = checked_pathconf(path, _PC_CHOWN_RESTRICTED,
"chown_restricted", &chown_error);
putchar('\n');
if (name_error != 0 || path_error != 0 || filesizebits_error != 0 ||
link_error != 0 || no_trunc_error != 0 || chown_error != 0 ||
name_max != 255 || path_max <= 0 || filesizebits != 64 ||
link_max <= 0 || no_trunc != 1 || chown_restricted != 1)
errx(1, "unexpected EROFS pathconf values");
}
static void
show_readlink(const char *path)
{
unsigned char target[4096];
uint64_t hash;
ssize_t length;
length = readlink(path, (char *)target, sizeof(target));
if (length < 0)
err(1, "readlink %s", path);
if ((size_t)length == sizeof(target))
errx(1, "symlink target is too long");
hash = UINT64_C(14695981039346656037);
for (ssize_t index = 0; index < length; index++) {
hash ^= target[index];
hash *= UINT64_C(1099511628211);
}
target[length] = '\0';
printf("length=%zd fnv1a64=%016" PRIx64 " target=%s\n", length,
hash, target);
}
static void
show_stat(const char *path)
{
struct stat sb;
if (lstat(path, &sb) != 0)
err(1, "lstat %s", path);
printf("ino=%ju mode=%#jo uid=%ju gid=%ju nlink=%ju size=%jd "
"blocks=%jd blksize=%jd",
(uintmax_t)sb.st_ino, (uintmax_t)sb.st_mode,
(uintmax_t)sb.st_uid, (uintmax_t)sb.st_gid,
(uintmax_t)sb.st_nlink, (intmax_t)sb.st_size,
(intmax_t)sb.st_blocks, (intmax_t)sb.st_blksize);
#ifdef __FreeBSD__
printf(" gen=%ju", (uintmax_t)sb.st_gen);
#endif
putchar('\n');
}
int
main(int argc, char **argv)
{
if (argc == 5 && strcmp(argv[1], "expect-error") == 0) {
expect_result(argv[2], argv[3], parse_errno(argv[4]));
return (0);
}
if (argc == 4 && strcmp(argv[1], "expect-success") == 0) {
expect_result(argv[2], argv[3], 0);
return (0);
}
if (argc == 3 && strcmp(argv[1], "pathconf") == 0) {
show_pathconf(argv[2]);
return (0);
}
if (argc == 3 && strcmp(argv[1], "readlink") == 0) {
show_readlink(argv[2]);
return (0);
}
if (argc == 3 && strcmp(argv[1], "stat") == 0) {
show_stat(argv[2]);
return (0);
}
errx(2, "usage: %s expect-error OP PATH ERRNO | "
"expect-success OP PATH | pathconf PATH | readlink PATH | stat PATH",
argv[0]);
}