]> pd.if.org Git - zpackage/blob - lib/integ.c
add scripts to package hashing
[zpackage] / lib / integ.c
1 #define _POSIX_C_SOURCE 200809L
2 #include <stdlib.h>
3 #include <string.h>
4
5 #include "zpm.h"
6 #include "sqlite3.h"
7 #include "lib/blake2/ref/blake2.h"
8
9 static void hash_byte(struct blake2b_state__ *h, int ch) {
10         unsigned char buf[1];
11
12         buf[0] = ch & 0xff;
13         blake2b_update(h, buf, 1);
14 }
15
16 /* i will be positive, we are hashing column sizes */
17 static void hash_int(struct blake2b_state__ *h, int i) {
18         int n;
19         uint64_t z;
20
21         z = i;
22
23         n = sizeof i;
24         while (n--) {
25                 hash_byte(h, (int)(z & 0xff));
26                 z = z>>8;
27         }
28 }
29
30 /*
31  * Implementation of the sha3_query(SQL,SIZE) function.
32  *
33  * This function compiles and runs the SQL statement(s) given in the argument.
34  * The results are hashed using a SIZE-bit SHA3.  The default size is 256.
35  *
36  * The format of the byte stream that is hashed is summarized as follows:
37  *
38  *       R
39  *       N
40  *       I<int>
41  *       F<ieee-float>
42  *       B<size>:<bytes>
43  *       T<size>:<text>
44  *
45  * <sql> is the original SQL text for each statement run and <n> is the size of
46  * that text.  The SQL text is UTF-8.  A single R character occurs before the
47  * start of each row.  N means a NULL value.  I mean an 8-byte little-endian
48  * integer <int>.  F is a floating point number with an 8-byte little-endian
49  * IEEE floating point value <ieee-float>.  B means blobs of <size> bytes.  T
50  * means text rendered as <size> bytes of UTF-8.  The <size> values are
51  * expressed as little endian 8 byte integers.
52  *
53  * 
54  * There are zero or more R segments, one for each row in the
55  * result set.  After each R, there are one or more N, I, F, B, or T segments,
56  * one for each column in the result set.  Segments are concatentated directly
57  * with no delimiters of any kind.
58  */
59
60 static int hash_query(struct zpm *zpm, const char *zSql, struct blake2b_state__ *h) {
61         sqlite3 *db;
62         sqlite3_stmt *pStmt = 0;
63         int nCol; /* Number of columns in the result set */
64         int i, rc;
65
66         const unsigned char *data;
67         int bytes;
68
69         double r;
70         sqlite3_uint64 u;
71         sqlite3_int64 v;
72         int j;
73         unsigned char x[9];
74
75         if (!zSql) return 0;
76         if (!zpm) return 0;
77
78         db = zpm->db;
79
80         rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zSql);
81         if (rc) {
82                 zpm->dberrmsg = strdup(sqlite3_errmsg(db));
83                 sqlite3_finalize(pStmt);
84                 return rc;
85         }
86
87         nCol = sqlite3_column_count(pStmt);
88
89         while (sqlite3_step(pStmt) == SQLITE_ROW) {
90                 blake2b_update(h, "R", 1);
91                 for (i = 0; i < nCol; i++) {
92                         switch (sqlite3_column_type(pStmt, i)) {
93                                 case SQLITE_NULL:
94                                         hash_byte(h, 'N');
95                                         continue;
96                                         break;
97                                 case SQLITE_INTEGER:
98                                         v = sqlite3_column_int64(pStmt, i);
99                                         memcpy(&u, &v, 8);
100                                         for (j = 8; j >= 1; j--) {
101                                                 x[j] = u & 0xff;
102                                                 u >>= 8;
103                                         }
104                                         x[0] = 'I';
105                                         data = x;
106                                         bytes = 9;
107                                         break;
108                                 case SQLITE_FLOAT:
109                                         r = sqlite3_column_double(pStmt, i);
110                                         memcpy(&u, &r, 8);
111                                         for (j = 8; j >= 1; j--) {
112                                                 x[j] = u & 0xff;
113                                                 u >>= 8;
114                                         }
115                                         x[0] = 'F';
116                                         data = x;
117                                         bytes = 9;
118                                         break;
119                                 case SQLITE_TEXT:
120                                         bytes = sqlite3_column_bytes(pStmt, i);
121                                         data = sqlite3_column_text(pStmt, i);
122                                         hash_byte(h, 'T');
123                                         hash_int(h, bytes);
124                                         break;
125                                 case SQLITE_BLOB:
126                                         bytes = sqlite3_column_bytes(pStmt, i);
127                                         data = sqlite3_column_blob(pStmt, i);
128                                         hash_byte(h, 'B');
129                                         hash_int(h, bytes);
130                                         break;
131                                 default:
132                                         hash_byte(h, 'U');
133                                         continue;
134                                         break;
135                         }
136                         blake2b_update(h, data, bytes);
137                 }
138         }
139         return sqlite3_finalize(pStmt);
140 }
141
142 int zpm_package_hash(struct zpm *zpm, char *pkgid, char *hash) {
143         struct blake2b_state__ d;
144         char *sql;
145         int i;
146         unsigned char tmp[32];
147
148         if (!hash) {
149                 return 0;
150         }
151
152         /* find package */
153
154         blake2b_init(&d, 32);
155
156         sql = sqlite3_mprintf("select package,version,release,description,architecture,url,licenses,packager,build_time from packages_pkgid where pkgid = %Q", pkgid);
157
158         i = hash_query(zpm, sql, &d);
159         sqlite3_free(sql);
160         if (i) {
161                 return i;
162         }
163
164         /* hash package files */
165
166         sql = sqlite3_mprintf("select path, mode, username, groupname, configuration, "
167                 "filetype, target, device, mtime, hash "
168                 "from packagefiles_pkgid where pkgid = %Q order by path",
169                 pkgid);
170         i = hash_query(zpm, sql, &d);
171         sqlite3_free(sql);
172         if (i) {
173                 return i;
174         }
175
176         /* package dependencies */
177         sql = sqlite3_mprintf("select requires from packagedeps"
178                 " where printf('%%q-%%q-%%d',package,version,release) = %Q"
179                " order by requires",
180                 pkgid);
181         i = hash_query(zpm, sql, &d);
182         sqlite3_free(sql);
183         if (i) {
184                 return i;
185         }
186
187         /* package scripts */
188         sql = sqlite3_mprintf("select stage,hash from scripts"
189                 " where printf('%%q-%%q-%%d',package,version,release) = %Q"
190                " order by stage,hash",
191                 pkgid);
192         i = hash_query(zpm, sql, &d);
193         sqlite3_free(sql);
194         if (i) {
195                 return i;
196         }
197
198         blake2b_final(&d, tmp, sizeof tmp);
199         for (i=0; i<32; i++) {
200                 sprintf(hash+i*2, "%02x", (unsigned)tmp[i]);
201         }
202
203         return 0;
204 }
205
206 int zpm_package_sethash(struct zpm *zpm, char *pkgid, char *hash) {
207         char buf[ZPM_HASH_STRLEN + 1];
208
209         if (!hash) {
210                 hash = buf;
211         }
212
213         zpm_package_hash(zpm, pkgid, hash);
214         hash[ZPM_HASH_STRLEN] = 0;
215
216         return zpm_db_run(zpm, "update packages_pkgid set hash = %Q where pkgid = %Q", hash, pkgid);
217 }
218
219 int zpm_package_clearhash(struct zpm *zpm, char *pkgid) {
220         if (!zpm || !zpm->db) {
221                 return 1;
222         }
223
224         return zpm_db_run(zpm, "update packages_pkgid set hash = NULL where pkgid = %Q", pkgid);
225 }
226
227 char *zpm_package_gethash(struct zpm *zpm, char *pkgid, char *hash) {
228         char *saved;
229
230         if (!zpm || !zpm->db || !pkgid) {
231                 return 0;
232         }
233
234         saved = zpm_db_string(zpm, "select hash from packages_pkgid where pkgid = %Q", pkgid);
235         if (saved && hash) {
236                 strncpy(hash, saved, ZPM_HASH_STRLEN);
237                 free(saved);
238                 return hash;
239         }
240         return saved;
241 }
242
243 /* calc vs stored (hash == 0)
244  *
245  * otherwise check both.
246  * 0 == match both
247  * 1 = no match stored
248  * 2 = no match calc
249  * 3 = no match either
250  * 4 = no such pkgid
251  */
252 int zpm_package_checkhash(struct zpm *zpm, char *pkgid, char *hash) {
253         /* check calculated hash against stored hash */
254         char calc[ZPM_HASH_STRLEN];
255         char set[ZPM_HASH_STRLEN];
256         char *current;
257         int rv = 0;
258
259         zpm_package_hash(zpm, pkgid, calc);
260         current = zpm_package_gethash(zpm, pkgid, set);
261         if (!current) {
262                 rv |= 1;
263         }
264
265         if (hash) {
266                 if (current && memcmp(hash, current, ZPM_HASH_STRLEN)) {
267                         rv |= 1;
268                 }
269                 if (memcmp(hash, calc, ZPM_HASH_STRLEN)) {
270                         rv |= 2;
271                 }
272         } else {
273                 if (current) {
274                         rv = memcmp(calc, current, ZPM_HASH_STRLEN) ? 1 : 0;
275                 }
276         }
277         return rv;
278 }