1 // SPDX-License-Identifier: CDDL-1.0
2 /*
3 * This file and its contents are supplied under the terms of the
4 * Common Development and Distribution License ("CDDL"), version 1.0.
5 * You may only use this file in accordance with the terms of version
6 * 1.0 of the CDDL.
7 *
8 * A full copy of the text of the CDDL should have accompanied this
9 * source. A copy of the CDDL is also available via the Internet at
10 * http://www.illumos.org/license/CDDL.
11 */
12
13 /*
14 * Copyright (c) 2018 by Delphix. All rights reserved.
15 */
16
17 #include <stdio.h>
18 #include <fcntl.h>
19 #include <unistd.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <assert.h>
23 #include <sys/param.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <errno.h>
27
28 static void
usage(const char * msg,int exit_value)29 usage(const char *msg, int exit_value)
30 {
31 (void) fprintf(stderr, "usage: get_diff file redacted_file\n%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
main(int argc,char * argv[])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) {
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