comparison checksum/checksum.c @ 0:13d2b8934445

Import AnaGram (near-)release tree into Mercurial.
author David A. Holland
date Sat, 22 Dec 2007 17:52:45 -0500
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:13d2b8934445
1 /*
2 * AnaGram, A System for Syntax Directed Programming
3 * Copyright 2006 David A. Holland. All Rights Reserved.
4 * See the file COPYING for license and usage terms.
5 */
6
7 /*
8 * checksum - compute checksums of key files.
9 * usage: checksum outputprefix symbolic-name filename
10 *
11 * Outputs to two files, one with the checksum info and one
12 * the control file for insertsums.
13 *
14 * In each binary searches for a sums patch area, which is a
15 * region of size TARGETSIZE beginning with the string TARGETLABEL.
16 * This region is excluded from the sum and reported to insertsums.
17 *
18 * XXX the definitions of TARGETSIZE and TARGETLABEL should be shared
19 * with the ag code.
20 *
21 * This module is new code as of June 2006 and should be much more
22 * portable than the old stuff.
23 */
24
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <stdio.h>
28 #include <stdarg.h>
29 #include <stdint.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <assert.h>
33 #include <unistd.h>
34 #include <fcntl.h>
35 #include <getopt.h>
36 #include <errno.h>
37
38 #include "bits.h"
39
40 #ifndef O_BINARY
41 #define O_BINARY 0
42 #define O_TEXT 0
43 #endif
44
45 #define TARGETSIZE 512
46 #define TARGETLABEL "Checksum data:\n"
47
48 static FILE *datfile, *ctlfile;
49
50 #if 0
51 /* The file extensions depend on the platform we're building for. */
52 typedef enum {
53 EXEEXT,
54 SHLIBEXT,
55 HLPEXT,
56 } whichext;
57
58 /* Information about files we checksum. */
59 struct fileinfo {
60 const char *basename;
61 whichext ext;
62 int istarget;
63 const char *tag;
64 };
65
66 /* These are the files. */
67 static const struct fileinfo files[] = {
68 { "ag", EXEEXT, 0, "ag" },
69 { "agcl", EXEEXT, 0, "agcl" },
70 { "ag1", SHLIBEXT, 1, "ag1" },
71 { "AnaGram", HLPEXT, 0, "hlp" },
72 };
73 static const unsigned numfiles = sizeof(files) / sizeof(files[0]);
74 #endif
75
76 /* The name of this program, from argv[0]. */
77 static const char *me;
78
79 ////////////////////////////////////////////////////////////
80
81 static off_t filelength(int fd) {
82 struct stat statbuf;
83 fstat(fd, &statbuf);
84 return statbuf.st_size;
85 }
86
87 static void setme(const char *av0) {
88 me = strrchr(av0, '/');
89 if (me) {
90 me++;
91 }
92 else {
93 me = av0;
94 }
95 }
96
97 static void die(const char *fmt, ...) {
98 va_list ap;
99 fprintf(stderr, "%s: ", me);
100 va_start(ap, fmt);
101 vfprintf(stderr, fmt, ap);
102 fputc('\n', stderr);
103 exit(EXIT_FAILURE);
104 }
105
106 ////////////////////////////////////////////////////////////
107
108 static void openoutput(const char *prefix) {
109 char buf[128];
110
111 snprintf(buf, sizeof(buf), "%s.dat", prefix);
112 datfile = fopen(buf, "at");
113 if (!datfile) {
114 die("%s: fopen failed", buf);
115 }
116
117 snprintf(buf, sizeof(buf), "%s.ctl", prefix);
118 ctlfile = fopen(buf, "at");
119 if (!ctlfile) {
120 die("%s: fopen failed", buf);
121 }
122 }
123
124 static void closeoutput(void) {
125 fclose(datfile);
126 fclose(ctlfile);
127 }
128
129 ////////////////////////////////////////////////////////////
130
131 /*
132 * Note: allocates a zero byte after the end of the file
133 * (the checksum code demands this)
134 */
135 static char *loadfile(const char *path, size_t *len_ret) {
136 int fd;
137 char *buf;
138 off_t length;
139 ssize_t nread;
140
141 fd = open(path, O_BINARY|O_RDONLY);
142 if (fd < 0) {
143 die("%s: %s", path, strerror(errno));
144 }
145
146 length = filelength(fd);
147 if (length > 1000000000L) {
148 // paranoia is good
149 die("Unreasonably large file");
150 }
151
152 buf = malloc(length+1);
153 if (!buf) {
154 die("malloc failed");
155 }
156
157 nread = read(fd, buf, length);
158 if (nread < 0) {
159 die("%s: read: %s", path, strerror(errno));
160 }
161 if (nread != length) {
162 die("%s: read: short count", path);
163 }
164
165 close(fd);
166
167 buf[length] = 0;
168
169 *len_ret = length;
170 return buf;
171 }
172
173 static void unloadfile(char *buf) {
174 free(buf);
175 }
176
177 ////////////////////////////////////////////////////////////
178
179 static int search(const char *data, size_t len, size_t *pos_ret) {
180 static const char tag[] = TARGETLABEL;
181 static unsigned expected = 0;
182 static size_t start = 0;
183
184 size_t pos = 0;
185
186 for (pos=0; pos<len; pos++) {
187 int ch = data[pos];
188
189 if (ch == tag[expected]) {
190 if (expected==0) {
191 start = pos;
192 }
193 expected++;
194 if (tag[expected]==0) {
195 /* found */
196 *pos_ret = start;
197 return 1;
198 }
199 }
200 else {
201 expected = 0;
202 }
203 }
204
205 return 0;
206 }
207
208 ////////////////////////////////////////////////////////////
209
210 static void sumfile(const char *sym, const char *path) {
211 char *data;
212 uint32_t sum;
213 size_t length, patchpos;
214 int haspatcharea;
215
216 data = loadfile(path, &length);
217 haspatcharea = search(data, length, &patchpos);
218 sum = dosum(data, length, haspatcharea ? patchpos : 0, TARGETSIZE);
219 unloadfile(data);
220
221 if (haspatcharea && patchpos==0) {
222 die("%s: patch area is at file offset 0", path);
223 }
224
225 fprintf(datfile, "%s=%lu,%lu",
226 sym, (unsigned long) length, (unsigned long) sum);
227 if (haspatcharea) {
228 fprintf(datfile, "@%lu", (unsigned long) patchpos);
229 fprintf(ctlfile, "%s %lu\n", path, (unsigned long) patchpos);
230 }
231 else {
232 fprintf(ctlfile, "# %s no-patch-area\n", path);
233 }
234 fprintf(datfile, "\n");
235 }
236
237 ////////////////////////////////////////////////////////////
238
239 static void usage(void) {
240 die("Usage: %s outputprefix symbolic-name pathname", me);
241 }
242
243 int main(int argc, char *argv[]) {
244 const char *out, *sym, *path;
245
246 setme(argv[0]);
247 if (argc != 4) {
248 usage();
249 }
250
251 out = argv[1];
252 sym = argv[2];
253 path = argv[3];
254
255 openoutput(out);
256 sumfile(sym, path);
257 closeoutput();
258
259 return EXIT_SUCCESS;
260 }