LCOV - code coverage report
Current view: top level - libpkg - pkg_repo_meta.c (source / functions) Hit Total Coverage
Test: cov.info Lines: 124 163 76.1 %
Date: 2015-08-15 Functions: 9 10 90.0 %

          Line data    Source code
       1             : /*-
       2             :  * Copyright (c) 2014 Vsevolod Stakhov <vsevolod@FreeBSD.org>
       3             :  * All rights reserved.
       4             :  *
       5             :  * Redistribution and use in source and binary forms, with or without
       6             :  * modification, are permitted provided that the following conditions
       7             :  * are met:
       8             :  * 1. Redistributions of source code must retain the above copyright
       9             :  *    notice, this list of conditions and the following disclaimer
      10             :  *    in this position and unchanged.
      11             :  * 2. Redistributions in binary form must reproduce the above copyright
      12             :  *    notice, this list of conditions and the following disclaimer in the
      13             :  *    documentation and/or other materials provided with the distribution.
      14             :  *
      15             :  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
      16             :  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
      17             :  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
      18             :  * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
      19             :  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
      20             :  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
      21             :  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      22             :  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
      23             :  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
      24             :  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      25             :  */
      26             : 
      27             : #include <ucl.h>
      28             : 
      29             : #include "pkg.h"
      30             : #include "private/event.h"
      31             : #include "private/pkg.h"
      32             : 
      33             : static ucl_object_t *repo_meta_schema_v1 = NULL;
      34             : 
      35             : static void
      36         276 : pkg_repo_meta_set_default(struct pkg_repo_meta *meta)
      37             : {
      38         276 :         meta->digest_format = PKG_HASH_TYPE_SHA256_BASE32;
      39         276 :         meta->packing_format = TXZ;
      40             : 
      41             :         /* Not use conflicts for now */
      42         276 :         meta->conflicts = NULL;
      43         276 :         meta->conflicts_archive = NULL;
      44         276 :         meta->manifests = strdup("packagesite.yaml");
      45         276 :         meta->manifests_archive = strdup("packagesite");
      46         276 :         meta->digests = strdup("digests");
      47         276 :         meta->digests_archive = strdup("digests");
      48         276 :         meta->filesite = strdup("filesite.yaml");
      49         276 :         meta->filesite_archive = strdup("filesite");
      50             :         /* Not using fulldb */
      51         276 :         meta->fulldb = NULL;
      52         276 :         meta->fulldb_archive = NULL;
      53         276 :         meta->version = 1;
      54         276 : }
      55             : 
      56             : void
      57          29 : pkg_repo_meta_free(struct pkg_repo_meta *meta)
      58             : {
      59             :         struct pkg_repo_meta_key *k, *ktmp;
      60             : 
      61             :         /*
      62             :          * It is safe to free NULL pointer by standard
      63             :          */
      64          29 :         if (meta != NULL) {
      65          29 :                 free(meta->conflicts);
      66          29 :                 free(meta->manifests);
      67          29 :                 free(meta->digests);
      68          29 :                 free(meta->fulldb);
      69          29 :                 free(meta->filesite);
      70          29 :                 free(meta->conflicts_archive);
      71          29 :                 free(meta->manifests_archive);
      72          29 :                 free(meta->digests_archive);
      73          29 :                 free(meta->fulldb_archive);
      74          29 :                 free(meta->filesite_archive);
      75          29 :                 free(meta->maintainer);
      76          29 :                 free(meta->source);
      77          29 :                 free(meta->source_identifier);
      78          29 :                 HASH_ITER(hh, meta->keys, k, ktmp) {
      79           0 :                         HASH_DELETE(hh, meta->keys, k);
      80           0 :                         free(k->name);
      81           0 :                         free(k->pubkey);
      82           0 :                         free(k->pubkey_type);
      83           0 :                         free(k);
      84             :                 }
      85          29 :                 free(meta);
      86             :         }
      87          29 : }
      88             : 
      89             : static ucl_object_t*
      90          34 : pkg_repo_meta_open_schema_v1()
      91             : {
      92             :         struct ucl_parser *parser;
      93             :         static const char meta_schema_str_v1[] = ""
      94             :                         "{"
      95             :                         "type = object;"
      96             :                         "properties {"
      97             :                         "version = {type = integer};\n"
      98             :                         "maintainer = {type = string};\n"
      99             :                         "source = {type = string};\n"
     100             :                         "packing_format = {enum = [txz, tbz, tgz, tar]};\n"
     101             :                         "digest_format = {enum = [sha256_base32, sha256_hex, blake2_base32]};\n"
     102             :                         "digests = {type = string};\n"
     103             :                         "manifests = {type = string};\n"
     104             :                         "conflicts = {type = string};\n"
     105             :                         "fulldb = {type = string};\n"
     106             :                         "filesite = {type = string};\n"
     107             :                         "digests_archive = {type = string};\n"
     108             :                         "manifests_archive = {type = string};\n"
     109             :                         "conflicts_archive = {type = string};\n"
     110             :                         "fulldb_archive = {type = string};\n"
     111             :                         "filesite_archive = {type = string};\n"
     112             :                         "source_identifier = {type = string};\n"
     113             :                         "revision = {type = integer};\n"
     114             :                         "eol = {type = integer};\n"
     115             :                         "cert = {"
     116             :                         "  type = object;\n"
     117             :                         "  properties {"
     118             :                         "    type = {enum = [rsa]};\n"
     119             :                         "    data = {type = string};\n"
     120             :                         "    name = {type = string};\n"
     121             :                         "  }"
     122             :                         "  required = [type, data, name];\n"
     123             :                         "};\n"
     124             : 
     125             :                         "}\n"
     126             :                         "required = [version]\n"
     127             :                         "}";
     128             : 
     129          34 :         if (repo_meta_schema_v1 != NULL)
     130          15 :                 return (repo_meta_schema_v1);
     131             : 
     132          19 :         parser = ucl_parser_new(0);
     133          19 :         if (!ucl_parser_add_chunk(parser, meta_schema_str_v1,
     134             :                         sizeof(meta_schema_str_v1) - 1)) {
     135           0 :                 pkg_emit_error("cannot parse schema for repo meta: %s",
     136             :                                 ucl_parser_get_error(parser));
     137           0 :                 ucl_parser_free(parser);
     138           0 :                 return (NULL);
     139             :         }
     140             : 
     141          19 :         repo_meta_schema_v1 = ucl_parser_get_object(parser);
     142          19 :         ucl_parser_free(parser);
     143             : 
     144          19 :         return (repo_meta_schema_v1);
     145             : }
     146             : 
     147             : static struct pkg_repo_meta_key*
     148           0 : pkg_repo_meta_parse_cert(const ucl_object_t *obj)
     149             : {
     150             :         struct pkg_repo_meta_key *key;
     151             : 
     152           0 :         key = calloc(1, sizeof(*key));
     153           0 :         if (key == NULL) {
     154           0 :                 pkg_emit_errno("pkg_repo_meta_parse", "malloc failed for pkg_repo_meta_key");
     155           0 :                 return (NULL);
     156             :         }
     157             : 
     158             :         /*
     159             :          * It is already validated so just use it as is
     160             :          */
     161           0 :         key->name = strdup(ucl_object_tostring(ucl_object_find_key(obj, "name")));
     162           0 :         key->pubkey = strdup(ucl_object_tostring(ucl_object_find_key(obj, "data")));
     163           0 :         key->pubkey_type = strdup(ucl_object_tostring(ucl_object_find_key(obj, "type")));
     164             : 
     165           0 :         return (key);
     166             : }
     167             : 
     168             : #define META_EXTRACT_STRING(field) do {                                                 \
     169             :         obj = ucl_object_find_key(top, (#field));                                       \
     170             :         if (obj != NULL && obj->type == UCL_STRING) {                                \
     171             :             free(meta->field);                                                                       \
     172             :             meta->field = strdup(ucl_object_tostring(obj));                  \
     173             :         }                                                                                                                       \
     174             : } while (0)
     175             : 
     176             : static int
     177          34 : pkg_repo_meta_parse(ucl_object_t *top, struct pkg_repo_meta **target, int version)
     178             : {
     179             :         const ucl_object_t *obj, *cur;
     180          34 :         ucl_object_iter_t iter = NULL;
     181             :         struct pkg_repo_meta *meta;
     182             :         struct pkg_repo_meta_key *cert;
     183             : 
     184          34 :         meta = calloc(1, sizeof(*meta));
     185          34 :         if (meta == NULL) {
     186           0 :                 pkg_emit_errno("pkg_repo_meta_parse", "malloc failed for pkg_repo_meta");
     187           0 :                 return (EPKG_FATAL);
     188             :         }
     189             : 
     190          34 :         pkg_repo_meta_set_default(meta);
     191          34 :         meta->version = version;
     192             : 
     193          34 :         META_EXTRACT_STRING(maintainer);
     194          34 :         META_EXTRACT_STRING(source);
     195             : 
     196          34 :         META_EXTRACT_STRING(conflicts);
     197          34 :         META_EXTRACT_STRING(digests);
     198          34 :         META_EXTRACT_STRING(manifests);
     199          34 :         META_EXTRACT_STRING(fulldb);
     200          34 :         META_EXTRACT_STRING(filesite);
     201          34 :         META_EXTRACT_STRING(conflicts_archive);
     202          34 :         META_EXTRACT_STRING(digests_archive);
     203          34 :         META_EXTRACT_STRING(manifests_archive);
     204          34 :         META_EXTRACT_STRING(fulldb_archive);
     205          34 :         META_EXTRACT_STRING(filesite_archive);
     206             : 
     207          34 :         META_EXTRACT_STRING(source_identifier);
     208             : 
     209          34 :         obj = ucl_object_find_key(top, "eol");
     210          34 :         if (obj != NULL && obj->type == UCL_INT) {
     211           0 :                 meta->eol = ucl_object_toint(obj);
     212             :         }
     213             : 
     214          34 :         obj = ucl_object_find_key(top, "revision");
     215          34 :         if (obj != NULL && obj->type == UCL_INT) {
     216           0 :                 meta->revision = ucl_object_toint(obj);
     217             :         }
     218             : 
     219          34 :         obj = ucl_object_find_key(top, "packing_format");
     220          34 :         if (obj != NULL && obj->type == UCL_STRING) {
     221          34 :                 meta->packing_format = packing_format_from_string(ucl_object_tostring(obj));
     222             :         }
     223             : 
     224          34 :         obj = ucl_object_find_key(top, "digest_format");
     225          34 :         if (obj != NULL && obj->type == UCL_STRING) {
     226          34 :                 meta->digest_format = pkg_checksum_type_from_string(ucl_object_tostring(obj));
     227             :         }
     228             : 
     229          34 :         obj = ucl_object_find_key(top, "cert");
     230          68 :         while ((cur = ucl_iterate_object(obj, &iter, false)) != NULL) {
     231           0 :                 cert = pkg_repo_meta_parse_cert(cur);
     232           0 :                 if (cert != NULL)
     233           0 :                         HASH_ADD_STR(meta->keys, name, cert);
     234             :         }
     235             : 
     236          34 :         *target = meta;
     237             : 
     238          34 :         return (EPKG_OK);
     239             : }
     240             : 
     241             : #undef META_EXTRACT_STRING
     242             : 
     243             : static int
     244          34 : pkg_repo_meta_version(ucl_object_t *top)
     245             : {
     246             :         const ucl_object_t *obj;
     247             : 
     248          34 :         if ((obj = ucl_object_find_key(top, "version")) != NULL) {
     249          34 :                 if (obj->type == UCL_INT) {
     250          34 :                         return (ucl_object_toint(obj));
     251             :                 }
     252             :         }
     253             : 
     254           0 :         return (-1);
     255             : }
     256             : 
     257             : int
     258          34 : pkg_repo_meta_load(const char *file, struct pkg_repo_meta **target)
     259             : {
     260             :         struct ucl_parser *parser;
     261             :         ucl_object_t *top, *schema;
     262             :         struct ucl_schema_error err;
     263             :         int version;
     264             : 
     265          34 :         parser = ucl_parser_new(UCL_PARSER_KEY_LOWERCASE);
     266             : 
     267          34 :         if (!ucl_parser_add_file(parser, file)) {
     268           0 :                 pkg_emit_error("cannot parse repository meta from %s: %s", file,
     269             :                                 ucl_parser_get_error(parser));
     270           0 :                 ucl_parser_free(parser);
     271           0 :                 return (EPKG_FATAL);
     272             :         }
     273             : 
     274          34 :         top = ucl_parser_get_object(parser);
     275          34 :         ucl_parser_free(parser);
     276             : 
     277          34 :         version = pkg_repo_meta_version(top);
     278          34 :         if (version == -1) {
     279           0 :                 pkg_emit_error("repository meta %s has wrong version or wrong format", file);
     280           0 :                 ucl_object_unref(top);
     281           0 :                 return (EPKG_FATAL);
     282             :         }
     283             : 
     284             :         /* Now we support only v1 meta */
     285          34 :         if (version == 1) {
     286          34 :                 schema = pkg_repo_meta_open_schema_v1();
     287             : 
     288          34 :                 if (schema != NULL) {
     289          34 :                         if (!ucl_object_validate(schema, top, &err)) {
     290           0 :                                 pkg_emit_error("repository meta %s cannot be validated: %s", file, err.msg);
     291           0 :                                 ucl_object_unref(top);
     292           0 :                                 return (EPKG_FATAL);
     293             :                         }
     294             :                 }
     295             :         }
     296             :         else {
     297           0 :                 pkg_emit_error("repository meta %s has wrong version %d", file, version);
     298           0 :                 ucl_object_unref(top);
     299           0 :                 return (EPKG_FATAL);
     300             :         }
     301             : 
     302          34 :         return (pkg_repo_meta_parse(top, target, version));
     303             : }
     304             : 
     305             : struct pkg_repo_meta *
     306         242 : pkg_repo_meta_default(void)
     307             : {
     308             :         struct pkg_repo_meta *meta;
     309             : 
     310         242 :         meta = calloc(1, sizeof(*meta));
     311         242 :         if (meta == NULL) {
     312           0 :                 pkg_emit_errno("pkg_repo_meta_default", "malloc failed for pkg_repo_meta");
     313           0 :                 return (NULL);
     314             :         }
     315             : 
     316         242 :         pkg_repo_meta_set_default(meta);
     317             : 
     318         242 :         return (meta);
     319             : }
     320             : 
     321             : #define META_EXPORT_FIELD(result, meta, field, type)    do {                                    \
     322             :         if (meta->field != 0)                                        \
     323             :                 ucl_object_insert_key((result), ucl_object_from ## type (meta->field),       \
     324             :                                 #field, 0, false);                                                                                              \
     325             :         } while(0)
     326             : 
     327             : #define META_EXPORT_FIELD_FUNC(result, meta, field, type, func) do {                    \
     328             :         if (func(meta->field) != 0)                          \
     329             :                 ucl_object_insert_key((result), ucl_object_from ## type (func(meta->field)), \
     330             :                                 #field, 0, false);                                                                                              \
     331             :         } while(0)
     332             : 
     333             : 
     334             : ucl_object_t *
     335          11 : pkg_repo_meta_to_ucl(struct pkg_repo_meta *meta)
     336             : {
     337          11 :         ucl_object_t *result = ucl_object_typed_new(UCL_OBJECT);
     338             : 
     339          11 :         META_EXPORT_FIELD(result, meta, version, int);
     340          11 :         META_EXPORT_FIELD(result, meta, maintainer, string);
     341          11 :         META_EXPORT_FIELD(result, meta, source, string);
     342             : 
     343          11 :         META_EXPORT_FIELD_FUNC(result, meta, packing_format, string,
     344             :                 packing_format_to_string);
     345          11 :         META_EXPORT_FIELD_FUNC(result, meta, digest_format, string,
     346             :                 pkg_checksum_type_to_string);
     347             : 
     348          11 :         META_EXPORT_FIELD(result, meta, digests, string);
     349          11 :         META_EXPORT_FIELD(result, meta, manifests, string);
     350          11 :         META_EXPORT_FIELD(result, meta, conflicts, string);
     351          11 :         META_EXPORT_FIELD(result, meta, fulldb, string);
     352          11 :         META_EXPORT_FIELD(result, meta, filesite, string);
     353          11 :         META_EXPORT_FIELD(result, meta, digests_archive, string);
     354          11 :         META_EXPORT_FIELD(result, meta, manifests_archive, string);
     355          11 :         META_EXPORT_FIELD(result, meta, conflicts_archive, string);
     356          11 :         META_EXPORT_FIELD(result, meta, fulldb_archive, string);
     357          11 :         META_EXPORT_FIELD(result, meta, filesite_archive, string);
     358             : 
     359          11 :         META_EXPORT_FIELD(result, meta, source_identifier, string);
     360          11 :         META_EXPORT_FIELD(result, meta, revision, int);
     361          11 :         META_EXPORT_FIELD(result, meta, eol, int);
     362             : 
     363             :         /* TODO: export keys */
     364             : 
     365          11 :         return (result);
     366             : }
     367             : 
     368             : #undef META_EXPORT_FIELD
     369             : #undef META_EXPORT_FIELD_FUNC
     370             : 
     371             : #define META_SPECIAL_FILE(file, meta, field) \
     372             :         special || (meta->field == NULL ? false : (strcmp(file, meta->field) == 0))
     373             : 
     374             : bool
     375         103 : pkg_repo_meta_is_special_file(const char *file, struct pkg_repo_meta *meta)
     376             : {
     377         103 :         bool special = false;
     378             : 
     379         103 :         special = META_SPECIAL_FILE(file, meta, digests_archive);
     380         103 :         special = META_SPECIAL_FILE(file, meta, manifests_archive);
     381         103 :         special = META_SPECIAL_FILE(file, meta, filesite_archive);
     382         103 :         special = META_SPECIAL_FILE(file, meta, conflicts_archive);
     383         103 :         special = META_SPECIAL_FILE(file, meta, fulldb_archive);
     384             : 
     385         103 :         return (special);
     386             : }

Generated by: LCOV version 1.10