A hint: This file contains one or more very long lines, so maybe it is better readable using the pure text view mode that shows the contents as wrapped lines within the browser window.
1 /******************************************************************************\ 2 * * 3 * UNIPKG (c) iSteve <isteve@bofh.cz>, 2005 * 4 * * 5 * Universal PacKaGer. * 6 * Licensed under GNU/GPL - if you don't like the software, fix it! * 7 * * 8 \******************************************************************************/ 9 10 /////////////////////////////////////////////////////////////////////////////// 11 // // 12 // B A S E I N C L U S I O N S A N D D E F I N I T I O N S // 13 // // 14 /////////////////////////////////////////////////////////////////////////////// 15 #define _GNU_SOURCE 16 #include <stdlib.h> 17 #include <stdio.h> 18 #include <stdarg.h> 19 #include <string.h> 20 #include <unistd.h> 21 #include <fnmatch.h> 22 #include <errno.h> 23 #include <dlfcn.h> 24 #include <libgen.h> 25 #include <dirent.h> 26 27 #include <sqlite3.h> 28 29 #include <sys/stat.h> 30 #include <sys/mman.h> 31 #include <sys/types.h> 32 33 #include "../common.h" 34 35 #define BUSYSLEEP 350 36 37 typedef struct { 38 sqlite3_stmt *read; 39 sqlite3_stmt *write; 40 sqlite3_stmt *write_file; 41 sqlite3_stmt *find_name; 42 sqlite3_stmt *find_file; 43 sqlite3_stmt *find_name_file; 44 45 sqlite3_stmt *begin, *end; 46 } tdbcalls; 47 48 typedef struct { 49 sqlite3 *dbid; // db handle 50 tdbcalls dbcalls; 51 unsigned long lpkg; // Last read package 52 int writeable; // Can we write? 53 } dbhandle; 54 55 typedef struct { 56 pkginfo *pinfo; 57 dbhandle *dhandle; 58 int update; 59 } callbackhandle; 60 61 62 /////////////////////////////////////////////////////////////////////////////// 63 // // 64 // B A S E F U N C T I O N S // 65 // // 66 /////////////////////////////////////////////////////////////////////////////// 67 68 // SWITCHCOLNAME() 69 // 70 // Identifies the column name. 71 // 72 // Parameters: 73 // the column name 74 // 75 // Return value: 76 // 0 if no match 77 // 1 if package name 78 // 2 if package version 79 // 3 if package description 80 // 4 if preinst 81 // 5 if postinst 82 // 6 if preremove 83 // 7 if postremove 84 static int switchcolname(char *colname) { 85 if (colname == NULL) { return 0; } 86 if (!strcmp(colname, "name")) { return 1; } 87 if (!strcmp(colname, "version")) { return 2; } 88 if (!strcmp(colname, "description")) { return 3; } 89 90 if (!strcmp(colname, "preinst")) { return 4; } 91 if (!strcmp(colname, "postinst")) { return 5; } 92 if (!strcmp(colname, "preremove")) { return 6; } 93 if (!strcmp(colname, "postremove")) { return 7; } 94 95 if (!strcmp(colname, "id")) { return 10; } 96 return 0; 97 } 98 99 /////////////////////////////////////////////////////////////////////////////// 100 // // 101 // A P I F U N C T I O N S // 102 // // 103 /////////////////////////////////////////////////////////////////////////////// 104 105 void *opendb(char *path) { 106 dbhandle *reval; 107 int err; 108 109 reval = malloc(sizeof(dbhandle)); 110 if (sqlite3_open(path, &reval->dbid)) { 111 free(reval); 112 return NULL; 113 } 114 reval->lpkg = 0; 115 reval->writeable = 1; 116 117 // Half a second busy timeout wait. 118 sqlite3_busy_timeout(reval->dbid, 500); 119 err = sqlite3_exec(reval->dbid, "CREATE TABLE packages (" 120 "id INTEGER PRIMARY KEY, " 121 "name STRING NULL, " 122 "version STRING NULL, " 123 "description STRING NULL, " 124 "preinst BLOB NULL, postinst BLOB NULL, preremove BLOB NULL, postremove BLOB NULL" 125 "); " 126 "CREATE TABLE files (" 127 "id INTEGER PRIMARY KEY, " 128 "filename STRING NULL, " 129 "pkgid INTEGER" 130 ");", NULL, NULL, NULL); 131 132 err = sqlite3_exec(reval->dbid, "PRAGMA short_column_names; PRAGMA synchronous = FULL;", NULL, NULL, NULL); 133 if (err) { 134 free(reval); 135 return NULL; 136 } 137 138 //sqlite3_prepare(reval->dbid, ";", -1, &reval->dbcalls.write, NULL); 139 140 sqlite3_prepare(reval->dbid, "INSERT INTO packages (" 141 "name, version, description, preinst, postinst, preremove, postremove" 142 ") VALUES (" 143 "?, ?, ?, ?, ?, ?, ?" 144 ");", -1, &reval->dbcalls.write, NULL); 145 146 sqlite3_prepare(reval->dbid, "INSERT INTO files (" 147 "filename, pkgid" 148 ") VALUES (" 149 "?, ?" 150 ");", -1, &reval->dbcalls.write_file, NULL); 151 152 return reval; 153 } 154 155 void rewinddb(dbhandle *handle) { 156 handle->lpkg=0; 157 } 158 159 int iswriteable(dbhandle *handle) { 160 return handle->writeable; 161 } 162 163 int closedb(dbhandle *handle) { 164 sqlite3_close(handle->dbid); 165 free(handle); 166 return 0; 167 } 168 169 int readpkg(dbhandle *handle, pkginfo *pinfo) { 170 return 1; 171 } 172 173 int writepkg(dbhandle *handle, pkginfo *pinfo) { 174 unsigned long i; 175 unsigned long lastid; 176 char *foo; 177 178 foo = sqlite3_mprintf("INSERT INTO packages (" 179 "name, version, description, preinst, postinst, preremove, postremove" 180 ") VALUES (" 181 "'%q', '%q', '%q', '%q', '%q', '%q', '%q'" 182 ");", pinfo->name, pinfo->version, pinfo->description, 183 pinfo->preinst.data, pinfo->postinst.data, pinfo->prerm.data, pinfo->postrm.data); 184 sqlite3_exec(handle->dbid, foo, NULL, NULL, NULL); 185 /* sqlite3_bind_text(handle->dbcalls.write, 1, pinfo->name, strlen(pinfo->name), SQLITE_TRANSIENT); 186 sqlite3_bind_text(handle->dbcalls.write, 2, pinfo->version, strlen(pinfo->version), SQLITE_TRANSIENT); 187 sqlite3_bind_text(handle->dbcalls.write, 3, pinfo->description, strlen(pinfo->description), SQLITE_TRANSIENT); 188 189 sqlite3_bind_blob(handle->dbcalls.write, 4, pinfo->preinst.data, pinfo->preinst.len, SQLITE_TRANSIENT); 190 sqlite3_bind_blob(handle->dbcalls.write, 5, pinfo->postinst.data, pinfo->postinst.len, SQLITE_TRANSIENT); 191 sqlite3_bind_blob(handle->dbcalls.write, 6, pinfo->prerm.data, pinfo->prerm.len, SQLITE_TRANSIENT); 192 sqlite3_bind_blob(handle->dbcalls.write, 7, pinfo->postrm.data, pinfo->postrm.len, SQLITE_TRANSIENT); 193 194 sqlite3_step(handle->dbcalls.write);*/ 195 196 lastid = sqlite3_last_insert_rowid(handle->dbid); 197 // sqlite3_reset(handle->dbcalls.write); 198 199 // sqlite3_exec(handle->dbid, "BEGIN;", NULL, NULL, NULL); 200 /* sqlite3_prepare(handle->dbid, "INSERT INTO files (" 201 "filename, pkgid" 202 ") VALUES (" 203 "?, ?" 204 ");", -1, &handle->dbcalls.write_file, NULL); 205 206 sqlite3_bind_int64(handle->dbcalls.write_file, 2, lastid);*/ 207 sqlite3_exec(handle->dbid, "BEGIN;", NULL, NULL, NULL); 208 for (i = 0; i < pinfo->filecount; i++) { 209 foo = sqlite3_mprintf("INSERT INTO files (filename, pkgid) VALUES ('%q', '%i');", pinfo->files[i].name, lastid); 210 sqlite3_exec(handle->dbid, foo, NULL, NULL, NULL); 211 sqlite3_free(foo); 212 //fprintf(stderr, " Now %s\n", pinfo->files[i].name);*/ 213 /* sqlite3_bind_text(handle->dbcalls.write_file, 1, pinfo->files[i].name, strlen(pinfo->files[i].name), SQLITE_TRANSIENT); 214 sqlite3_step(handle->dbcalls.write_file); 215 sqlite3_reset(handle->dbcalls.write_file);*/ 216 } 217 //sqlite3_reset(handle->dbcalls.write_file); 218 // sqlite3_finalize(handle->dbcalls.write_file); 219 sqlite3_exec(handle->dbid, "COMMIT; END;", NULL, NULL, NULL); 220 221 return 0; 222 } 223 224 int findpkg(dbhandle *handle, pkginfo needle, pkginfo *reval, int matchtype) { 225 return 1; 226 } 227 /*void *opendb(char *path) { 228 dbhandle *reval; 229 unsigned long i; 230 int rv; 231 232 reval = malloc(sizeof(dbhandle)); 233 234 if (sqlite3_open(path, &reval->dbid)) { free(reval); return NULL; } 235 reval->lpkg = 0; 236 237 // I HATE THIS HACK //////////////////////// 238 // We create a dummy table and drop it ///// 239 // afterwards, to check if we can write //// 240 // Damn, there must be a better way. /////// 241 i=0; 242 do { 243 rv = sqlite3_nobusy_exec_printf(reval->dbid, "CREATE TABLE testtable%02ld (id int); DROP TABLE testtable%02ld;", NULL, NULL, NULL, i, i); 244 i++; 245 } while ((rv != 0) && (rv != 8) && (i < 100)); 246 247 reval->writeable = 0; 248 switch (rv) { 249 case 0: 250 reval->writeable = 1; 251 break; 252 case 8: 253 reval->writeable = 0; 254 break; 255 default: 256 sqlite3_close(reval->dbid); 257 free(reval); 258 return NULL; 259 } 260 // END OF UGLY HACK /////////// 261 262 // This will fail if there are tables already... if there are of diferent format, bad luck 263 sqlite3_nobusy_exec(reval->dbid, "CREATE TABLE packages (id INTEGER PRIMARY KEY, name STRING NULL, version STRING NULL, description STRING NULL, preinst STRING NULL, postinst STRING NULL, preremove STRING NULL, postremove STRING NULL); CREATE TABLE files (id INTEGER PRIMARY KEY, filename STRING NULL, pkgid INTEGER);", NULL, NULL, NULL); 264 sqlite3_nobusy_exec(reval->dbid, "PRAGMA short_column_names;", NULL, NULL, NULL); 265 266 return reval; 267 } 268 void rewinddb(void *handle) { 269 ((dbhandle*)handle)->lpkg=0; 270 } 271 int iswriteable(void *handle) { 272 return ((dbhandle*)handle)->writeable; 273 } 274 int closedb(void *handle) { 275 sqlite3_close(((dbhandle*)handle)->dbid); 276 free((dbhandle*)handle); 277 return 0; 278 } 279 280 // READPKG_PKG_CALLBACK() 281 // 282 // Parses data returned by sql query asking for package info and feeds it 283 // into package descripting structure within the dataptr. 284 // 285 // Return value and parameters viz sqlite3_callback 286 static int readpkg_pkg_callback(void *dataptr, int argc, char **argv, char **azColName){ 287 int i; 288 callbackhandle *cbh; 289 290 cbh = (callbackhandle*)dataptr; 291 cbh->update = 1; 292 for (i=0; i<argc; i++) { 293 switch (switchcolname(azColName[i])) { 294 case 1: 295 cbh->pinfo->name = strdup(argv[i]); 296 break; 297 case 2: 298 cbh->pinfo->version = strdup(argv[i]); 299 break; 300 case 3: 301 cbh->pinfo->description = strdup(argv[i]); 302 break; 303 304 case 4: 305 if (strcmp(argv[i], "(NULL)")) { // This is probably not very safe. 306 cbh->pinfo->preinst = strdup(argv[i]); 307 } 308 break; 309 case 5: 310 if (strcmp(argv[i], "(NULL)")) { 311 cbh->pinfo->postinst = strdup(argv[i]); 312 } 313 break; 314 case 6: 315 if (strcmp(argv[i], "(NULL)")) { 316 cbh->pinfo->prerm = strdup(argv[i]); 317 } 318 break; 319 case 7: 320 if (strcmp(argv[i], "(NULL)")) { 321 cbh->pinfo->postrm = strdup(argv[i]); 322 } 323 break; 324 325 case 10: 326 cbh->dhandle->lpkg = strtoul(argv[i], NULL, 10); 327 break; 328 } 329 } 330 return 0; 331 } 332 333 // READPKG_PKG_CALLBACK() 334 // 335 // Parses data returned by sql query asking for package file list and feeds it 336 // into package descripting structure within the dataptr. 337 // 338 // Return value and parameters viz sqlite3_callback 339 static int readpkg_file_callback(void *dataptr, int argc, char **argv, char **azColName){ 340 int i; 341 callbackhandle *cbh; 342 343 cbh = (callbackhandle*)dataptr; 344 cbh->update = 1; 345 for (i=0; i<argc; i++) { 346 if (!strcmp(azColName[i], "filename")) { 347 cbh->pinfo->files = realloc(cbh->pinfo->files, sizeof(char*) * (cbh->pinfo->filecount + 1)); 348 cbh->pinfo->files[cbh->pinfo->filecount] = strdup(argv[i]); 349 cbh->pinfo->filecount++; 350 } 351 } 352 return 0; 353 } 354 int readpkg(void *handle, pkginfo *pinfo) { 355 callbackhandle cbh; 356 357 cbh.dhandle = (dbhandle*)handle; 358 cbh.pinfo = pinfo; 359 cbh.update = 0; 360 sqlite3_nobusy_exec_printf(((dbhandle*)handle)->dbid, "SELECT * FROM packages WHERE id >= %ld ORDER BY id ASC LIMIT 1;", readpkg_pkg_callback, (void *)(&cbh), NULL, ((dbhandle*)handle)->lpkg); 361 if (!cbh.update){ 362 ((dbhandle*)handle)->lpkg = 0; 363 return 1; 364 } 365 366 // lpkg now contains the id of the currently checked pkg 367 sqlite3_nobusy_exec_printf(((dbhandle*)handle)->dbid, "SELECT * FROM files WHERE pkgid = %ld;", readpkg_file_callback, (void *)(&cbh), NULL, ((dbhandle*)handle)->lpkg); 368 369 ((dbhandle*)handle)->lpkg++; 370 return 0; 371 } 372 int writepkg(void *handle, pkginfo *pinfo) { 373 int lastid; 374 unsigned long i; 375 376 if (sqlite3_nobusy_exec_printf(((dbhandle*)handle)->dbid, "INSERT INTO packages (name, version, description, preinst, postinst, preremove, postremove) VALUES ('%q', '%q', '%q', '%q', '%q', '%q', '%q');", NULL, NULL, NULL, pinfo->name, pinfo->version, pinfo->description, pinfo->preinst, pinfo->postinst, pinfo->prerm, pinfo->postrm) != SQLITE_OK) { 377 return 1; 378 } 379 380 lastid = sqlite3_last_insert_rowid(((dbhandle*)handle)->dbid); 381 382 for (i=0; i<pinfo->filecount; i++) { 383 sqlite3_nobusy_exec_printf(((dbhandle*)handle)->dbid, "INSERT INTO files (filename, pkgid) VALUES ('%q', %ld);", NULL, NULL, NULL, pinfo->files[i], lastid); 384 } 385 386 return 0; 387 } 388 int delpkg(void *handle, char *pneedle) { 389 return sqlite3_nobusy_exec_printf(((dbhandle*)handle)->dbid, "DELETE FROM files WHERE pkgid = ( SELECT id FROM packages WHERE name GLOB '%q' ); DELETE FROM packages WHERE name GLOB '%q';", NULL, NULL, NULL, pneedle, pneedle); 390 } 391 392 // FINDPKG_PKG_CALLBACK() 393 // 394 // Checks whether a match is for given sql query, if so, reads full package 395 // information using readpkg. 396 // 397 // Return value and parameters viz sqlite3_callback 398 static int findpkg_callback(void *dataptr, int argc, char **argv, char **azColName){ 399 callbackhandle *cbh; 400 pkginfo *tmppinfo; 401 402 cbh = (callbackhandle*)dataptr; 403 if ((!strcmp(azColName[0], "id")) || (!strcmp(azColName[0], "pkgid"))) { 404 cbh->dhandle->lpkg = strtoul(argv[0], NULL, 10); 405 if (cbh->pinfo == NULL) { 406 tmppinfo = malloc(sizeof(pkginfo)); 407 } else { 408 tmppinfo = cbh->pinfo; 409 } 410 cbh->update = readpkg((void*)cbh->dhandle, tmppinfo) ? 0 : 1; 411 if (cbh->pinfo == NULL) { 412 freepinfo(tmppinfo); 413 free(tmppinfo); 414 } 415 } 416 417 return 0; 418 } 419 int findpkg(void *handle, pkginfo needle, pkginfo *reval, int matchtype) { 420 char *sqlbuf, *buf; 421 unsigned long i, sqlbuflen; 422 callbackhandle cbh; 423 pkginfo tmppinfo; 424 425 // We first get the id of the package, then readpkg it by editing lpkg. 426 if ((needle.filecount == 0) && (matchtype & MATCH_FILE) && (!(matchtype & MATCH_NAME))) { 427 return 0; 428 } 429 430 sqlbuf = NULL; 431 if ((matchtype & MATCH_NAME) && (!(matchtype & MATCH_FILE))) { 432 sqlbuf = sqlite3_mprintf("SELECT id FROM packages WHERE id >= %ld AND name GLOB '%q' ORDER BY id ASC LIMIT 1;", ((dbhandle*)handle)->lpkg, needle.name); 433 } else if ((matchtype & MATCH_FILE) && (!(matchtype & MATCH_NAME))) { 434 sqlbuf = sqlite3_mprintf("SELECT pkgid FROM files WHERE pkgid >= %ld AND ( ", ((dbhandle*)handle)->lpkg); 435 sqlbuflen = strlen(sqlbuf) + 1; 436 for (i=0; i<needle.filecount; i++) { 437 buf = sqlite3_mprintf("filename GLOB '%q' OR ", needle.files[i]); 438 sqlbuflen += strlen(buf) + 1; 439 sqlbuf = realloc(sqlbuf, sqlbuflen); 440 strcat(sqlbuf, buf); 441 sqlite3_free(buf); 442 } 443 sqlbuflen += 18; 444 sqlbuf = realloc(sqlbuf, sqlbuflen); 445 strcat(sqlbuf, " 1=0 ) LIMIT;1"); 446 } else if ((matchtype & MATCH_NAME) && (matchtype & MATCH_FILE)) { 447 sqlbuf = sqlite3_mprintf("SELECT pkgid FROM files WHERE packages.name GLOB '%q' AND packages.id = files.pkgid AND pkgid >= %ld AND ( ", needle.name, ((dbhandle*)handle)->lpkg); 448 sqlbuflen = strlen(sqlbuf) + 1; 449 for (i=0; i<needle.filecount; i++) { 450 buf = sqlite3_mprintf("filename GLOB '%q' OR ", needle.files[i]); 451 sqlbuflen += strlen(buf) + 1; 452 sqlbuf = realloc(sqlbuf, sqlbuflen); 453 strcat(sqlbuf, buf); 454 sqlite3_free(buf); 455 } 456 sqlbuflen += 18; 457 sqlbuf = realloc(sqlbuf, sqlbuflen); 458 strcat(sqlbuf, " 1=0 ) LIMIT 1;"); 459 } 460 461 cbh.dhandle = (dbhandle*)handle; 462 cbh.pinfo = &tmppinfo; 463 cbh.update = 0; 464 sqlite3_nobusy_exec(((dbhandle*)handle)->dbid, sqlbuf, findpkg_callback, (void *)(&cbh), NULL); 465 sqlite3_free(sqlbuf); 466 467 if (cbh.update == 0) { 468 return 0; 469 } 470 471 if ((!strcmp(reval->name, needle.name)) && (matchtype & MATCH_OVRWR)) { 472 return -1; 473 } else { 474 return 1; 475 } 476 } 477 */