// SPDX-FileCopyrightText: 2025 Markus Uhlin // SPDX-License-Identifier: ISC #include #include #include #include #include #include #include #include #include #include "copyfile.h" #define PRINT_CHECKSUMS 0 #define SELF_TEST 0 static int do_post_checks(const char *p1, const char *p2) { char buf[2][41]; char *str[2]; str[0] = &buf[0][0]; str[1] = &buf[1][0]; memset(str[0], 0, sizeof(buf[0])); memset(str[1], 0, sizeof(buf[1])); if (SHA1File(p1, str[0]) != NULL && SHA1File(p2, str[1]) != NULL) { #if PRINT_CHECKSUMS puts(str[0]); puts(str[1]); #endif if (strcmp(str[0], str[1]) != 0) { warnx("%s: digest mismatch", __func__); return -1; } } else warnx("%s: failed to calculate file digest", __func__); return 0; } bool fics_copyfile(const char *p1, const char *p2, const bool post_checks) { char tmp[2048] = { '\0' }; int fd[2]; ssize_t ret[2]; ssize_t total_read = 0; ssize_t total_written = 0; if (p1 == NULL || p2 == NULL || strcmp(p1, "") == 0 || strcmp(p2, "") == 0) return false; if (!is_regular_file(p1)) { warnx("%s: not a regular file", __func__); return false; } if ((fd[0] = open(p1, O_RDONLY)) < 0) { warn("%s: open(%s, ...)", __func__, p1); return false; } fd[1] = open(p2, (O_RDWR|O_APPEND|O_CREAT|O_TRUNC), (S_IRUSR|S_IWUSR|S_IRGRP)); if (fd[1] < 0) { warn("%s: open(%s, ...)", __func__, p2); close(fd[0]); return false; } while ((ret[0] = read(fd[0], tmp, sizeof tmp)) > 0) { total_read += ret[0]; if ((ret[1] = write(fd[1], tmp, ret[0])) != ret[0]) { warnx("%s: written mismatch read", __func__); break; } total_written += ret[1]; } if (close(fd[0]) != 0) perror("close"); if (close(fd[1]) != 0) perror("close"); if (total_read != total_written) { warnx("%s: total written mismatch total read", __func__); return false; } else if (post_checks) { if (do_post_checks(p1, p2) == -1) return false; } return true; } bool is_regular_file(const char *path) { struct stat sb = { 0 }; if (path == NULL || strcmp(path, "") == 0) return false; return (stat(path, &sb) == 0 && S_ISREG(sb.st_mode)); } #if SELF_TEST int main(int argc, char *argv[]) { if (argc != 3) errx(1, "bogus number of args"); return (fics_copyfile(argv[1], argv[2], true) ? 0 : 1); } #endif