#define _POSIX_C_SOURCE 200809L #include #include #include #include #include #include #include #include #include #include #include static uint64_t parse_number(const char *text, const char *what) { char *end; uintmax_t value; errno = 0; value = strtoumax(text, &end, 0); if (errno != 0 || *text == '\0' || *end != '\0' || value > INT64_MAX) errx(2, "invalid %s: %s", what, text); return ((uint64_t)value); } static void write_all(int fd, const unsigned char *buffer, size_t length) { size_t done; ssize_t written; for (done = 0; done < length; done += (size_t)written) { written = write(fd, buffer + done, length - done); if (written < 0) err(1, "write output"); } } static void pread_range(const char *path, uint64_t raw_offset, uint64_t raw_length, const char *output) { unsigned char buffer[65536]; uint64_t done; ssize_t count; size_t request; int fd, outfd; if (raw_length > INT64_MAX - raw_offset) errx(2, "offset plus length overflows off_t"); fd = open(path, O_RDONLY); if (fd < 0) err(1, "open %s", path); outfd = open(output, O_WRONLY | O_CREAT | O_TRUNC, 0600); if (outfd < 0) err(1, "open %s", output); for (done = 0; done < raw_length; done += (uint64_t)count) { request = raw_length - done < sizeof(buffer) ? (size_t)(raw_length - done) : sizeof(buffer); count = pread(fd, buffer, request, (off_t)(raw_offset + done)); if (count < 0) err(1, "pread %s at %ju", path, (uintmax_t)(raw_offset + done)); if (count == 0) errx(1, "unexpected EOF at %ju", (uintmax_t)(raw_offset + done)); write_all(outfd, buffer, (size_t)count); } if (close(outfd) != 0 || close(fd) != 0) err(1, "close"); printf("bytes=%ju offset=%ju\n", (uintmax_t)raw_length, (uintmax_t)raw_offset); } static void expect_error(const char *path, int expected) { unsigned char buffer[65536]; ssize_t count; int fd; fd = open(path, O_RDONLY); if (fd < 0) { if (errno != expected) errx(1, "open returned %s, expected errno %d", strerror(errno), expected); printf("expected_errno=%d stage=open\n", expected); return; } for (;;) { errno = 0; count = read(fd, buffer, sizeof(buffer)); if (count < 0) break; if (count == 0) errx(1, "read reached EOF without expected errno %d", expected); } if (errno != expected) errx(1, "read returned %s, expected errno %d", strerror(errno), expected); if (close(fd) != 0) err(1, "close"); printf("expected_errno=%d stage=read\n", expected); } int main(int argc, char **argv) { uint64_t offset, length, error_number; if (argc == 6 && strcmp(argv[1], "pread") == 0) { offset = parse_number(argv[3], "offset"); length = parse_number(argv[4], "length"); pread_range(argv[2], offset, length, argv[5]); return (0); } if (argc == 4 && strcmp(argv[1], "expect-error") == 0) { error_number = parse_number(argv[3], "errno"); if (error_number == 0 || error_number > INT_MAX) errx(2, "errno is out of range"); expect_error(argv[2], (int)error_number); return (0); } errx(2, "usage: %s pread FILE OFFSET LENGTH OUTPUT | " "expect-error FILE ERRNO", argv[0]); }