From 7ce66edc572eb3c47c890bfe3ce5d37cc2b0f346 Mon Sep 17 00:00:00 2001
From: Enno Boland <g@s01.de>
Date: Wed, 15 Jun 2016 23:21:29 +0200
Subject: [PATCH] lib/util_hash.c: add xbps_file_hash_raw method

this function does not mmap the target file and therefore
avoids out of memory exceptions on 32bit systems.
---
 include/xbps.h.in | 11 +++++++++++
 lib/util_hash.c   | 33 ++++++++++++++++++++++++---------
 2 files changed, 35 insertions(+), 9 deletions(-)

diff --git a/include/xbps.h.in b/include/xbps.h.in
index 6f707cb9..6c1a7964 100644
--- a/include/xbps.h.in
+++ b/include/xbps.h.in
@@ -1795,6 +1795,17 @@ bool xbps_mmap_file(const char *file, void **mmf, size_t *mmflen, size_t *filele
  */
 char *xbps_file_hash(const char *file);
 
+/**
+ * Returns a raw byte buffer with the sha256 hash for the file specified
+ * by \a file.
+ *
+ * @param[in] file Path to a file.
+ * @return A pointer to a malloc(3)ed buffer, NULL otherwise and errno
+ * is set appropiately. The pointer should be free(3)d when it's no
+ * longer needed.
+ */
+unsigned char *xbps_file_hash_raw(const char *file);
+
 /**
  * Compares the sha256 hash of the file \a file with the sha256
  * string specified by \a sha256.
diff --git a/lib/util_hash.c b/lib/util_hash.c
index 0c03c3c0..b170b432 100644
--- a/lib/util_hash.c
+++ b/lib/util_hash.c
@@ -108,24 +108,39 @@ xbps_mmap_file(const char *file, void **mmf, size_t *mmflen, size_t *filelen)
 	return true;
 }
 
+unsigned char *
+xbps_file_hash_raw(const char *file)
+{
+	int fd;
+	ssize_t len;
+	unsigned char *digest, buf[65536];
+	SHA256_CTX sha256;
+
+	if ((fd = open(file, O_RDONLY)) < 0)
+		return NULL;
+	digest = malloc(SHA256_DIGEST_LENGTH);
+	assert(digest);
+	SHA256_Init(&sha256);
+	while ((len = read(fd, buf, sizeof(buf))) > 0)
+		SHA256_Update(&sha256, buf, len);
+	SHA256_Final(digest, &sha256);
+	close(fd);
+
+	return digest;
+}
+
 char *
 xbps_file_hash(const char *file)
 {
 	char *res, hash[SHA256_DIGEST_LENGTH * 2 + 1];
-	unsigned char digest[SHA256_DIGEST_LENGTH];
-	unsigned char *mmf = NULL;
-	size_t mmflen, filelen;
+	unsigned char *digest;
 
-	if (!xbps_mmap_file(file, (void *)&mmf, &mmflen, &filelen))
+	if (!(digest = xbps_file_hash_raw(file)))
 		return NULL;
 
-	if (SHA256(mmf, filelen, digest) == NULL) {
-		(void)munmap(mmf, mmflen);
-		return NULL;
-	}
 	digest2string(digest, hash, SHA256_DIGEST_LENGTH);
 	res = strdup(hash);
-	(void)munmap(mmf, mmflen);
+	free(digest);
 
 	return res;
 }