128 lines
3.6 KiB
C
128 lines
3.6 KiB
C
#include <sys/param.h>
|
|
#include <sys/mount.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/types.h>
|
|
|
|
#include <err.h>
|
|
#include <dirent.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 uint64_t
|
|
parse_u64(const char *text)
|
|
{
|
|
char *end;
|
|
uintmax_t value;
|
|
|
|
errno = 0;
|
|
value = strtoumax(text, &end, 0);
|
|
if (errno != 0 || *text == '\0' || *end != '\0' || value > UINT64_MAX)
|
|
errx(2, "invalid integer: %s", text);
|
|
return ((uint64_t)value);
|
|
}
|
|
|
|
static void
|
|
stat_blocks(const char *path, const char *expected_text)
|
|
{
|
|
fhandle_t handle;
|
|
struct stat direct, by_handle;
|
|
uint64_t expected;
|
|
|
|
expected = parse_u64(expected_text);
|
|
if (stat(path, &direct) != 0)
|
|
err(1, "stat %s", path);
|
|
if (getfh(path, &handle) != 0)
|
|
err(1, "getfh %s", path);
|
|
if (fhstat(&handle, &by_handle) != 0)
|
|
err(1, "fhstat %s", path);
|
|
if ((uint64_t)direct.st_blocks != expected ||
|
|
(uint64_t)by_handle.st_blocks != expected)
|
|
errx(1, "st_blocks direct=%jd handle=%jd expected=%" PRIu64,
|
|
(intmax_t)direct.st_blocks, (intmax_t)by_handle.st_blocks,
|
|
expected);
|
|
printf("direct_blocks=%jd handle_blocks=%jd size=%jd expected=%" PRIu64
|
|
"\n", (intmax_t)direct.st_blocks, (intmax_t)by_handle.st_blocks,
|
|
(intmax_t)direct.st_size, expected);
|
|
}
|
|
|
|
static void
|
|
expect_stat_error(const char *path, const char *expected_text)
|
|
{
|
|
struct stat status;
|
|
int expected;
|
|
|
|
expected = (int)parse_u64(expected_text);
|
|
errno = 0;
|
|
if (stat(path, &status) != -1)
|
|
errx(1, "stat unexpectedly succeeded: %s", path);
|
|
if (errno != expected)
|
|
errx(1, "stat errno=%d expected=%d", errno, expected);
|
|
printf("stat_errno=%d path=%s\n", errno, path);
|
|
}
|
|
|
|
static void
|
|
readdir_offmax(const char *path, const char *expected_text)
|
|
{
|
|
char buffer[512];
|
|
off_t base, current;
|
|
ssize_t bytes;
|
|
int descriptor, expected;
|
|
|
|
expected = (int)parse_u64(expected_text);
|
|
descriptor = open(path, O_RDONLY | O_DIRECTORY);
|
|
if (descriptor < 0)
|
|
err(1, "open %s", path);
|
|
if (lseek(descriptor, OFF_MAX, SEEK_SET) != OFF_MAX)
|
|
err(1, "lseek OFF_MAX");
|
|
base = 0;
|
|
errno = 0;
|
|
bytes = getdirentries(descriptor, buffer, sizeof(buffer), &base);
|
|
if (bytes != -1 || errno != expected)
|
|
errx(1, "OFF_MAX getdirentries bytes=%zd errno=%d expected=%d",
|
|
bytes, errno, expected);
|
|
current = lseek(descriptor, 0, SEEK_CUR);
|
|
if (current < 0 || current != OFF_MAX)
|
|
errx(1, "negative or changed post-error offset: %jd",
|
|
(intmax_t)current);
|
|
if (lseek(descriptor, 0, SEEK_SET) != 0)
|
|
err(1, "lseek zero");
|
|
base = 0;
|
|
errno = 0;
|
|
bytes = getdirentries(descriptor, buffer, sizeof(buffer), &base);
|
|
if (bytes != -1 || errno != expected)
|
|
errx(1, "zero-offset getdirentries bytes=%zd errno=%d expected=%d",
|
|
bytes, errno, expected);
|
|
current = lseek(descriptor, 0, SEEK_CUR);
|
|
if (current < 0 || current != 0)
|
|
errx(1, "negative or changed zero offset: %jd", (intmax_t)current);
|
|
if (close(descriptor) != 0)
|
|
err(1, "close %s", path);
|
|
printf("offmax_errno=%d offmax_offset=%jd zero_errno=%d zero_offset=%jd\n",
|
|
expected, (intmax_t)OFF_MAX, expected, (intmax_t)current);
|
|
}
|
|
|
|
int
|
|
main(int argc, char **argv)
|
|
{
|
|
if (argc == 4 && strcmp(argv[1], "stat-blocks") == 0) {
|
|
stat_blocks(argv[2], argv[3]);
|
|
return (0);
|
|
}
|
|
if (argc == 4 && strcmp(argv[1], "expect-stat-error") == 0) {
|
|
expect_stat_error(argv[2], argv[3]);
|
|
return (0);
|
|
}
|
|
if (argc == 4 && strcmp(argv[1], "readdir-offmax") == 0) {
|
|
readdir_offmax(argv[2], argv[3]);
|
|
return (0);
|
|
}
|
|
errx(2, "usage: %s stat-blocks PATH EXPECTED | "
|
|
"expect-stat-error PATH ERRNO | readdir-offmax PATH ERRNO", argv[0]);
|
|
}
|