1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * Copyright (c) 2018 by Delphix. All rights reserved. 14 */ 15 16 #include <stdio.h> 17 #include <fcntl.h> 18 #include <unistd.h> 19 #include <stdlib.h> 20 #include <string.h> 21 #include <assert.h> 22 #include <sys/param.h> 23 #include <sys/types.h> 24 #include <sys/stat.h> 25 #include <errno.h> 26 27 static void 28 usage(const char *msg, int exit_value) 29 { 30 (void) fprintf(stderr, "usage: get_diff file redacted_file\n%s\n", msg); 31 exit(exit_value); 32 } 33 34 /* 35 * This utility compares two files, an original and its redacted counterpart 36 * (in that order). It compares the files 512 bytes at a time, printing out 37 * any ranges (as offset and length) where the redacted file does not match 38 * the original. This output is used to verify that the expected ranges of 39 * a redacted file do not contain the original data. 40 */ 41 int 42 main(int argc, char *argv[]) 43 { 44 off_t diff_off = 0, diff_len = 0, off = 0; 45 int fd1, fd2; 46 char *fname1, *fname2; 47 char buf1[DEV_BSIZE], buf2[DEV_BSIZE]; 48 ssize_t bytes; 49 50 if (argc != 3) 51 usage("Incorrect number of arguments.", 1); 52 53 if ((fname1 = argv[1]) == NULL) 54 usage("Filename missing.", 1); 55 if ((fd1 = open(fname1, O_LARGEFILE | O_RDONLY)) < 0) { 56 perror("open1 failed"); 57 exit(1); 58 } 59 60 if ((fname2 = argv[2]) == NULL) 61 usage("Redacted filename missing.", 1); 62 if ((fd2 = open(fname2, O_LARGEFILE | O_RDONLY)) < 0) { 63 perror("open2 failed"); 64 exit(1); 65 } 66 67 while ((bytes = pread(fd1, buf1, DEV_BSIZE, off)) > 0) { 68 if (pread(fd2, buf2, DEV_BSIZE, off) < 0) { 69 if (errno == EIO) { 70 /* 71 * A read in a redacted section of a file will 72 * fail with EIO. If we get EIO, continue on 73 * but ensure that a comparison of buf1 and 74 * buf2 will fail, indicating a redacted block. 75 */ 76 buf2[0] = ~buf1[0]; 77 } else { 78 perror("pread failed"); 79 exit(1); 80 } 81 } 82 if (memcmp(buf1, buf2, bytes) == 0) { 83 if (diff_len != 0) { 84 (void) fprintf(stdout, "%lld,%lld\n", 85 (long long)diff_off, (long long)diff_len); 86 assert(off == diff_off + diff_len); 87 diff_len = 0; 88 } 89 diff_off = 0; 90 } else { 91 if (diff_len == 0) 92 diff_off = off; 93 assert(off == diff_off + diff_len); 94 diff_len += bytes; 95 } 96 off += bytes; 97 } 98 99 if (diff_len != 0) { 100 (void) fprintf(stdout, "%lld,%lld\n", (long long)diff_off, 101 (long long)diff_len); 102 } 103 104 (void) close(fd1); 105 (void) close(fd2); 106 107 return (0); 108 } 109