#define _POSIX_C_SOURCE 200809L #include #include #include #include #include #include #include #include #include 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); }