]> pd.if.org Git - zpackage/blobdiff - lib/integ.c
add program to generate a hash of package contents
[zpackage] / lib / integ.c
diff --git a/lib/integ.c b/lib/integ.c
new file mode 100644 (file)
index 0000000..016302e
--- /dev/null
@@ -0,0 +1,191 @@
+#define _POSIX_C_SOURCE 200809L
+#include <string.h>
+
+#include "zpm.h"
+#include "sqlite3.h"
+#include "sha256.h"
+
+static void hash_byte(struct sha256_state *h, int ch) {
+       unsigned char buf[1];
+
+       buf[0] = ch & 0xff;
+       sha256_process(h, buf, 1);
+}
+
+/* i will be positive, we are hashing column sizes */
+static void hash_int(struct sha256_state *h, int i) {
+       int n;
+       uint64_t z;
+
+       z = i;
+
+       n = sizeof i;
+       while (n--) {
+               hash_byte(h, (int)(z & 0xff));
+               z = z>>8;
+       }
+}
+
+/*
+ * Implementation of the sha3_query(SQL,SIZE) function.
+ *
+ * This function compiles and runs the SQL statement(s) given in the argument.
+ * The results are hashed using a SIZE-bit SHA3.  The default size is 256.
+ *
+ * The format of the byte stream that is hashed is summarized as follows:
+ *
+ *       R
+ *       N
+ *       I<int>
+ *       F<ieee-float>
+ *       B<size>:<bytes>
+ *       T<size>:<text>
+ *
+ * <sql> is the original SQL text for each statement run and <n> is the size of
+ * that text.  The SQL text is UTF-8.  A single R character occurs before the
+ * start of each row.  N means a NULL value.  I mean an 8-byte little-endian
+ * integer <int>.  F is a floating point number with an 8-byte little-endian
+ * IEEE floating point value <ieee-float>.  B means blobs of <size> bytes.  T
+ * means text rendered as <size> bytes of UTF-8.  The <size> values are
+ * expressed as little endian 8 byte integers.
+ *
+ * 
+ * There are zero or more R segments, one for each row in the
+ * result set.  After each R, there are one or more N, I, F, B, or T segments,
+ * one for each column in the result set.  Segments are concatentated directly
+ * with no delimiters of any kind.
+ */
+
+static void hash_query(struct zpm *zpm, const char *zSql, struct sha256_state *h) {
+       sqlite3 *db;
+       sqlite3_stmt *pStmt = 0;
+       int nCol; /* Number of columns in the result set */
+       int i, rc;
+
+       const unsigned char *data;
+       int bytes;
+
+       double r;
+       sqlite3_uint64 u;
+       sqlite3_int64 v;
+       int j;
+       unsigned char x[9];
+
+       if (!zSql) return;
+       if (!zpm) return;
+
+       db = zpm->db;
+
+       rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zSql);
+       if (rc) {
+               zpm->dberrmsg = strdup(sqlite3_errmsg(db));
+               sqlite3_finalize(pStmt);
+               return;
+       }
+
+       nCol = sqlite3_column_count(pStmt);
+
+       while (sqlite3_step(pStmt) == SQLITE_ROW) {
+               sha256_process(h, (const unsigned char *)"R", 1);
+               for (i = 0; i < nCol; i++) {
+                       switch (sqlite3_column_type(pStmt, i)) {
+                               case SQLITE_NULL:
+                                       hash_byte(h, 'N');
+                                       continue;
+                                       break;
+                               case SQLITE_INTEGER:
+                                       v = sqlite3_column_int64(pStmt, i);
+                                       memcpy(&u, &v, 8);
+                                       for (j = 8; j >= 1; j--) {
+                                               x[j] = u & 0xff;
+                                               u >>= 8;
+                                       }
+                                       x[0] = 'I';
+                                       data = x;
+                                       bytes = 9;
+                                       break;
+                               case SQLITE_FLOAT:
+                                       r = sqlite3_column_double(pStmt, i);
+                                       memcpy(&u, &r, 8);
+                                       for (j = 8; j >= 1; j--) {
+                                               x[j] = u & 0xff;
+                                               u >>= 8;
+                                       }
+                                       x[0] = 'F';
+                                       data = x;
+                                       bytes = 9;
+                                       break;
+                               case SQLITE_TEXT:
+                                       bytes = sqlite3_column_bytes(pStmt, i);
+                                       data = sqlite3_column_text(pStmt, i);
+                                       hash_byte(h, 'T');
+                                       hash_int(h, bytes);
+                                       break;
+                               case SQLITE_BLOB:
+                                       bytes = sqlite3_column_bytes(pStmt, i);
+                                       data = sqlite3_column_blob(pStmt, i);
+                                       hash_byte(h, 'B');
+                                       hash_int(h, bytes);
+                                       break;
+                       }
+                       sha256_process(h, data, bytes);
+               }
+       }
+       sqlite3_finalize(pStmt);
+}
+
+int zpm_package_hash(struct zpm *zpm, char *pkgid, char *hash) {
+       struct sha256_state d;
+       char *sql;
+       int i;
+       unsigned char tmp[32];
+
+       if (!hash) {
+               return 0;
+       }
+
+       sha256_init(&d);
+       /* find package */
+
+       sql = sqlite3_mprintf("select package,version,release,description,architecture,url,licenses,packager,build_time from packages_pkgid where pkgid = %Q", pkgid);
+
+       hash_query(zpm, sql, &d);
+       sqlite3_free(sql);
+
+       /* hash package files */
+
+       sql = sqlite3_mprintf("select path, mode, username, groupname, configuration, "
+               "filetype, target, devmajor, devminor, mtime, hash "
+               "from packagefiles_pkgid where pkgid = %Q order by path",
+               pkgid);
+       hash_query(zpm, sql, &d);
+       sqlite3_free(sql);
+
+       sha256_done(&d, tmp);
+       for (i=0; i<32; i++) {
+               sprintf(hash+i*2, "%02x", (unsigned)tmp[i]);
+       }
+       hash[64] = 0;
+
+       return 1;
+
+}
+
+int zpm_package_sethash(struct zpm *zpm, char *pkgid, char *hash) {
+       char buf[ZPM_HASH_STRLEN + 1];
+       char *sql;
+
+       if (!hash) {
+               hash = buf;
+       }
+
+       zpm_package_hash(zpm, pkgid, hash);
+
+       sql = sqlite3_mprintf("update packages_pkgid set hash = %Q where pkgid = %Q", hash, pkgid);
+
+       zpm_exec(zpm, sql, NULL, NULL, NULL);
+       sqlite3_free(sql);
+
+       return 1;
+
+}