diff 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
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/checksum/checksum.c	Sat Dec 22 17:52:45 2007 -0500
@@ -0,0 +1,260 @@
+/*
+ * 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;
+}