summaryrefslogtreecommitdiff
path: root/lib-src/make-fingerprint.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib-src/make-fingerprint.c')
-rw-r--r--lib-src/make-fingerprint.c119
1 files changed, 88 insertions, 31 deletions
diff --git a/lib-src/make-fingerprint.c b/lib-src/make-fingerprint.c
index 35bb8b98a00..dc21fc2aa9a 100644
--- a/lib-src/make-fingerprint.c
+++ b/lib-src/make-fingerprint.c
@@ -25,14 +25,25 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
#include <config.h>
+#include <limits.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/stat.h>
+
#include <sysstdio.h>
-#include <sha256.h>
+
+#include <fingerprint.h>
#include <getopt.h>
+#include <intprops.h>
+#include <min-max.h>
+#include <sha256.h>
+
+#ifndef SSIZE_MAX
+# define SSIZE_MAX TYPE_MAXIMUM (ssize_t)
+#endif
#ifdef WINDOWSNT
/* Defined to be sys_fopen in ms-w32.h, but only #ifdef emacs, so this
@@ -54,41 +65,62 @@ main (int argc, char **argv)
raw = true;
break;
case 'h':
- printf ("make-fingerprint [-r] FILES...: compute a hash\n");
- return 0;
+ printf ("make-fingerprint [-r] FILE: replace or compute a hash\n");
+ return EXIT_SUCCESS;
default:
- return 1;
+ return EXIT_FAILURE;
}
}
struct sha256_ctx ctx;
sha256_init_ctx (&ctx);
- for (int i = optind; i < argc; ++i)
+ if (argc - optind != 1)
{
- FILE *f = fopen (argv[i], "r" FOPEN_BINARY);
- if (!f)
- {
- fprintf (stderr, "%s: Error: could not open %s\n",
- argv[0], argv[i]);
- return 1;
- }
+ fprintf (stderr, "%s: missing or extra file operand\n", argv[0]);
+ return EXIT_FAILURE;
+ }
- char buf[128*1024];
- do
- {
- size_t chunksz = fread (buf, 1, sizeof (buf), f);
- if (ferror (f))
- {
- fprintf (stderr, "%s: Error: could not read %s\n",
- argv[0], argv[i]);
- return 1;
- }
- sha256_process_bytes (buf, chunksz, &ctx);
- } while (!feof (f));
- fclose (f);
+ FILE *f = fopen (argv[1], raw ? "r" FOPEN_BINARY : "r+" FOPEN_BINARY);
+ struct stat st;
+ if (!f || fstat (fileno (f), &st) != 0)
+ {
+ perror (argv[1]);
+ return EXIT_FAILURE;
}
+ if (!S_ISREG (st.st_mode))
+ {
+ fprintf (stderr, "%s: Error: %s is not a regular file\n",
+ argv[0], argv[1]);
+ return EXIT_FAILURE;
+ }
+
+ ptrdiff_t maxlen = min (min (TYPE_MAXIMUM (off_t), PTRDIFF_MAX),
+ min (SIZE_MAX, SSIZE_MAX));
+ if (maxlen <= st.st_size)
+ {
+ fprintf (stderr, "%s: %s: file too big\n", argv[0], argv[1]);
+ return EXIT_FAILURE;
+ }
+
+ char *buf = malloc (st.st_size + 1);
+ if (!buf)
+ {
+ perror ("malloc");
+ return EXIT_FAILURE;
+ }
+
+ size_t chunksz = fread (buf, 1, st.st_size + 1, f);
+ if (ferror (f) || chunksz != st.st_size)
+ {
+ fprintf (stderr, "%s: Error: could not read %s\n",
+ argv[0], argv[1]);
+ return EXIT_FAILURE;
+ }
+
+ sha256_process_bytes (buf, chunksz, &ctx);
+
unsigned char digest[32];
sha256_finish_ctx (&ctx, digest);
@@ -99,12 +131,37 @@ main (int argc, char **argv)
}
else
{
- puts ("#include \"fingerprint.h\"\n"
- "unsigned char const fingerprint[] =\n"
- "{");
- for (int i = 0; i < 32; ++i)
- printf ("\t0x%02X,\n", digest[i]);
- puts ("};");
+ char *finger = memmem (buf, chunksz, fingerprint, sizeof fingerprint);
+ if (!finger)
+ {
+ fprintf (stderr, "%s: %s: missing fingerprint\n", argv[0], argv[1]);
+ return EXIT_FAILURE;
+ }
+ else if (memmem (finger + 1, buf + chunksz - (finger + 1),
+ fingerprint, sizeof fingerprint))
+ {
+ fprintf (stderr, "%s: %s: two occurrences of fingerprint\n",
+ argv[0], argv[1]);
+ return EXIT_FAILURE;
+ }
+
+ if (fseeko (f, finger - buf, SEEK_SET) != 0)
+ {
+ perror (argv[1]);
+ return EXIT_FAILURE;
+ }
+
+ if (fwrite (digest, 1, sizeof digest, f) != sizeof digest)
+ {
+ perror (argv[1]);
+ return EXIT_FAILURE;
+ }
+ }
+
+ if (fclose (f) != 0)
+ {
+ perror (argv[1]);
+ return EXIT_FAILURE;
}
return EXIT_SUCCESS;