176 lines
4.2 KiB
C
176 lines
4.2 KiB
C
#define _POSIX_C_SOURCE 200809L
|
|
|
|
#include <sys/types.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_offset(const char *text, off_t *value)
|
|
{
|
|
char *end;
|
|
long long parsed;
|
|
|
|
errno = 0;
|
|
parsed = strtoll(text, &end, 10);
|
|
if (errno != 0 || end == text || *end != '\0' || parsed < 0)
|
|
return (-1);
|
|
*value = (off_t)parsed;
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
parse_size(const char *text, size_t *value)
|
|
{
|
|
char *end;
|
|
unsigned long parsed;
|
|
|
|
errno = 0;
|
|
parsed = strtoul(text, &end, 10);
|
|
if (errno != 0 || end == text || *end != '\0' || parsed == 0 ||
|
|
parsed > 1024 * 1024)
|
|
return (-1);
|
|
*value = (size_t)parsed;
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
open_pair(const char *path, const char *reference, int *actual_fd,
|
|
int *expected_fd)
|
|
{
|
|
|
|
*actual_fd = open(path, O_RDONLY);
|
|
*expected_fd = open(reference, O_RDONLY);
|
|
if (*actual_fd >= 0 && *expected_fd >= 0)
|
|
return (0);
|
|
perror("open B28 range input");
|
|
if (*actual_fd >= 0)
|
|
close(*actual_fd);
|
|
if (*expected_fd >= 0)
|
|
close(*expected_fd);
|
|
return (1);
|
|
}
|
|
|
|
static int
|
|
check_range(const char *path, const char *reference, off_t offset, size_t size)
|
|
{
|
|
unsigned char *actual, *expected;
|
|
ssize_t actual_count, expected_count;
|
|
int actual_fd, expected_fd, result;
|
|
|
|
actual = malloc(size);
|
|
expected = malloc(size);
|
|
if (actual == NULL || expected == NULL) {
|
|
free(actual);
|
|
free(expected);
|
|
return (1);
|
|
}
|
|
if (open_pair(path, reference, &actual_fd, &expected_fd) != 0) {
|
|
free(actual);
|
|
free(expected);
|
|
return (1);
|
|
}
|
|
actual_count = pread(actual_fd, actual, size, offset);
|
|
expected_count = pread(expected_fd, expected, size, offset);
|
|
result = actual_count == (ssize_t)size && expected_count == (ssize_t)size &&
|
|
memcmp(actual, expected, size) == 0 ? 0 : 1;
|
|
if (result != 0)
|
|
fprintf(stderr, "range mismatch offset=%jd size=%zu actual=%zd expected=%zd errno=%d\n",
|
|
(intmax_t)offset, size, actual_count, expected_count, errno);
|
|
close(actual_fd);
|
|
close(expected_fd);
|
|
free(actual);
|
|
free(expected);
|
|
return (result);
|
|
}
|
|
|
|
static int
|
|
check_range_errno(const char *path, off_t offset, size_t size,
|
|
int expected_errno)
|
|
{
|
|
unsigned char *buffer;
|
|
ssize_t count;
|
|
int descriptor, result;
|
|
|
|
buffer = malloc(size);
|
|
if (buffer == NULL)
|
|
return (1);
|
|
descriptor = open(path, O_RDONLY);
|
|
if (descriptor < 0) {
|
|
perror("open B28 damaged payload");
|
|
free(buffer);
|
|
return (1);
|
|
}
|
|
errno = 0;
|
|
count = pread(descriptor, buffer, size, offset);
|
|
result = count < 0 && errno == expected_errno ? 0 : 1;
|
|
if (result != 0)
|
|
fprintf(stderr, "range errno mismatch offset=%jd size=%zu count=%zd errno=%d expected=%d\n",
|
|
(intmax_t)offset, size, count, errno, expected_errno);
|
|
close(descriptor);
|
|
free(buffer);
|
|
return (result);
|
|
}
|
|
|
|
static int
|
|
check_full_errno(const char *path, int expected_errno)
|
|
{
|
|
unsigned char buffer[4096];
|
|
ssize_t count;
|
|
int descriptor;
|
|
|
|
descriptor = open(path, O_RDONLY);
|
|
if (descriptor < 0) {
|
|
if (errno == expected_errno)
|
|
return (0);
|
|
perror("open B28 damaged payload");
|
|
return (1);
|
|
}
|
|
for (;;) {
|
|
errno = 0;
|
|
count = read(descriptor, buffer, sizeof(buffer));
|
|
if (count < 0) {
|
|
int actual_errno = errno;
|
|
|
|
close(descriptor);
|
|
if (actual_errno == expected_errno)
|
|
return (0);
|
|
fprintf(stderr, "full errno=%d expected=%d\n", actual_errno,
|
|
expected_errno);
|
|
return (1);
|
|
}
|
|
if (count == 0) {
|
|
close(descriptor);
|
|
fprintf(stderr, "damaged extent reached clean EOF\n");
|
|
return (1);
|
|
}
|
|
}
|
|
}
|
|
|
|
int
|
|
main(int argc, char **argv)
|
|
{
|
|
off_t offset;
|
|
size_t size;
|
|
|
|
if (argc == 6 && strcmp(argv[1], "range") == 0 &&
|
|
parse_offset(argv[4], &offset) == 0 &&
|
|
parse_size(argv[5], &size) == 0)
|
|
return (check_range(argv[2], argv[3], offset, size));
|
|
if (argc == 6 && strcmp(argv[1], "range-errno") == 0 &&
|
|
parse_offset(argv[3], &offset) == 0 &&
|
|
parse_size(argv[4], &size) == 0)
|
|
return (check_range_errno(argv[2], offset, size, atoi(argv[5])));
|
|
if (argc == 4 && strcmp(argv[1], "full-errno") == 0)
|
|
return (check_full_errno(argv[2], atoi(argv[3])));
|
|
fprintf(stderr, "usage: %s range PATH REFERENCE OFFSET SIZE | range-errno PATH OFFSET SIZE ERRNO | full-errno PATH ERRNO\n",
|
|
argv[0]);
|
|
return (2);
|
|
}
|