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(char *msg, int exit_value) 29 { 30 (void) fprintf(stderr, "get_diff file redacted_file\n"); 31 (void) fprintf(stderr, "%s\n", msg); 32 exit(exit_value); 33 } 34 35 /* 36 * This utility compares two files, an original and its redacted counterpart 37 * (in that order). It compares the files 512 bytes at a time, printing out 38 * any ranges (as offset and length) where the redacted file does not match 39 * the original. This output is used to verify that the expected ranges of 40 * a redacted file do not contain the original data. 41 */ 42 int 43 main(int argc, char *argv[]) 44 { 45 off_t diff_off = 0, diff_len = 0, off = 0; 46 int fd1, fd2; 47 char *fname1, *fname2; 48 char buf1[DEV_BSIZE], buf2[DEV_BSIZE]; 49 ssize_t bytes; 50 51 if (argc != 3) 52 usage("Incorrect number of arguments.", 1); 53 54 if ((fname1 = argv[1]) == NULL) 55 usage("Filename missing.", 1); 56 if ((fd1 = open(fname1, O_LARGEFILE | O_RDONLY)) < 0) { 57 perror("open1 failed"); 58 exit(1); 59 } 60 61 if ((fname2 = argv[2]) == NULL) 62 usage("Redacted filename missing.", 1); 63 if ((fd2 = open(fname2, O_LARGEFILE | O_RDONLY)) < 0) { 64 perror("open2 failed"); 65 exit(1); 66 } 67 68 while ((bytes = pread(fd1, buf1, DEV_BSIZE, off)) > 0) { 69 if (pread(fd2, buf2, DEV_BSIZE, off) < 0) { 70 if (errno == EIO) { 71 /* 72 * A read in a redacted section of a file will 73 * fail with EIO. If we get EIO, continue on 74 * but ensure that a comparison of buf1 and 75 * buf2 will fail, indicating a redacted block. 76 */ 77 buf2[0] = ~buf1[0]; 78 } else { 79 perror("pread failed"); 80 exit(1); 81 } 82 } 83 if (memcmp(buf1, buf2, bytes) == 0) { 84 if (diff_len != 0) { 85 (void) fprintf(stdout, "%lld,%lld\n", 86 (long long)diff_off, (long long)diff_len); 87 assert(off == diff_off + diff_len); 88 diff_len = 0; 89 } 90 diff_off = 0; 91 } else { 92 if (diff_len == 0) 93 diff_off = off; 94 assert(off == diff_off + diff_len); 95 diff_len += bytes; 96 } 97 off += bytes; 98 } 99 100 if (diff_len != 0 && diff_len != 0) { 101 (void) fprintf(stdout, "%lld,%lld\n", (long long)diff_off, 102 (long long)diff_len); 103 } 104 105 (void) close(fd1); 106 (void) close(fd2); 107 108 return (0); 109 } 110