Mercurial > ~dholland > hg > ag > index.cgi
view checksum/checksum.c @ 14:a02e9434072e
Fix friend declaration for gcc10.
XXX: did not check it against the IBM compiler, might end up needing
XXX: to be conditional.
author | David A. Holland |
---|---|
date | Tue, 31 May 2022 00:59:42 -0400 |
parents | 13d2b8934445 |
children |
line wrap: on
line source
/* * AnaGram, A System for Syntax Directed Programming * Copyright 2006 David A. Holland. All Rights Reserved. * See the file COPYING for license and usage terms. */ /* * checksum - compute checksums of key files. * usage: checksum outputprefix symbolic-name filename * * Outputs to two files, one with the checksum info and one * the control file for insertsums. * * In each binary searches for a sums patch area, which is a * region of size TARGETSIZE beginning with the string TARGETLABEL. * This region is excluded from the sum and reported to insertsums. * * XXX the definitions of TARGETSIZE and TARGETLABEL should be shared * with the ag code. * * This module is new code as of June 2006 and should be much more * portable than the old stuff. */ #include <sys/types.h> #include <sys/stat.h> #include <stdio.h> #include <stdarg.h> #include <stdint.h> #include <stdlib.h> #include <string.h> #include <assert.h> #include <unistd.h> #include <fcntl.h> #include <getopt.h> #include <errno.h> #include "bits.h" #ifndef O_BINARY #define O_BINARY 0 #define O_TEXT 0 #endif #define TARGETSIZE 512 #define TARGETLABEL "Checksum data:\n" static FILE *datfile, *ctlfile; #if 0 /* The file extensions depend on the platform we're building for. */ typedef enum { EXEEXT, SHLIBEXT, HLPEXT, } whichext; /* Information about files we checksum. */ struct fileinfo { const char *basename; whichext ext; int istarget; const char *tag; }; /* These are the files. */ static const struct fileinfo files[] = { { "ag", EXEEXT, 0, "ag" }, { "agcl", EXEEXT, 0, "agcl" }, { "ag1", SHLIBEXT, 1, "ag1" }, { "AnaGram", HLPEXT, 0, "hlp" }, }; static const unsigned numfiles = sizeof(files) / sizeof(files[0]); #endif /* The name of this program, from argv[0]. */ static const char *me; //////////////////////////////////////////////////////////// static off_t filelength(int fd) { struct stat statbuf; fstat(fd, &statbuf); return statbuf.st_size; } static void setme(const char *av0) { me = strrchr(av0, '/'); if (me) { me++; } else { me = av0; } } static void die(const char *fmt, ...) { va_list ap; fprintf(stderr, "%s: ", me); va_start(ap, fmt); vfprintf(stderr, fmt, ap); fputc('\n', stderr); exit(EXIT_FAILURE); } //////////////////////////////////////////////////////////// static void openoutput(const char *prefix) { char buf[128]; snprintf(buf, sizeof(buf), "%s.dat", prefix); datfile = fopen(buf, "at"); if (!datfile) { die("%s: fopen failed", buf); } snprintf(buf, sizeof(buf), "%s.ctl", prefix); ctlfile = fopen(buf, "at"); if (!ctlfile) { die("%s: fopen failed", buf); } } static void closeoutput(void) { fclose(datfile); fclose(ctlfile); } //////////////////////////////////////////////////////////// /* * Note: allocates a zero byte after the end of the file * (the checksum code demands this) */ static char *loadfile(const char *path, size_t *len_ret) { int fd; char *buf; off_t length; ssize_t nread; fd = open(path, O_BINARY|O_RDONLY); if (fd < 0) { die("%s: %s", path, strerror(errno)); } length = filelength(fd); if (length > 1000000000L) { // paranoia is good die("Unreasonably large file"); } buf = malloc(length+1); if (!buf) { die("malloc failed"); } nread = read(fd, buf, length); if (nread < 0) { die("%s: read: %s", path, strerror(errno)); } if (nread != length) { die("%s: read: short count", path); } close(fd); buf[length] = 0; *len_ret = length; return buf; } static void unloadfile(char *buf) { free(buf); } //////////////////////////////////////////////////////////// static int search(const char *data, size_t len, size_t *pos_ret) { static const char tag[] = TARGETLABEL; static unsigned expected = 0; static size_t start = 0; size_t pos = 0; for (pos=0; pos<len; pos++) { int ch = data[pos]; if (ch == tag[expected]) { if (expected==0) { start = pos; } expected++; if (tag[expected]==0) { /* found */ *pos_ret = start; return 1; } } else { expected = 0; } } return 0; } //////////////////////////////////////////////////////////// static void sumfile(const char *sym, const char *path) { char *data; uint32_t sum; size_t length, patchpos; int haspatcharea; data = loadfile(path, &length); haspatcharea = search(data, length, &patchpos); sum = dosum(data, length, haspatcharea ? patchpos : 0, TARGETSIZE); unloadfile(data); if (haspatcharea && patchpos==0) { die("%s: patch area is at file offset 0", path); } fprintf(datfile, "%s=%lu,%lu", sym, (unsigned long) length, (unsigned long) sum); if (haspatcharea) { fprintf(datfile, "@%lu", (unsigned long) patchpos); fprintf(ctlfile, "%s %lu\n", path, (unsigned long) patchpos); } else { fprintf(ctlfile, "# %s no-patch-area\n", path); } fprintf(datfile, "\n"); } //////////////////////////////////////////////////////////// static void usage(void) { die("Usage: %s outputprefix symbolic-name pathname", me); } int main(int argc, char *argv[]) { const char *out, *sym, *path; setme(argv[0]); if (argc != 4) { usage(); } out = argv[1]; sym = argv[2]; path = argv[3]; openoutput(out); sumfile(sym, path); closeoutput(); return EXIT_SUCCESS; }