commit:     bc4321f30bb95ab1c2112f045a4cde811045ed59
Author:     Fabian Groffen <grobian <AT> gentoo <DOT> org>
AuthorDate: Wed Jan 31 19:24:41 2024 +0000
Commit:     Fabian Groffen <grobian <AT> gentoo <DOT> org>
CommitDate: Wed Jan 31 19:24:41 2024 +0000
URL:        https://gitweb.gentoo.org/proj/portage-utils.git/commit/?id=bc4321f3

libq/hash: add hash_string function

Alternative to the implementation in PR #21, so as to reuse the same
hashing code.

We could add the interface to compute multiple hashes from the same
string when that's actually necessary.

Signed-off-by: Fabian Groffen <grobian <AT> gentoo.org>

 libq/hash.c | 137 +++++++++++++++++++++++++++++++++++++++++++++++++-----------
 libq/hash.h |   1 +
 2 files changed, 114 insertions(+), 24 deletions(-)

diff --git a/libq/hash.c b/libq/hash.c
index 9b36bb9..f3a440f 100644
--- a/libq/hash.c
+++ b/libq/hash.c
@@ -98,29 +98,54 @@ hash_hex(char *out, const unsigned char *buf, const int 
length)
        }
 }
 
-/**
- * Computes the hashes for file fname and writes the hex-representation
- * for those hashes into the address space pointed to by the return
- * pointers for these hashes.  The caller should ensure enough space is
- * available.  Only those hashes which are in the global hashes variable
- * are computed, the address space pointed to for non-used hashes are
- * left untouched, e.g. they can be NULL.  The number of bytes read from
- * the file pointed to by fname is returned in the flen argument.
- */
-int
-hash_multiple_file_fd(
-               int fd,
-               char *md5,
-               char *sha1,
-               char *sha256,
-               char *sha512,
-               char *blak2b,
+/* len func(dest,destlen,cbctx) */
+typedef size_t (*read_cb)(char *,size_t,void *);
+
+static size_t read_stdio(char *dest, size_t destlen, void *ctx)
+{
+       FILE *io = ctx;
+
+       return fread(dest, 1, destlen, io);
+}
+
+struct bufctx {
+       const char *buf;
+       size_t      buflen;
+};
+
+static size_t read_buffer(char *dest, size_t destlen, void *ctx)
+{
+       struct bufctx *membuf = ctx;
+       size_t         readlen;
+
+       readlen = destlen;
+       if (readlen > membuf->buflen)
+               readlen = membuf->buflen;
+
+       memcpy(dest, membuf->buf, readlen);
+
+       /* update buffer to the remainder */
+       membuf->buf    += readlen;
+       membuf->buflen -= readlen;
+
+       return readlen;
+}
+
+static int
+hash_multiple_internal(
+               read_cb rcb,
+               void   *ctx,
+               char   *md5,
+               char   *sha1,
+               char   *sha256,
+               char   *sha512,
+               char   *blak2b,
                size_t *flen,
-               int hashes)
+               int     hashes)
 {
-       FILE             *f;
-       char              data[8192];
        size_t            len;
+       char              data[8192];
+
        struct md5_ctx    m5;
        struct sha1_ctx   s1;
        struct sha256_ctx s256;
@@ -132,8 +157,6 @@ hash_multiple_file_fd(
 #endif
 
        *flen = 0;
-       if ((f = fdopen(fd, "r")) == NULL)
-               return -1;
 
        md5_init_ctx(&m5);
        sha1_init_ctx(&s1);
@@ -143,7 +166,7 @@ hash_multiple_file_fd(
        blake2b_init(&bl2b, BLAKE2B_OUTBYTES);
 #endif
 
-       while ((len = fread(data, 1, sizeof(data), f)) > 0) {
+       while ((len = rcb(data, sizeof(data), ctx)) > 0) {
                *flen += len;
 #pragma omp parallel sections
                {
@@ -176,7 +199,6 @@ hash_multiple_file_fd(
 #endif
                }
        }
-       fclose(f);
 
 #pragma omp parallel sections
        {
@@ -227,6 +249,41 @@ hash_multiple_file_fd(
        return 0;
 }
 
+/**
+ * Computes the hashes for file fname and writes the hex-representation
+ * for those hashes into the address space pointed to by the return
+ * pointers for these hashes.  The caller should ensure enough space is
+ * available.  Only those hashes which are in the global hashes variable
+ * are computed, the address space pointed to for non-used hashes are
+ * left untouched, e.g. they can be NULL.  The number of bytes read from
+ * the file pointed to by fname is returned in the flen argument.
+ */
+int
+hash_multiple_file_fd(
+               int fd,
+               char *md5,
+               char *sha1,
+               char *sha256,
+               char *sha512,
+               char *blak2b,
+               size_t *flen,
+               int hashes)
+{
+       FILE *f;
+       int   ret;
+
+       if ((f = fdopen(fd, "r")) == NULL)
+               return -1;
+
+       ret = hash_multiple_internal(read_stdio, f,
+                                                                md5, sha1, 
sha256, sha512, blak2b,
+                                                                flen, hashes);
+
+       fclose(f);
+
+       return ret;
+}
+
 int
 hash_multiple_file_at_cb(
                int pfd,
@@ -285,3 +342,35 @@ hash_file_at_cb(int pfd, const char *fname, int hash, 
hash_cb_t cb)
 
        return _hash_file_buf;
 }
+
+char *
+hash_string(const char *buf, ssize_t buflen, int hash)
+{
+       struct bufctx membuf;
+       size_t        dummy;
+
+       if (buflen < 0)
+               buflen = (ssize_t)strlen(buf);
+
+       membuf.buf    =  buf;
+       membuf.buflen = (size_t)buflen;
+
+       switch (hash) {
+               case HASH_MD5:
+               case HASH_SHA1:
+               case HASH_SHA256:
+               case HASH_SHA512:
+               case HASH_BLAKE2B:
+                       if (hash_multiple_internal(read_buffer, &membuf,
+                                                                          
_hash_file_buf, _hash_file_buf,
+                                                                          
_hash_file_buf, _hash_file_buf,
+                                                                          
_hash_file_buf,
+                                                                          
&dummy, hash) != 0)
+                               return NULL;
+                       break;
+               default:
+                       return NULL;
+       }
+
+       return _hash_file_buf;
+}

diff --git a/libq/hash.h b/libq/hash.h
index fb4ab5f..ffbd2ef 100644
--- a/libq/hash.h
+++ b/libq/hash.h
@@ -44,5 +44,6 @@ int hash_multiple_file_at_cb(
 char *hash_file_at_cb(int pfd, const char *filename, int hash_algo, hash_cb_t 
cb);
 #define hash_file(f, h) hash_file_at_cb(AT_FDCWD, f, h, NULL)
 #define hash_file_at(fd, f, h) hash_file_at_cb(fd, f, h, NULL)
+char *hash_string(const char *buf, ssize_t buflen, int hash);
 
 #endif

Reply via email to