source: branches/gsoc11-statistics/base/src/cregistry/entry.c @ 140222

Last change on this file since 140222 was 105085, checked in by snc@…, 7 years ago

merge from trunk

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 45.1 KB
Line 
1/*
2 * entry.c
3 * $Id: entry.c 105085 2013-04-09 18:46:31Z snc@macports.org $
4 *
5 * Copyright (c) 2010-2011 The MacPorts Project
6 * Copyright (c) 2007 Chris Pickel <sfiera@macports.org>
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#if HAVE_CONFIG_H
31#include <config.h>
32#endif
33
34#include "entry.h"
35#include "registry.h"
36#include "sql.h"
37#include "util.h"
38
39#include <sqlite3.h>
40#include <stdlib.h>
41#include <string.h>
42
43/*
44 * TODO: possibly, allow reg_entry_search to take different matching strategies
45 *       for different keys. I don't know of an application for this feature
46 *       yet, so no reason to bother for now.
47 *
48 * TODO: reg_entry_installed and reg_entry_imaged could benefit from the added
49 *       flexibility of -glob and -regexp too. Not a high priority, though.
50 *
51 * TODO: process the 'state' keyword in a more efficient way. I still believe
52 *       there could be benefits to be reaped in the future by allowing
53 *       arbitrary values; but at the same time the field will (or should)
54 *       always have very discrete values. These could be more efficiently dealt
55 *       with as integers.
56 *
57 * TODO: considering a "weak" flag in registry.files. The meaning of this would
58 *       be "I wish for my version of this file to be activated when I am, but
59 *       not to be deactivated when I am; nor should other ports be prevented
60 *       from overwriting this file." This would be useful for files like e.g.
61 *       perllocal.pod (or whatever it's called; the one that causes problems).
62 *
63 * TODO: expose a file's mtime attribute. This should be used during port
64 *       deactivation to determine if any files have local modifications. If so,
65 *       they should be moved aside instead of being removed when the port is
66 *       deactivated/uninstalled.
67 */
68
69/**
70 * Converts a `sqlite3_stmt` into a `reg_entry`. The first column of the stmt's
71 * row must be the id of an entry; the second either `SQLITE_NULL` or the
72 * address of the entry in memory.
73 *
74 * @param [in] userdata sqlite3 database
75 * @param [out] entry   entry described by `stmt`
76 * @param [in] stmt     `sqlite3_stmt` with appropriate columns
77 * @param [out] errPtr  unused
78 * @return              true if success; false if failure
79 */
80static int reg_stmt_to_entry(void* userdata, void** entry, void* stmt,
81        void* calldata UNUSED, reg_error* errPtr UNUSED) {
82    int is_new;
83    reg_registry* reg = (reg_registry*)userdata;
84    sqlite_int64 id = sqlite3_column_int64(stmt, 0);
85    Tcl_HashEntry* hash = Tcl_CreateHashEntry(&reg->open_entries,
86            (const char*)&id, &is_new);
87    if (is_new) {
88        reg_entry* e = malloc(sizeof(reg_entry));
89        if (!e) {
90            return 0;
91        }
92        e->reg = reg;
93        e->id = id;
94        e->proc = NULL;
95        *entry = e;
96        Tcl_SetHashValue(hash, e);
97    } else {
98        *entry = Tcl_GetHashValue(hash);
99    }
100    return 1;
101}
102
103/**
104 * Creates a new entry in the ports registry. Unlike the old
105 * `registry::new_entry`, revision, variants, and epoch are all required. That's
106 * OK because there's only one place this function is called, and it's called
107 * with all of them there.
108 *
109 * @param [in] reg      the registry to create the entry in
110 * @param [in] name     name of port
111 * @param [in] version  version of port
112 * @param [in] revision revision of port
113 * @param [in] variants variants to record
114 * @param [in] epoch    epoch of port
115 * @param [out] errPtr  on error, a description of the error that occurred
116 * @return              the entry if success; NULL if failure
117 */
118reg_entry* reg_entry_create(reg_registry* reg, char* name, char* version,
119        char* revision, char* variants, char* epoch, reg_error* errPtr) {
120    sqlite3_stmt* stmt = NULL;
121    reg_entry* entry = NULL;
122    char* query = "INSERT INTO registry.ports "
123        "(name, version, revision, variants, epoch) VALUES (?, ?, ?, ?, ?)";
124    if ((sqlite3_prepare_v2(reg->db, query, -1, &stmt, NULL) == SQLITE_OK)
125            && (sqlite3_bind_text(stmt, 1, name, -1, SQLITE_STATIC)
126                == SQLITE_OK)
127            && (sqlite3_bind_text(stmt, 2, version, -1, SQLITE_STATIC)
128                == SQLITE_OK)
129            && (sqlite3_bind_text(stmt, 3, revision, -1, SQLITE_STATIC)
130                == SQLITE_OK)
131            && (sqlite3_bind_text(stmt, 4, variants, -1, SQLITE_STATIC)
132                == SQLITE_OK)
133            && (sqlite3_bind_text(stmt, 5, epoch, -1, SQLITE_STATIC)
134                == SQLITE_OK)) {
135        int r;
136        Tcl_HashEntry* hash;
137        int is_new;
138        do {
139            r = sqlite3_step(stmt);
140            switch (r) {
141                case SQLITE_DONE:
142                    entry = malloc(sizeof(reg_entry));
143                    if (entry) {
144                        entry->id = sqlite3_last_insert_rowid(reg->db);
145                        entry->reg = reg;
146                        entry->proc = NULL;
147                        hash = Tcl_CreateHashEntry(&reg->open_entries,
148                                (const char*)&entry->id, &is_new);
149                        Tcl_SetHashValue(hash, entry);
150                    }
151                    break;
152                case SQLITE_BUSY:
153                    break;
154                default:
155                    reg_sqlite_error(reg->db, errPtr, query);
156                    break;
157            }
158        } while (r == SQLITE_BUSY);
159    } else {
160        reg_sqlite_error(reg->db, errPtr, query);
161    }
162    if (stmt) {
163        sqlite3_finalize(stmt);
164    }
165    return entry;
166}
167
168/**
169 * Opens an existing entry in the registry.
170 *
171 * @param [in] reg      registry to open entry in
172 * @param [in] name     name of port
173 * @param [in] version  version of port
174 * @param [in] revision revision of port
175 * @param [in] variants variants to record
176 * @param [in] epoch    epoch of port
177 * @param [out] errPtr  on error, a description of the error that occurred
178 * @return              the entry if success; NULL if failure
179 */
180reg_entry* reg_entry_open(reg_registry* reg, char* name, char* version,
181        char* revision, char* variants, char* epoch, reg_error* errPtr) {
182    sqlite3_stmt* stmt = NULL;
183    reg_entry* entry = NULL;
184    int lower_bound = 0;
185    char* query;
186    if (strlen(epoch) > 0) {
187        query = "SELECT id FROM registry.ports WHERE name=? AND version=? "
188        "AND revision=? AND variants=? AND epoch=?";
189    } else {
190        query = "SELECT id FROM registry.ports WHERE name=? AND version=? "
191        "AND revision=? AND variants=? AND epoch!=?";
192    }
193    if ((sqlite3_prepare_v2(reg->db, query, -1, &stmt, NULL) == SQLITE_OK)
194            && (sqlite3_bind_text(stmt, 1, name, -1, SQLITE_STATIC)
195                == SQLITE_OK)
196            && (sqlite3_bind_text(stmt, 2, version, -1, SQLITE_STATIC)
197                == SQLITE_OK)
198            && (sqlite3_bind_text(stmt, 3, revision, -1, SQLITE_STATIC)
199                == SQLITE_OK)
200            && (sqlite3_bind_text(stmt, 4, variants, -1, SQLITE_STATIC)
201                == SQLITE_OK)
202            && (sqlite3_bind_text(stmt, 5, epoch, -1, SQLITE_STATIC)
203                == SQLITE_OK)) {
204        int r;
205        do {
206            r = sqlite3_step(stmt);
207            switch (r) {
208                case SQLITE_ROW:
209                    reg_stmt_to_entry(reg, (void**)&entry, stmt, &lower_bound, errPtr);
210                    break;
211                case SQLITE_DONE:
212                    errPtr->code = REG_NOT_FOUND;
213                    errPtr->description = sqlite3_mprintf("no matching port found for: " \
214                            "name=%s, version=%s, revision=%s, variants=%s, epoch=%s", \
215                            name, version, revision, variants, epoch);
216                    errPtr->free = (reg_error_destructor*) sqlite3_free;
217                    break;
218                case SQLITE_BUSY:
219                    continue;
220                default:
221                    reg_sqlite_error(reg->db, errPtr, query);
222                    break;
223            }
224        } while (r == SQLITE_BUSY);
225    } else {
226        reg_sqlite_error(reg->db, errPtr, query);
227    }
228    if (stmt) {
229        sqlite3_finalize(stmt);
230    }
231    return entry;
232}
233
234/**
235 * Deletes an entry. After calling this, `reg_entry_free` needs to be called
236 * manually on the entry. Care should be taken to not free the entry if this
237 * deletion is rolled back.
238 *
239 * @param [in] entry   the entry to delete
240 * @param [out] errPtr on error, a description of the error that occurred
241 * @return             true if success; false if failure
242 */
243int reg_entry_delete(reg_entry* entry, reg_error* errPtr) {
244    reg_registry* reg = entry->reg;
245    int result = 0;
246    sqlite3_stmt* ports = NULL;
247    sqlite3_stmt* files = NULL;
248    sqlite3_stmt* dependencies = NULL;
249    char* ports_query = "DELETE FROM registry.ports WHERE id=?";
250    char* files_query = "DELETE FROM registry.files WHERE id=?";
251    char* dependencies_query = "DELETE FROM registry.dependencies WHERE id=?";
252    if ((sqlite3_prepare_v2(reg->db, ports_query, -1, &ports, NULL) == SQLITE_OK)
253            && (sqlite3_bind_int64(ports, 1, entry->id) == SQLITE_OK)
254            && (sqlite3_prepare_v2(reg->db, files_query, -1, &files, NULL)
255                == SQLITE_OK)
256            && (sqlite3_bind_int64(files, 1, entry->id) == SQLITE_OK)
257            && (sqlite3_prepare_v2(reg->db, dependencies_query, -1, &dependencies,
258                    NULL) == SQLITE_OK)
259            && (sqlite3_bind_int64(dependencies, 1, entry->id) == SQLITE_OK)) {
260        int r;
261        do {
262            r = sqlite3_step(ports);
263            switch (r) {
264                case SQLITE_DONE:
265                    if (sqlite3_changes(reg->db) > 0) {
266                        do {
267                            r = sqlite3_step(files);
268                            switch (r) {
269                                case SQLITE_DONE:
270                                    do {
271                                        r = sqlite3_step(dependencies);
272                                        switch (r) {
273                                            case SQLITE_DONE:
274                                                result = 1;
275                                                break;
276                                            case SQLITE_BUSY:
277                                                break;
278                                            case SQLITE_ERROR:
279                                                reg_sqlite_error(reg->db,
280                                                        errPtr, NULL);
281                                                break;
282                                        }
283                                    } while (r == SQLITE_BUSY);
284                                    break;
285                                case SQLITE_BUSY:
286                                    break;
287                                case SQLITE_ERROR:
288                                    reg_sqlite_error(reg->db, errPtr, NULL);
289                                    break;
290                            }
291                        } while (r == SQLITE_BUSY);
292                        break;
293                    } else {
294                        errPtr->code = REG_INVALID;
295                        errPtr->description = "an invalid entry was passed";
296                        errPtr->free = NULL;
297                    }
298                    break;
299                case SQLITE_BUSY:
300                    break;
301                case SQLITE_ERROR:
302                    reg_sqlite_error(reg->db, errPtr, NULL);
303                    break;
304            }
305        } while (r == SQLITE_BUSY);
306    } else {
307        reg_sqlite_error(reg->db, errPtr, NULL);
308    }
309    if (ports) {
310        sqlite3_finalize(ports);
311    }
312    if (files) {
313        sqlite3_finalize(files);
314    }
315    if (dependencies) {
316        sqlite3_finalize(dependencies);
317    }
318    return result;
319}
320
321/**
322 * Frees an entry. Normally this is unnecessary, as open entries will be
323 * automatically freed when the registry is detached. Calling this method
324 * externally should only be necessary following `reg_entry_delete`.
325 *
326 * @param [in] entry the entry to free
327 */
328void reg_entry_free(reg_entry* entry) {
329    Tcl_HashEntry* hash = Tcl_FindHashEntry(&entry->reg->open_entries,
330                            (const char*)&entry->id);
331    Tcl_DeleteHashEntry(hash);
332    if (entry->proc != NULL) {
333        free(entry->proc);
334    }
335    free(entry);
336}
337
338/**
339 * Type-safe version of `reg_all_objects` for `reg_entry`.
340 *
341 * @param [in] reg       registry to select entries from
342 * @param [in] query     the select query to execute
343 * @param [in] query_len length of the query (or -1 for automatic)
344 * @param [out] objects  the entries selected
345 * @param [out] errPtr   on error, a description of the error that occurred
346 * @return               the number of entries if success; negative if failure
347 */
348static int reg_all_entries(reg_registry* reg, char* query, int query_len,
349        reg_entry*** objects, reg_error* errPtr) {
350    int lower_bound = 0;
351    return reg_all_objects(reg, query, query_len, (void***)objects,
352            reg_stmt_to_entry, &lower_bound, NULL, errPtr);
353}
354
355/**
356 * Searches the registry for ports for which each key's value is equal to the
357 * given value. To find all ports, pass a key_count of 0.
358 *
359 * Bad keys should cause sqlite3 errors but not permit SQL injection attacks.
360 * Pass it good keys anyway.
361 *
362 * @param [in] reg       registry to search in
363 * @param [in] keys      a list of keys to search by
364 * @param [in] vals      a list of values to search by, matching keys
365 * @param [in] key_count the number of key/value pairs passed
366 * @param [in] strategy  strategy to use (one of the `reg_strategy_*` constants)
367 * @param [out] entries  a list of matching entries
368 * @param [out] errPtr   on error, a description of the error that occurred
369 * @return               the number of entries if success; false if failure
370 */
371int reg_entry_search(reg_registry* reg, char** keys, char** vals, int key_count,
372        int strategy, reg_entry*** entries, reg_error* errPtr) {
373    int i;
374    char* kwd = " WHERE ";
375    char* query;
376    size_t query_len, query_space;
377    int result;
378    /* get the strategy */
379    char* op = reg_strategy_op(strategy, errPtr);
380    if (op == NULL) {
381        return -1;
382    }
383    /* build the query */
384    query = strdup("SELECT id FROM registry.ports");
385    if (!query) {
386        return -1;
387    }
388    query_len = query_space = strlen(query);
389    for (i=0; i<key_count; i++) {
390        char* cond = sqlite3_mprintf(op, keys[i], vals[i]);
391        if (!cond || !reg_strcat(&query, &query_len, &query_space, kwd)
392            || !reg_strcat(&query, &query_len, &query_space, cond)) {
393            free(query);
394            return -1;
395        }
396        sqlite3_free(cond);
397        kwd = " AND ";
398    }
399    /* do the query */
400    result = reg_all_entries(reg, query, -1, entries, errPtr);
401    free(query);
402    return result;
403}
404
405/**
406 * Finds ports which are installed as an image, and/or those which are active
407 * in the filesystem. When the install mode is 'direct', this will be equivalent
408 * to `reg_entry_installed`.
409 *
410 * Note that the name is a bit of a misnomer, since you can install a port with
411 * installtype direct and it will still be in this list. It's really "imaged or
412 * installed" but that's usually redundant and too long to type.
413 *
414 * @param [in] reg      registry object as created by `registry_open`
415 * @param [in] name     specific port to find (NULL for any)
416 * @param [in] version  specific version to find (NULL for any)
417 * @param [out] entries list of ports meeting the criteria
418 * @param [out] errPtr  description of error encountered, if any
419 * @return              the number of entries if success; false if failure
420 */
421int reg_entry_imaged(reg_registry* reg, const char* name, const char* version,
422        const char* revision, const char* variants, reg_entry*** entries,
423        reg_error* errPtr) {
424    char* query;
425    int result;
426    char* empty = "";
427    char* name_clause = empty;
428    char* version_clause = empty;
429    char* revision_clause = empty;
430    char* variants_clause = empty;
431    if (name != NULL) {
432        name_clause = sqlite3_mprintf(" AND name='%q'", name);
433    }
434    if (version != NULL) {
435        version_clause = sqlite3_mprintf(" AND version='%q'", version);
436    }
437    if (revision != NULL) {
438        revision_clause = sqlite3_mprintf(" AND revision='%q'", revision);
439    }
440    if (variants != NULL) {
441        variants_clause = sqlite3_mprintf(" AND variants='%q'", variants);
442    }
443    query = sqlite3_mprintf("SELECT id FROM ports WHERE (state='imaged' OR "
444            "state='installed')%s%s%s%s", name_clause,
445            version_clause, revision_clause, variants_clause);
446    result = reg_all_entries(reg, query, -1, entries, errPtr);
447    sqlite3_free(query);
448    if (name_clause != empty) sqlite3_free(name_clause);
449    if (version_clause != empty) sqlite3_free(version_clause);
450    if (revision_clause != empty) sqlite3_free(revision_clause);
451    if (variants_clause != empty) sqlite3_free(variants_clause);
452    return result;
453}
454
455/**
456 * Finds ports which are active in the filesystem. These ports are able to meet
457 * dependencies, and properly own the files they map.
458 * @todo add more arguments (epoch, revision, variants), maybe
459 *
460 * @param [in] reg      registry object as created by `registry_open`
461 * @param [in] name     specific port to find (NULL for any)
462 * @param [out] entries list of ports meeting the criteria
463 * @param [out] errPtr  description of error encountered, if any
464 * @return              the number of entries if success; false if failure
465 */
466int reg_entry_installed(reg_registry* reg, char* name, reg_entry*** entries,
467        reg_error* errPtr) {
468    char* format;
469    char* query;
470    int result;
471    char* select = "SELECT id FROM registry.ports";
472    if (name == NULL) {
473        format = "%s WHERE state='installed'";
474    } else {
475        format = "%s WHERE state='installed' AND name='%q'";
476    }
477    query = sqlite3_mprintf(format, select, name);
478    result = reg_all_entries(reg, query, -1, entries, errPtr);
479    sqlite3_free(query);
480    return result;
481}
482
483/**
484 * Finds the owner of a given file. Only ports active in the filesystem will be
485 * returned.
486 *
487 * @param [in] reg     registry to search in
488 * @param [in] path    path of the file to check ownership of
489 * @param [out] entry  the owner, or NULL if no active port owns the file
490 * @param [out] errPtr on error, a description of the error that occurred
491 * @return             true if success; false if failure
492 */
493int reg_entry_owner(reg_registry* reg, char* path, reg_entry** entry,
494        reg_error* errPtr) {
495    int result = 0;
496    sqlite3_stmt* stmt = NULL;
497    char* query = "SELECT id FROM registry.files WHERE actual_path=? AND active";
498    int lower_bound = 0;
499    if ((sqlite3_prepare_v2(reg->db, query, -1, &stmt, NULL) == SQLITE_OK)
500            && (sqlite3_bind_text(stmt, 1, path, -1, SQLITE_STATIC)
501                == SQLITE_OK)) {
502        int r;
503        do {
504            r = sqlite3_step(stmt);
505            switch (r) {
506                case SQLITE_ROW:
507                    result = reg_stmt_to_entry(reg, (void**)entry, stmt,
508                            &lower_bound, errPtr);
509                    break;
510                case SQLITE_DONE:
511                    *entry = NULL;
512                    result = 1;
513                    break;
514                case SQLITE_BUSY:
515                    break;
516                default:
517                    reg_sqlite_error(reg->db, errPtr, query);
518                    break;
519            }
520        } while (r == SQLITE_BUSY);
521    } else {
522        reg_sqlite_error(reg->db, errPtr, query);
523    }
524    if (stmt) {
525        sqlite3_finalize(stmt);
526    }
527    return result;
528}
529
530/**
531 * Shortcut to retrieve a file's owner's id directly. This should be a bit
532 * faster than `reg_entry_owner` because it doesn't have to check the hash table
533 * of open entries. It might still be slower than necessary because it's doing
534 * a join of two tables, but the only way to improve that would be to cache a
535 * file's active state in registry.files itself, which I'd rather not do unless
536 * absolutely necessary.
537 *
538 * @param [in] reg  registry to find file in
539 * @param [in] path path of file to get owner of
540 * @return          id of owner, or 0 for none
541 */
542sqlite_int64 reg_entry_owner_id(reg_registry* reg, char* path) {
543    sqlite3_stmt* stmt = NULL;
544    sqlite_int64 result = 0;
545    char* query = "SELECT id FROM registry.files WHERE actual_path=? AND active";
546    if ((sqlite3_prepare_v2(reg->db, query, -1, &stmt, NULL) == SQLITE_OK)
547            && (sqlite3_bind_text(stmt, 1, path, -1, SQLITE_STATIC)
548                == SQLITE_OK)) {
549        int r;
550        do {
551            r = sqlite3_step(stmt);
552            if (r == SQLITE_ROW) {
553                result = sqlite3_column_int64(stmt, 0);
554            }
555        } while (r == SQLITE_BUSY);
556    }
557    if (stmt) {
558        sqlite3_finalize(stmt);
559    }
560    return result;
561}
562
563/**
564 * Gets a named property of an entry. That property can be set using
565 * `reg_entry_propset`. The property named must be one that exists in the table
566 * and must not be one with internal meaning such as `id` or `state`.
567 *
568 * @param [in] entry   entry to get property from
569 * @param [in] key     property to get
570 * @param [out] value  the value of the property
571 * @param [out] errPtr on error, a description of the error that occurred
572 * @return             true if success; false if failure
573 */
574int reg_entry_propget(reg_entry* entry, char* key, char** value,
575        reg_error* errPtr) {
576    reg_registry* reg = entry->reg;
577    int result = 0;
578    sqlite3_stmt* stmt = NULL;
579    char* query;
580    const char *text;
581    query = sqlite3_mprintf("SELECT %q FROM registry.ports WHERE id=%lld", key,
582            entry->id);
583    if (sqlite3_prepare_v2(reg->db, query, -1, &stmt, NULL) == SQLITE_OK) {
584        int r;
585        do {
586            r = sqlite3_step(stmt);
587            switch (r) {
588                case SQLITE_ROW:
589                    text = (const char*)sqlite3_column_text(stmt, 0);
590                    if (text) {
591                        *value = strdup(text);
592                        result = 1;
593                    } else {
594                        reg_sqlite_error(reg->db, errPtr, query);
595                    }
596                    break;
597                case SQLITE_DONE:
598                    errPtr->code = REG_INVALID;
599                    errPtr->description = "an invalid entry was passed";
600                    errPtr->free = NULL;
601                    break;
602                case SQLITE_BUSY:
603                    continue;
604                default:
605                    reg_sqlite_error(reg->db, errPtr, query);
606                    break;
607            }
608        } while (r == SQLITE_BUSY);
609    } else {
610        reg_sqlite_error(reg->db, errPtr, query);
611    }
612    if (stmt) {
613        sqlite3_finalize(stmt);
614    }
615    sqlite3_free(query);
616    return result;
617}
618
619/**
620 * Sets a named property of an entry. That property can be later retrieved using
621 * `reg_entry_propget`. The property named must be one that exists in the table
622 * and must not be one with internal meaning such as `id` or `state`. If `name`,
623 * `epoch`, `version`, `revision`, or `variants` is set, it could trigger a
624 * conflict if another port with the same combination of values for those
625 * columns exists.
626 *
627 * @param [in] entry   entry to set property for
628 * @param [in] key     property to set
629 * @param [in] value   the desired value of the property
630 * @param [out] errPtr on error, a description of the error that occurred
631 * @return             true if success; false if failure
632 */
633int reg_entry_propset(reg_entry* entry, char* key, char* value,
634        reg_error* errPtr) {
635    reg_registry* reg = entry->reg;
636    int result = 0;
637    sqlite3_stmt* stmt = NULL;
638    char* query;
639    query = sqlite3_mprintf("UPDATE registry.ports SET %q = '%q' WHERE id=%lld",
640            key, value, entry->id);
641    if (sqlite3_prepare_v2(reg->db, query, -1, &stmt, NULL) == SQLITE_OK) {
642        int r;
643        do {
644            r = sqlite3_step(stmt);
645            switch (r) {
646                case SQLITE_DONE:
647                    result = 1;
648                    break;
649                case SQLITE_BUSY:
650                    break;
651                default:
652                    if (sqlite3_reset(stmt) == SQLITE_CONSTRAINT) {
653                        errPtr->code = REG_CONSTRAINT;
654                        errPtr->description = "a constraint was disobeyed";
655                        errPtr->free = NULL;
656                    } else {
657                        reg_sqlite_error(reg->db, errPtr, query);
658                    }
659                    break;
660            }
661        } while (r == SQLITE_BUSY);
662    } else {
663        reg_sqlite_error(reg->db, errPtr, query);
664    }
665    if (stmt) {
666        sqlite3_finalize(stmt);
667    }
668    sqlite3_free(query);
669    return result;
670}
671
672/**
673 * Maps files to the given port in the filemap. The list of files must not
674 * contain files that are already mapped to the given port.
675 *
676 * @param [in] entry      the entry to map the files to
677 * @param [in] files      a list of files to map
678 * @param [in] file_count the number of files
679 * @param [out] errPtr    on error, a description of the error that occurred
680 * @return                true if success; false if failure
681 */
682int reg_entry_map(reg_entry* entry, char** files, int file_count,
683        reg_error* errPtr) {
684    reg_registry* reg = entry->reg;
685    int result = 1;
686    sqlite3_stmt* stmt = NULL;
687    char* insert = "INSERT INTO registry.files (id, path, mtime, active) "
688        "VALUES (?, ?, 0, 0)";
689    if ((sqlite3_prepare_v2(reg->db, insert, -1, &stmt, NULL) == SQLITE_OK)
690            && (sqlite3_bind_int64(stmt, 1, entry->id) == SQLITE_OK)) {
691        int i;
692        for (i=0; i<file_count && result; i++) {
693            if (sqlite3_bind_text(stmt, 2, files[i], -1, SQLITE_STATIC)
694                    == SQLITE_OK) {
695                int r;
696                do {
697                    r = sqlite3_step(stmt);
698                    switch (r) {
699                        case SQLITE_DONE:
700                            sqlite3_reset(stmt);
701                            break;
702                        case SQLITE_BUSY:
703                            break;
704                        default:
705                            reg_sqlite_error(reg->db, errPtr, insert);
706                            result = 0;
707                            break;
708                    }
709                } while (r == SQLITE_BUSY);
710            } else {
711                reg_sqlite_error(reg->db, errPtr, insert);
712                result = 0;
713            }
714        }
715    } else {
716        reg_sqlite_error(reg->db, errPtr, insert);
717        result = 0;
718    }
719    if (stmt) {
720        sqlite3_finalize(stmt);
721    }
722    return result;
723}
724
725/**
726 * Unaps files from the given port in the filemap. The files must be owned by
727 * the given entry.
728 *
729 * @param [in] entry      the entry to unmap the files from
730 * @param [in] files      a list of files to unmap
731 * @param [in] file_count the number of files
732 * @param [out] errPtr    on error, a description of the error that occurred
733 * @return                true if success; false if failure
734 */
735int reg_entry_unmap(reg_entry* entry, char** files, int file_count,
736        reg_error* errPtr) {
737    reg_registry* reg = entry->reg;
738    int result = 1;
739    sqlite3_stmt* stmt = NULL;
740    char* query = "DELETE FROM registry.files WHERE path=? AND id=?";
741    if ((sqlite3_prepare_v2(reg->db, query, -1, &stmt, NULL) == SQLITE_OK)
742            && (sqlite3_bind_int64(stmt, 2, entry->id) == SQLITE_OK)) {
743        int i;
744        for (i=0; i<file_count && result; i++) {
745            if (sqlite3_bind_text(stmt, 1, files[i], -1, SQLITE_STATIC)
746                    == SQLITE_OK) {
747                int r;
748                do {
749                    r = sqlite3_step(stmt);
750                    switch (r) {
751                        case SQLITE_DONE:
752                            if (sqlite3_changes(reg->db) == 0) {
753                                reg_throw(errPtr, REG_INVALID, "this entry "
754                                        "does not own the given file");
755                                result = 0;
756                            } else {
757                                sqlite3_reset(stmt);
758                            }
759                            break;
760                        case SQLITE_BUSY:
761                            break;
762                        default:
763                            reg_sqlite_error(reg->db, errPtr, query);
764                            result = 0;
765                            break;
766                    }
767                } while (r == SQLITE_BUSY);
768            } else {
769                reg_sqlite_error(reg->db, errPtr, query);
770                result = 0;
771            }
772        }
773    } else {
774        reg_sqlite_error(reg->db, errPtr, query);
775        result = 0;
776    }
777    if (stmt) {
778        sqlite3_finalize(stmt);
779    }
780    return result;
781}
782
783/**
784 * Gets a list of files provided by the given port. These files are in the port
785 * image and do not necessarily correspond to active files on the filesystem.
786 *
787 * TODO: check that the port's installtype is image
788 *
789 * @param [in] entry   entry to get the list for
790 * @param [out] files  a list of files provided by the port
791 * @param [out] errPtr on error, a description of the error that occurred
792 * @return             the number of files if success; negative if failure
793 */
794int reg_entry_imagefiles(reg_entry* entry, char*** files, reg_error* errPtr) {
795    reg_registry* reg = entry->reg;
796    sqlite3_stmt* stmt = NULL;
797    char* query = "SELECT path FROM registry.files WHERE id=? ORDER BY path";
798    if ((sqlite3_prepare_v2(reg->db, query, -1, &stmt, NULL) == SQLITE_OK)
799            && (sqlite3_bind_int64(stmt, 1, entry->id) == SQLITE_OK)) {
800        char** result = malloc(10*sizeof(char*));
801        int result_count = 0;
802        int result_space = 10;
803        int r;
804        const char *text;
805        char* element;
806        if (!result) {
807            return -1;
808        }
809        do {
810            r = sqlite3_step(stmt);
811            switch (r) {
812                case SQLITE_ROW:
813                    text = (const char*)sqlite3_column_text(stmt, 0);
814                    if (text) {
815                        element = strdup(text);
816                        if (!element || !reg_listcat((void***)&result, &result_count, &result_space, element)) {
817                            r = SQLITE_ERROR;
818                        }
819                    }
820                    break;
821                case SQLITE_DONE:
822                case SQLITE_BUSY:
823                    break;
824                default:
825                    reg_sqlite_error(reg->db, errPtr, query);
826                    break;
827            }
828        } while (r == SQLITE_ROW || r == SQLITE_BUSY);
829        sqlite3_finalize(stmt);
830        if (r == SQLITE_DONE) {
831            *files = result;
832            return result_count;
833        } else {
834            int i;
835            for (i=0; i<result_count; i++) {
836                free(result[i]);
837            }
838            free(result);
839            return -1;
840        }
841    } else {
842        reg_sqlite_error(reg->db, errPtr, query);
843        if (stmt) {
844            sqlite3_finalize(stmt);
845        }
846        return -1;
847    }
848}
849
850/**
851 * Gets a list of files owned by the given port. These files are active in the
852 * filesystem and could be different from the port's imagefiles.
853 *
854 * TODO: check that the port is active
855 *
856 * @param [in] entry   entry to get the list for
857 * @param [out] files  a list of files owned by the port
858 * @param [out] errPtr on error, a description of the error that occurred
859 * @return             the number of files if success; negative if failure
860 */
861int reg_entry_files(reg_entry* entry, char*** files, reg_error* errPtr) {
862    reg_registry* reg = entry->reg;
863    sqlite3_stmt* stmt = NULL;
864    char* query = "SELECT actual_path FROM registry.files WHERE id=? "
865        "AND active ORDER BY actual_path";
866    if ((sqlite3_prepare_v2(reg->db, query, -1, &stmt, NULL) == SQLITE_OK)
867            && (sqlite3_bind_int64(stmt, 1, entry->id) == SQLITE_OK)) {
868        char** result = malloc(10*sizeof(char*));
869        int result_count = 0;
870        int result_space = 10;
871        int r;
872        const char *text;
873        char* element;
874        if (!result) {
875            return -1;
876        }
877        do {
878            r = sqlite3_step(stmt);
879            switch (r) {
880                case SQLITE_ROW:
881                    text = (const char*)sqlite3_column_text(stmt, 0);
882                    if (text) {
883                        element = strdup(text);
884                        if (!element || !reg_listcat((void***)&result, &result_count, &result_space, element)) {
885                            r = SQLITE_ERROR;
886                        }
887                    }
888                    break;
889                case SQLITE_DONE:
890                case SQLITE_BUSY:
891                    break;
892                default:
893                    reg_sqlite_error(reg->db, errPtr, query);
894                    break;
895            }
896        } while (r == SQLITE_ROW || r == SQLITE_BUSY);
897        sqlite3_finalize(stmt);
898        if (r == SQLITE_DONE) {
899            *files = result;
900            return result_count;
901        } else {
902            int i;
903            for (i=0; i<result_count; i++) {
904                free(result[i]);
905            }
906            free(result);
907            return -1;
908        }
909    } else {
910        reg_sqlite_error(reg->db, errPtr, query);
911        if (stmt) {
912            sqlite3_finalize(stmt);
913        }
914        return -1;
915    }
916}
917
918/**
919 * Sets an entry's files as being active in the filesystem. This entry will be
920 * subsequently returned by `reg_entry_owner` on those files' path. If all files
921 * are being activated as the names they are in the registry, then `as_files`
922 * may be NULL. If they are being activated to different paths than the original
923 * files, then `as_files` should be a list of the same length as `files`.
924 *
925 * @param [in] entry      entry to assign the file to
926 * @param [in] files      a list of files to activate
927 * @param [in] as_files   NULL, or a list of paths the files are activated as
928 * @param [in] file_count number of files to activate
929 * @param [out] errPtr    on error, a description of the error that occurred
930 * @return                true if success; false if failure
931 */
932int reg_entry_activate(reg_entry* entry, char** files, char** as_files,
933        int file_count, reg_error* errPtr) {
934    reg_registry* reg = entry->reg;
935    int result = 1;
936    int i;
937    sqlite3_stmt* select = NULL;
938    sqlite3_stmt* update = NULL;
939    char* select_query = "SELECT id FROM registry.files WHERE actual_path=? "
940        "AND active";
941    char* update_query = "UPDATE registry.files SET actual_path=?, active=1 "
942        "WHERE path=? AND id=?";
943
944    /* if as_files wasn't specified, activate as the original files */
945    if (as_files == NULL) {
946        as_files = files;
947    }
948
949    if (sqlite3_prepare_v2(reg->db, select_query, -1, &select, NULL) == SQLITE_OK){
950        if ((sqlite3_prepare_v2(reg->db, update_query, -1, &update, NULL)
951                == SQLITE_OK)
952                && (sqlite3_bind_int64(update, 3, entry->id) == SQLITE_OK)) {
953            for (i=0; i<file_count && result; i++) {
954                if ((sqlite3_bind_text(select, 1, as_files[i], -1, SQLITE_STATIC)
955                            == SQLITE_OK)
956                        && (sqlite3_bind_text(update, 1, as_files[i], -1,
957                                SQLITE_STATIC) == SQLITE_OK)
958                        && (sqlite3_bind_text(update, 2, files[i], -1,
959                                SQLITE_STATIC) == SQLITE_OK)) {
960                    int r;
961                    do {
962                        r = sqlite3_step(select);
963                        switch (r) {
964                            case SQLITE_ROW:
965                                reg_throw(errPtr, REG_ALREADY_ACTIVE, "%s is "
966                                        "being used by another port", files[i]);
967                                result = 0;
968                                break;
969                            case SQLITE_DONE:
970                                do {
971                                    r = sqlite3_step(update);
972                                    switch (r) {
973                                        case SQLITE_DONE:
974                                            if (sqlite3_changes(reg->db) == 0) {
975                                                reg_throw(errPtr, REG_INVALID,
976                                                        "%s is not provided by "
977                                                        "this port", files[i]);
978                                                result = 0;
979                                            } else {
980                                                sqlite3_reset(select);
981                                                sqlite3_reset(update);
982                                            }
983                                            break;
984                                        case SQLITE_BUSY:
985                                            break;
986                                        case SQLITE_ERROR:
987                                            reg_sqlite_error(reg->db, errPtr,
988                                                    update_query);
989                                            result = 0;
990                                            break;
991                                    }
992                                } while (r == SQLITE_BUSY);
993                                break;
994                            case SQLITE_BUSY:
995                                break;
996                            case SQLITE_ERROR:
997                                reg_sqlite_error(reg->db, errPtr, select_query);
998                                result = 0;
999                                break;
1000                        }
1001                    } while (r == SQLITE_BUSY);
1002                } else {
1003                    reg_sqlite_error(reg->db, errPtr, NULL);
1004                    result = 0;
1005                }
1006            }
1007        } else {
1008            reg_sqlite_error(reg->db, errPtr, update_query);
1009            result = 0;
1010        }
1011        if (update) {
1012            sqlite3_finalize(update);
1013        }
1014    } else {
1015        reg_sqlite_error(reg->db, errPtr, select_query);
1016        result = 0;
1017    }
1018    if (select) {
1019        sqlite3_finalize(select);
1020    }
1021    return result;
1022}
1023
1024/**
1025 * Deactivates files owned by a given entry. That entry's version of all files
1026 * must currently be active.
1027 *
1028 * @param [in] entry      current owner of the files
1029 * @param [in] files      a list of files to deactivate
1030 * @param [in] file_count number of files to deactivate
1031 * @param [out] errPtr    on error, a description of the error that occurred
1032 * @return                true if success; false if failure
1033 */
1034int reg_entry_deactivate(reg_entry* entry, char** files, int file_count,
1035        reg_error* errPtr) {
1036    reg_registry* reg = entry->reg;
1037    int result = 1;
1038    int i;
1039    sqlite3_stmt* stmt = NULL;
1040    char* query = "UPDATE registry.files SET active=0 WHERE actual_path=? AND id=?";
1041    if ((sqlite3_prepare_v2(reg->db, query, -1, &stmt, NULL) == SQLITE_OK)
1042            && (sqlite3_bind_int64(stmt, 2, entry->id) == SQLITE_OK)) {
1043        for (i=0; i<file_count && result; i++) {
1044            if (sqlite3_bind_text(stmt, 1, files[i], -1, SQLITE_STATIC)
1045                    == SQLITE_OK) {
1046                int r;
1047                do {
1048                    r = sqlite3_step(stmt);
1049                    switch (r) {
1050                        case SQLITE_DONE:
1051                            if (sqlite3_changes(reg->db) == 0) {
1052                                reg_throw(errPtr, REG_INVALID, "this entry "
1053                                        "does not own the given file");
1054                                result = 0;
1055                            } else {
1056                                sqlite3_reset(stmt);
1057                            }
1058                            break;
1059                        case SQLITE_BUSY:
1060                            break;
1061                        default:
1062                            reg_sqlite_error(reg->db, errPtr, query);
1063                            result = 0;
1064                            break;
1065                    }
1066                } while (r == SQLITE_BUSY);
1067            } else {
1068                reg_sqlite_error(reg->db, errPtr, query);
1069                result = 0;
1070            }
1071        }
1072    } else {
1073        reg_sqlite_error(reg->db, errPtr, query);
1074        result = 0;
1075    }
1076    if (stmt) {
1077        sqlite3_finalize(stmt);
1078    }
1079    return result;
1080}
1081
1082/**
1083 * Gets a list of ports that depend on this one. Uninstalling the given port
1084 * could potentially break any port listed in its dependents, and could not
1085 * break any other.
1086 *
1087 * @param [in] entry       a port
1088 * @param [out] dependents a list of ports dependent on the given port
1089 * @param [out] errPtr     on error, a description of the error that occurred
1090 * @return                 true if success; false if failure
1091 */
1092int reg_entry_dependents(reg_entry* entry, reg_entry*** dependents,
1093        reg_error* errPtr) {
1094    reg_registry* reg = entry->reg;
1095    char* query = sqlite3_mprintf("SELECT dependencies.id FROM ports port "
1096            "INNER JOIN dependencies USING(name) INNER JOIN ports dependent "
1097            "USING(id) WHERE port.id=%lld ORDER BY dependent.name,"
1098            "dependent.epoch, dependent.version, dependent.revision,"
1099            "dependent.variants",
1100            entry->id);
1101    int result = reg_all_entries(reg, query, -1, dependents, errPtr);
1102    sqlite3_free(query);
1103    return result;
1104}
1105
1106/**
1107 * Gets a list of ports that this one depends on. This only returns ports which
1108 * have state "installed" and should really only be called upon ports which have
1109 * state "installed" themselves. Uninstalling any port in this list could break
1110 * the given port, but uninstalling any other could not break it.
1111 *
1112 * @param [in] entry         a port
1113 * @param [out] dependencies a list of ports the given port depends on
1114 * @param [out] errPtr       on error, a description of the error that occurred
1115 * @return                   number of deps if success; negative if failure
1116 */
1117int reg_entry_dependencies(reg_entry* entry, reg_entry*** dependencies,
1118        reg_error* errPtr) {
1119    reg_registry* reg = entry->reg;
1120    char* query = sqlite3_mprintf("SELECT ports.id FROM registry.dependencies "
1121        "INNER JOIN registry.ports USING(name) WHERE dependencies.id=%lld",
1122        entry->id);
1123    int result = reg_all_entries(reg, query, -1, dependencies, errPtr);
1124    sqlite3_free(query);
1125    return result;
1126}
1127
1128/**
1129 * Sets the given port to depend on the named port. This is a weak link; it
1130 * refers to a name and not an actual port.
1131 *
1132 * @param [in] entry   a port
1133 * @param [in] name    the name of a port the given port depends on
1134 * @param [out] errPtr on error, a description of the error that occurred
1135 * @return             true if success; false if failure
1136 */
1137int reg_entry_depends(reg_entry* entry, char* name, reg_error* errPtr) {
1138    reg_registry* reg = entry->reg;
1139    int result = 0;
1140    sqlite3_stmt* stmt = NULL;
1141    char* query = "INSERT INTO registry.dependencies (id, name) VALUES (?,?)";
1142    if ((sqlite3_prepare_v2(reg->db, query, -1, &stmt, NULL) == SQLITE_OK)
1143            && (sqlite3_bind_int64(stmt, 1, entry->id) == SQLITE_OK)
1144            && (sqlite3_bind_text(stmt, 2, name, -1, SQLITE_STATIC)
1145                == SQLITE_OK)) {
1146        int r;
1147        do {
1148            r = sqlite3_step(stmt);
1149            switch (r) {
1150                case SQLITE_DONE:
1151                    result = 1;
1152                    break;
1153                case SQLITE_BUSY:
1154                    break;
1155                default:
1156                    reg_sqlite_error(reg->db, errPtr, query);
1157                    break;
1158            }
1159        } while (r == SQLITE_BUSY);
1160    } else {
1161        reg_sqlite_error(reg->db, errPtr, query);
1162    }
1163    if (stmt) {
1164        sqlite3_finalize(stmt);
1165    }
1166    return result;
1167}
1168
1169/**
1170 * Fetches a list of all open entries.
1171 *
1172 * @param [in] reg      registry to fetch entries from
1173 * @param [out] entries a list of open entries
1174 * @return              the number of open entries, -1 on error
1175 */
1176int reg_all_open_entries(reg_registry* reg, reg_entry*** entries) {
1177    reg_entry* entry;
1178    int entry_count = 0;
1179    int entry_space = 10;
1180    Tcl_HashEntry* hash;
1181    Tcl_HashSearch search;
1182    *entries = malloc(10*sizeof(void*));
1183    if (!*entries) {
1184        return -1;
1185    }
1186    for (hash = Tcl_FirstHashEntry(&reg->open_entries, &search); hash != NULL;
1187            hash = Tcl_NextHashEntry(&search)) {
1188        entry = Tcl_GetHashValue(hash);
1189        if (!reg_listcat((void***)entries, &entry_count, &entry_space, entry)) {
1190            free(*entries);
1191            return -1;
1192        }
1193    }
1194    return entry_count;
1195}
1196
Note: See TracBrowser for help on using the repository browser.