libmpm

morphux C package management library
Log | Files | Refs | Submodules | README | LICENSE | git clone https://git.ne02ptzero.me/git/libmpm

packer.c (33133B)


      1 /*********************************** LICENSE **********************************\
      2 *                            Copyright 2017 Morphux                            *
      3 *                                                                              *
      4 *        Licensed under the Apache License, Version 2.0 (the "License");       *
      5 *        you may not use this file except in compliance with the License.      *
      6 *                  You may obtain a copy of the License at                     *
      7 *                                                                              *
      8 *                 http://www.apache.org/licenses/LICENSE-2.0                   *
      9 *                                                                              *
     10 *      Unless required by applicable law or agreed to in writing, software     *
     11 *       distributed under the License is distributed on an "AS IS" BASIS,      *
     12 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  *
     13 *        See the License for the specific language governing permissions and   *
     14 *                       limitations under the License.                         *
     15 \******************************************************************************/
     16 
     17 #include <packer.h>
     18 
     19 
     20 MPX_STATIC packer_t *packer_init(const char *str) {
     21     packer_t    *ret;
     22 
     23     ret = malloc(sizeof(*ret));
     24     if (ret == NULL)
     25     {
     26         SET_ERR(ERR_MEMORY);
     27         return NULL;
     28     }
     29 
     30     ret->json = NULL;
     31     ret->header = NULL;
     32     ret->out_dir = NULL;
     33 
     34     ret->str = strdup(str);
     35     if (ret->str == NULL)
     36     {
     37         SET_ERR(ERR_MEMORY);
     38         goto cleanup;
     39     }
     40 
     41     return ret;
     42 
     43 cleanup:
     44     free(ret);
     45     return NULL;
     46 }
     47 
     48 MPX_STATIC packer_header_t *packer_header_init(void) {
     49     packer_header_t     *ret;
     50 
     51     ret = malloc(sizeof(*ret));
     52     if (ret == NULL)
     53     {
     54         SET_ERR(ERR_MEMORY);
     55         return NULL;
     56     }
     57 
     58     packer_header_package_init(ret);
     59     packer_header_comp_init(ret);
     60     packer_header_deps_init(ret);
     61 
     62     return ret;
     63 }
     64 
     65 MPX_STATIC void packer_header_free(packer_header_t *ptr) {
     66     if (ptr != NULL)
     67     {
     68         packer_header_package_free(ptr);
     69         packer_header_comp_free(ptr);
     70         packer_header_deps_free(ptr);
     71         free(ptr);
     72     }
     73 }
     74 
     75 packer_t *packer_init_dir(const char *dir) {
     76     packer_t    *ret;
     77 
     78     ret = packer_init(dir);
     79     if (ret == NULL)
     80     {
     81         SET_ERR(ERR_MEMORY);
     82         return NULL;
     83     }
     84 
     85     ret->type = PACKER_TYPE_DIRECTORY;
     86     return ret;
     87 }
     88 
     89 packer_t *packer_init_archive(const char *path) {
     90     packer_t    *ret;
     91 
     92     ret = packer_init(path);
     93     if (ret == NULL)
     94     {
     95         SET_ERR(ERR_MEMORY);
     96         return NULL;
     97     }
     98 
     99     ret->type = PACKER_TYPE_ARCHIVE;
    100     return ret;
    101 }
    102 
    103 void packer_free(packer_t *ptr) {
    104     if (ptr != NULL)
    105     {
    106         json_object_put(ptr->json);
    107         free(ptr->str);
    108         packer_header_free(ptr->header);
    109         free(ptr->out_dir);
    110         free(ptr);
    111     }
    112 }
    113 
    114 MPX_STATIC bool packer_read_config_comp(packer_t *ctx, struct json_object *obj) {
    115     struct json_object_iterator     it, it_end;
    116     struct json_object              *tmp;
    117     const char                      *name;
    118 
    119     assert(ctx != NULL);
    120 
    121     /* Can't raise an assertion since NULL is a valid type in JSON */
    122     if (obj == NULL || json_object_get_type(obj) != json_type_object)
    123     {
    124         SET_ERR(ERR_BAD_JSON_TYPE);
    125         SET_ERR_STR("Bad global JSON type for compilation section.");
    126         return false;
    127     }
    128 
    129     /* Get the first and last element */
    130     it = json_object_iter_begin(obj);
    131     it_end = json_object_iter_end(obj);
    132 
    133     /* Iterating for each member */
    134     while (!json_object_iter_equal(&it, &it_end))
    135     {
    136         name = json_object_iter_peek_name(&it);
    137         tmp = json_object_iter_peek_value(&it);
    138 
    139         /* Skip NULL (JSON null) values */
    140         JSON_SKIP_NULL(tmp, it);
    141 
    142         if (strcmp(name, PACKER_CONF_COMP_CONF_TOKEN) == 0)
    143         {
    144 
    145             /* Element type is unexpected */
    146             if (json_object_get_type(tmp) != json_type_array)
    147             {
    148                 SET_ERR(ERR_BAD_JSON_TYPE);
    149                 SET_ERR_STR_FMT("Bad JSON type for %s, expected an array", name);
    150                 goto cleanup;
    151             }
    152 
    153             /* Iteraite over each element of the array */
    154             for (size_t i = 0; i < json_object_array_length(tmp); i++)
    155             {
    156                 struct json_object      *array_ent, *array_tmp;
    157                 vector_string_t         *opt = NULL;
    158 
    159                 /* Get ID of the current member */
    160                 array_ent = json_object_array_get_idx(tmp, i);
    161 
    162                 /**
    163                  * If it's an array, we need to read each member
    164                  */
    165                 if (json_object_get_type(array_ent) == json_type_object)
    166                 {
    167                     struct json_object_iterator     it_arr, it_arr_end;
    168 
    169                     /* Get the first and last member */
    170                     it_arr = json_object_iter_begin(array_ent);
    171                     it_arr_end = json_object_iter_end(array_ent);
    172                     while (!json_object_iter_equal(&it_arr, &it_arr_end))
    173                     {
    174                         /* Get the value */
    175                         array_tmp = json_object_iter_peek_value(&it_arr);
    176 
    177                         /* Member type is unexpected */
    178                         if (json_object_get_type(array_tmp) != json_type_string)
    179                         {
    180                             SET_ERR(ERR_BAD_JSON_TYPE);
    181                             SET_ERR_STR("Bad JSON type for configure array, expected a string");
    182                             goto cleanup;
    183                         }
    184 
    185                         /* Get the value */
    186                         opt = vector_string_init(json_object_iter_peek_name(&it_arr),
    187                             json_object_get_string(array_tmp));
    188 
    189                         /* Add to the context */
    190                         list_add(ctx->header->compilation.configure, opt, sizeof(*opt));
    191                         free(opt);
    192 
    193                         /* Get the next member */
    194                         json_object_iter_next(&it_arr);
    195                     }
    196                 }
    197                 else if (json_object_get_type(array_ent) == json_type_string)
    198                 {
    199                     /* Get the value */
    200                     opt = vector_string_init(NULL, json_object_get_string(array_ent));
    201 
    202                     /* Add to the context */
    203                     list_add(ctx->header->compilation.configure, opt, sizeof(*opt));
    204                     free(opt);
    205                 }
    206                 else
    207                 {
    208                     SET_ERR(ERR_BAD_JSON);
    209                     SET_ERR_STR("Unknown JSON type in configure section");
    210                     goto cleanup;
    211                 }
    212             }
    213         }
    214         else if (strcmp(name, PACKER_CONF_COMP_MAKE_TOKEN) == 0)
    215         {
    216             /* Member type is unexpected */
    217             if (json_object_get_type(tmp) != json_type_string)
    218             {
    219                 SET_ERR(ERR_BAD_JSON_TYPE);
    220                 SET_ERR_STR_FMT("Bad JSON type for %s, expected a string", name);
    221                 goto cleanup;
    222             }
    223 
    224             /* If the string is empty, set the default Make command */
    225             if (json_object_get_string_len(tmp) == 0)
    226                 ctx->header->compilation.make = strdup(PACKER_MAKE_DEF);
    227             else
    228                 ctx->header->compilation.make = strdup(json_object_get_string(tmp));
    229         }
    230         else if (strcmp(name, PACKER_CONF_COMP_TEST_TOKEN) == 0)
    231         {
    232             /* Member type is unexpected */
    233             if (json_object_get_type(tmp) != json_type_string)
    234             {
    235                 SET_ERR(ERR_BAD_JSON_TYPE);
    236                 SET_ERR_STR_FMT("Bad JSON type for %s, expected a string", name);
    237                 goto cleanup;
    238             }
    239 
    240             /* If the string is empty, set the default test command */
    241             if (json_object_get_string_len(tmp) == 0)
    242                 ctx->header->compilation.test = strdup(PACKER_TEST_DEF);
    243             else
    244                 ctx->header->compilation.test = strdup(json_object_get_string(tmp));
    245         }
    246         else if (strcmp(name, PACKER_CONF_COMP_INST_TOKEN) == 0)
    247         {
    248             /* Member type is unexpected */
    249             if (json_object_get_type(tmp) != json_type_string)
    250             {
    251                 SET_ERR(ERR_BAD_JSON_TYPE);
    252                 SET_ERR_STR_FMT("Bad JSON type for %s, expected a string", name);
    253                 goto cleanup;
    254             }
    255 
    256             /* If the string is empty, set the default install command */
    257             if (json_object_get_string_len(tmp) == 0)
    258                 ctx->header->compilation.install = strdup(PACKER_INST_DEF);
    259             else
    260                 ctx->header->compilation.install = strdup(json_object_get_string(tmp));
    261         }
    262         else if (strcmp(name, PACKER_CONF_COMP_ENV_TOKEN) == 0)
    263         {
    264             /* Member type is unexpected */
    265             if (json_object_get_type(tmp) != json_type_array)
    266             {
    267                 SET_ERR(ERR_BAD_JSON_TYPE);
    268                 SET_ERR_STR_FMT("Bad JSON type for %s, expected an array", name);
    269                 goto cleanup;
    270             }
    271 
    272             /* Iterate over each member of the array */
    273             for (size_t i = 0; i < json_object_array_length(tmp); i++)
    274             {
    275                 struct json_object      *array_ent, *array_tmp;
    276                 vector_string_t         *opt = NULL;
    277 
    278                 /* Get the current member ID */
    279                 array_ent = json_object_array_get_idx(tmp, i);
    280                 if (json_object_get_type(array_ent) == json_type_object)
    281                 {
    282                     struct json_object_iterator     it_arr, it_arr_end;
    283 
    284                     /* Get the first and last member */
    285                     it_arr = json_object_iter_begin(array_ent);
    286                     it_arr_end = json_object_iter_end(array_ent);
    287 
    288                     /* Iterate over each member */
    289                     while (!json_object_iter_equal(&it_arr, &it_arr_end))
    290                     {
    291                         /* Get the value */
    292                         array_tmp = json_object_iter_peek_value(&it_arr);
    293 
    294                         /* Member type is unexpected */
    295                         if (json_object_get_type(array_tmp) != json_type_string)
    296                         {
    297                             SET_ERR(ERR_BAD_JSON_TYPE);
    298                             SET_ERR_STR("Bad JSON type in the env array, expected string");
    299                             goto cleanup;
    300                         }
    301 
    302                         /* Get the value */
    303                         opt = vector_string_init(json_object_iter_peek_name(&it_arr),
    304                             json_object_get_string(array_tmp));
    305 
    306                         /* Add it to the context */
    307                         list_add(ctx->header->compilation.env, opt, sizeof(*opt));
    308                         free(opt);
    309 
    310                         /* Iterate over next member */
    311                         json_object_iter_next(&it_arr);
    312                     }
    313                 }
    314                 else if (json_object_get_type(array_ent) == json_type_string)
    315                 {
    316                     /* Get the value */
    317                     opt = vector_string_init(NULL, json_object_get_string(array_ent));
    318 
    319                     /* Add it to the context */
    320                     list_add(ctx->header->compilation.env, opt, sizeof(*opt));
    321                     free(opt);
    322                 }
    323                 else
    324                 {
    325                     SET_ERR(ERR_BAD_JSON);
    326                     SET_ERR_STR("Bad JSON type in the env array, expected a string / array");
    327                     goto cleanup;
    328                 }
    329             }
    330         }
    331         /* Wrong token */
    332         else
    333         {
    334             SET_ERR(ERR_BAD_JSON);
    335             SET_ERR_STR_FMT("Unknown JSON token: %s", name);
    336             goto cleanup;
    337         }
    338 
    339         /* Get next member */
    340         json_object_iter_next(&it);
    341 
    342     }
    343     return true;
    344 
    345 cleanup:
    346     packer_header_comp_free(ctx->header);
    347     return false;
    348 }
    349 
    350 MPX_STATIC bool packer_read_config_deps(packer_t *ctx, struct json_object *obj) {
    351     struct json_object  *tmp;
    352     size_t              len = 0, i = 0;
    353 
    354     assert(ctx != NULL);
    355 
    356     /* Can't raise an assertion since NULL is a valid type in JSON */
    357     if (obj == NULL || json_object_get_type(obj) != json_type_array)
    358     {
    359         SET_ERR(ERR_BAD_JSON_TYPE);
    360         SET_ERR_STR("Bad JSON type for the dependencies, expected an array");
    361         return false;
    362     }
    363 
    364     /* Iterate over each member of the array */
    365     for (len = json_object_array_length(obj), i = 0; i < len; i++)
    366     {
    367         /* Get the current ID of the member */
    368         tmp = json_object_array_get_idx(obj, i);
    369 
    370         /* Member got an unexpected type */
    371         if (json_object_get_type(tmp) != json_type_string)
    372         {
    373             SET_ERR(ERR_BAD_JSON_TYPE);
    374             SET_ERR_STR("Bad JSON type for the dependencies array, expected a string");
    375             goto cleanup;
    376         }
    377 
    378         /* Add it to the context */
    379         list_add(ctx->header->dependencies.list, (char *)json_object_get_string(tmp),
    380             json_object_get_string_len(tmp) + 1);
    381     }
    382 
    383     return true;
    384 cleanup:
    385     packer_header_deps_free(ctx->header);
    386     return false;
    387 }
    388 
    389 MPX_STATIC bool packer_read_config_package(packer_t *ctx, struct json_object *obj) {
    390     struct json_object_iterator     it, it_end;
    391     struct json_object              *tmp;
    392     const char                      *name;
    393 
    394     assert(ctx != NULL);
    395 
    396     /* Can't raise an assertion since NULL is a valid type in JSON */
    397     if (obj == NULL || json_object_get_type(obj) != json_type_object)
    398     {
    399         SET_ERR(ERR_BAD_JSON_TYPE);
    400         SET_ERR_STR("Bad JSON type for the package section, expected an object");
    401         return false;
    402     }
    403 
    404     /* Get the first and last member */
    405     it = json_object_iter_begin(obj);
    406     it_end = json_object_iter_end(obj);
    407 
    408     /* Iterating over each member */
    409     while (!json_object_iter_equal(&it, &it_end))
    410     {
    411         /* Get name and value */
    412         name = json_object_iter_peek_name(&it);
    413         tmp = json_object_iter_peek_value(&it);
    414 
    415         if (strcmp(name, PACKER_CONF_PACKAGE_NAME_TOKEN) == 0)
    416         {
    417             /* Member type is unexpected */
    418             if (json_object_get_type(tmp) != json_type_string)
    419             {
    420                 SET_ERR(ERR_BAD_JSON_TYPE);
    421                 SET_ERR_STR_FMT("Wrong type for %s, expected a string", name);
    422                 goto cleanup;
    423             }
    424 
    425             /* Add it to the context */
    426             ctx->__pkg_name = strdup(json_object_get_string(tmp));
    427         }
    428         else if (strcmp(name, PACKER_CONF_PACKAGE_VERSION_TOKEN) == 0)
    429         {
    430             /* Member type is unexpected */
    431             if (json_object_get_type(tmp) != json_type_string)
    432             {
    433                 SET_ERR(ERR_BAD_JSON_TYPE);
    434                 SET_ERR_STR_FMT("Wrong type for %s, expected a string", name);
    435                 goto cleanup;
    436             }
    437 
    438             /* Add it to the context */
    439             ctx->__pkg_version = strdup(json_object_get_string(tmp));
    440         }
    441         else if (strcmp(name, PACKER_CONF_PACKAGE_DESC_TOKEN) == 0)
    442         {
    443             /* Member type is unexpected */
    444             if (json_object_get_type(tmp) != json_type_string)
    445             {
    446                 SET_ERR(ERR_BAD_JSON_TYPE);
    447                 SET_ERR_STR_FMT("Wrong type for %s, expected a string", name);
    448                 goto cleanup;
    449             }
    450 
    451             /* Add it to the context */
    452             ctx->__pkg_desc = strdup(json_object_get_string(tmp));
    453         }
    454         else if (strcmp(name, PACKER_CONF_PACKAGE_SBU_TOKEN) == 0)
    455         {
    456             /* Member type is unexpected */
    457             if (json_object_get_type(tmp) != json_type_double
    458                 && json_object_get_type(tmp) != json_type_int)
    459             {
    460                 SET_ERR(ERR_BAD_JSON_TYPE);
    461                 SET_ERR_STR_FMT("Wrong type for %s, expected a int / double", name);
    462                 goto cleanup;
    463             }
    464 
    465             /* Add it to the context */
    466             ctx->__pkg_sbu = json_object_get_double(tmp);
    467         }
    468         else if (strcmp(name, PACKER_CONF_PACKAGE_CATEG_TOKEN) == 0)
    469         {
    470             /* Member type is unexpected */
    471             if (json_object_get_type(tmp) != json_type_string)
    472             {
    473                 SET_ERR(ERR_BAD_JSON_TYPE);
    474                 SET_ERR_STR_FMT("Wrong type for %s, expected a string", name);
    475                 goto cleanup;
    476             }
    477 
    478             /* Add it to the context */
    479             ctx->__pkg_categ = strdup(json_object_get_string(tmp));
    480         }
    481         else if (strcmp(name, PACKER_CONF_PACKAGE_INST_SIZE_TOKEN) == 0)
    482         {
    483             /* Member type is unexpected */
    484             if (json_object_get_type(tmp) != json_type_double
    485                 && json_object_get_type(tmp) != json_type_int)
    486             {
    487                 SET_ERR(ERR_BAD_JSON_TYPE);
    488                 SET_ERR_STR_FMT("Wrong type for %s, expected a string", name);
    489                 goto cleanup;
    490             }
    491 
    492             /* Add it to the context */
    493             ctx->__pkg_inst_size = json_object_get_double(tmp);
    494         }
    495         /* Wrong token */
    496         else
    497         {
    498             SET_ERR(ERR_BAD_JSON);
    499             SET_ERR_STR_FMT("Unknown JSON token: %s", name);
    500             goto cleanup;
    501         }
    502 
    503         /* Get next member */
    504         json_object_iter_next(&it);
    505     }
    506     return true;
    507 
    508 cleanup:
    509     packer_header_package_free(ctx->header);
    510     return false;
    511 }
    512 
    513 MPX_STATIC bool packer_read_config_file(packer_t *ctx) {
    514     struct json_object_iterator     it, it_end;
    515     const char                      *name;
    516 
    517     assert(ctx != NULL);
    518 
    519     /* Get first and last member */
    520     it = json_object_iter_begin(ctx->json);
    521     it_end = json_object_iter_end(ctx->json);
    522 
    523     ctx->header = packer_header_init();
    524 
    525     /* Iterating over each member */
    526     while (!json_object_iter_equal(&it, &it_end))
    527     {
    528         /* Get the member's name */
    529         name = json_object_iter_peek_name(&it);
    530 
    531         if (strcmp(name, PACKER_CONF_PACKAGE_TOKEN) == 0)
    532         {
    533             if (!packer_read_config_package(ctx, json_object_iter_peek_value(&it)))
    534                 goto cleanup;
    535         }
    536         else if (strcmp(name, PACKER_CONF_COMP_TOKEN) == 0)
    537         {
    538             if (!packer_read_config_comp(ctx, json_object_iter_peek_value(&it)))
    539                 goto cleanup;
    540         }
    541         else if (strcmp(name, PACKER_CONF_DEPS_TOKEN) == 0)
    542         {
    543             if (!packer_read_config_deps(ctx, json_object_iter_peek_value(&it)))
    544                 goto cleanup;
    545         }
    546         /* Wrong token */
    547         else
    548         {
    549             SET_ERR(ERR_BAD_JSON);
    550             SET_ERR_STR_FMT("Unknown global JSON token: %s", name);
    551             goto cleanup;
    552         }
    553 
    554         /* Get next member */
    555         json_object_iter_next(&it);
    556     }
    557     return true;
    558 
    559 cleanup:
    560     packer_header_free(ctx->header);
    561     ctx->header = NULL;
    562     return false;
    563 }
    564 
    565 bool packer_read_dir(packer_t *ctx) {
    566     char        old_pwd[PATH_MAX];
    567 
    568     assert(ctx != NULL);
    569 
    570     getcwd(old_pwd, sizeof(old_pwd));
    571 
    572     /* If we can't get the current working directory, it's a fatal error */
    573     assert(old_pwd != NULL);
    574 
    575     if (ctx->type != PACKER_TYPE_DIRECTORY)
    576         goto error;
    577 
    578     if (chdir(ctx->str) == -1)
    579     {
    580         SET_ERR(ERR_CHDIR_FAILED);
    581         SET_ERR_STR_FMT("Can't go to the directory %s", ctx->str);
    582         goto error;
    583     }
    584 
    585     /* Get the JSON object */
    586     ctx->json = json_object_from_file(PACKER_DEF_CONF_FN);
    587     if (ctx->json == NULL)
    588     {
    589         SET_ERR(ERR_BAD_JSON);
    590         SET_ERR_STR_FMT("Error at parsing JSON in: %s/%s", ctx->str, PACKER_DEF_CONF_FN);
    591         goto error;
    592     }
    593 
    594     chdir(old_pwd);
    595     return packer_read_config_file(ctx);
    596 
    597 error:
    598     chdir(old_pwd);
    599     return false;
    600 }
    601 
    602 MPX_STATIC void write_package_header(FILE *fd, packer_t *ctx) {
    603     packer_header_t     *h = ctx->header;
    604     mlist_t             *tmp = NULL;
    605     vector_string_t     *opt = NULL;
    606     const char          *tmp_str = NULL;
    607     u32_t               list_len = 0, conf_len = 0;
    608     double              sbu, inst_size;
    609 
    610     /* Write 3 bytes magic */
    611     fprintf(fd, PACKER_MPX_MAGIC);
    612 
    613     fprintf(fd, "%s%c", h->package.name, 0);
    614     fprintf(fd, "%s%c", h->package.version, 0);
    615     fprintf(fd, "%s%c", h->package.description, 0);
    616     fprintf(fd, "%s%c", h->package.categ, 0);
    617 
    618     /* Endianness of the SBU */
    619     sbu = htonl(h->package._sbu);
    620     fwrite(&sbu, sizeof(sbu), 1, fd);
    621 
    622     /* Endianness of the installation size */
    623     inst_size = htonl(h->package.inst_size);
    624     fwrite(&inst_size, sizeof(inst_size), 1, fd);
    625 
    626     /* Endianness of the configuration list len */
    627     conf_len = htonl(list_size(h->compilation.configure));
    628     fwrite(&conf_len, sizeof(u32_t), 1, fd);
    629 
    630     /* If configure is not null, write it to the archive */
    631     if (list_size(h->compilation.configure) != 0)
    632     {
    633         list_for_each(h->compilation.configure, tmp, opt) {
    634             if (opt->str1 != NULL)
    635                 fprintf(fd, "%s:%s%c", opt->str1, opt->str2, 0);
    636             else
    637                 fprintf(fd, "%s%c", opt->str2, 0);
    638         }
    639     }
    640     fprintf(fd, "%s%c", STR_OR_EMPTY(h->compilation.make), 0);
    641     fprintf(fd, "%s%c", STR_OR_EMPTY(h->compilation.test), 0);
    642     fprintf(fd, "%s%c", STR_OR_EMPTY(h->compilation.install), 0);
    643 
    644     /* Endianness of the environnement list len */
    645     conf_len = htonl(list_size(h->compilation.env));
    646     fwrite(&conf_len, sizeof(u32_t), 1, fd);
    647 
    648     if (list_size(h->compilation.env) != 0)
    649     {
    650         list_for_each(h->compilation.env, tmp, opt)
    651         {
    652             if (opt->str1 != NULL)
    653                 fprintf(fd, "%s:%s%c", opt->str1, opt->str2, 0);
    654             else
    655                 fprintf(fd, "%s%c", opt->str2, 0);
    656         }
    657     }
    658 
    659     /* Endianness of the dependencies list */
    660     list_len = htonl(list_size(h->dependencies.list));
    661     fwrite(&list_len, sizeof(u32_t), 1, fd);
    662 
    663     list_for_each(h->dependencies.list, tmp, tmp_str) {
    664         fprintf(fd, "%s%c", tmp_str, '\0');
    665     }
    666 }
    667 
    668 MPX_STATIC bool write_packer_sources(FILE *fd, packer_t *ctx, const char *dir_name) {
    669     mlist_t         *files_list = NULL;
    670     mlist_t         *dirs = NULL;
    671     mlist_t         *tmp = NULL, *tmp2 = NULL;
    672     char            old_pwd[PATH_MAX];
    673     char            *dir = NULL;
    674     packer_file_t   *file;
    675 
    676     assert(fd != NULL && ctx != NULL);
    677 
    678     getcwd(old_pwd, sizeof(old_pwd));
    679 
    680     /* If we can't get the current working directory, it's a fatal error */
    681     assert(old_pwd != NULL);
    682 
    683     chdir(ctx->str);
    684 
    685     /* Add the dir to the linked list, to begin with */
    686     list_add(dirs, (void *)dir_name, strlen(dir_name) + 1);
    687 
    688     /* Iterating while there are dir to read in */
    689     list_for_each(dirs, tmp, dir) {
    690         if (read_files_from_dir(dir, &files_list, &dirs) == false)
    691             goto error;
    692 
    693         if (list_size(files_list) == 0)
    694             continue;
    695 
    696         /* For each file found, write it to the archive */
    697         list_for_each(files_list, tmp2, file) {
    698             fprintf(fd, "%s%c", file->fn, 0);
    699             fwrite(&file->mode, sizeof(file->mode), 1, fd);
    700             fwrite(&file->compressed_size, sizeof(file->compressed_size), 1, fd);
    701             fwrite(&file->file_size, sizeof(file->file_size), 1, fd);
    702             if (file->file_size != 0)
    703             {
    704                 fwrite(&file->sum, crypto_hash_sha256_BYTES, 1, fd);
    705                 fwrite(file->content, file->compressed_size, 1, fd);
    706             }
    707         }
    708 
    709         /* Cleanup the written files */
    710         list_free(files_list, packer_file_free);
    711         files_list = NULL;
    712     }
    713 
    714     list_free(dirs, NULL);
    715     chdir(old_pwd);
    716     return true;
    717 
    718 error:
    719     list_free(files_list, packer_file_free);
    720     list_free(dirs, NULL);
    721     chdir(old_pwd);
    722     return false;
    723 }
    724 
    725 bool packer_create_archive(packer_t *ctx, const char *archive_path) {
    726     FILE *fd;
    727 
    728     assert(archive_path == NULL || ctx != NULL);
    729     if (ctx->type != PACKER_TYPE_DIRECTORY)
    730     {
    731         SET_ERR(ERR_BAD_ARCHIVE_TYPE);
    732         return false;
    733     }
    734 
    735     /* Create the archive file */
    736     fd = fopen(archive_path, "w+");
    737     if (fd == NULL)
    738     {
    739         SET_ERR(ERR_OPEN);
    740         SET_ERR_STR_FMT("Can't open file %s", archive_path);
    741         return false;
    742     }
    743 
    744     /* Write header */
    745     write_package_header(fd, ctx);
    746 
    747     /* Write srcs/ */
    748     if (write_packer_sources(fd, ctx, PACKER_SRC_DIR) == false)
    749         goto error;
    750 
    751     /* Write patches/ */
    752     if (write_packer_sources(fd, ctx, PACKER_PATCH_DIR) == false)
    753         goto error;
    754 
    755     /* Write scripts/ */
    756     if (write_packer_sources(fd, ctx, PACKER_SCRIPT_DIR) == false)
    757         goto error;
    758 
    759     fclose(fd);
    760     return true;
    761 
    762 error:
    763     fclose(fd);
    764     return false;
    765 }
    766 
    767 MPX_STATIC int read_package_header_package(const char *file, packer_t *ctx)
    768 {
    769     int                         ret = 0;
    770     double                      sbu, inst_size;
    771 
    772     if (ctx == NULL)
    773         return ret;
    774 
    775     ctx->__pkg_name = strdup(file + ret);
    776     if (ctx->__pkg_name == NULL)
    777         goto cleanup;
    778 
    779     ret += strlen(ctx->__pkg_name) + 1;
    780 
    781     ctx->__pkg_version = strdup(file + ret);
    782     if (ctx->__pkg_version == NULL)
    783         goto cleanup;
    784 
    785     ret += strlen(ctx->__pkg_version) + 1;
    786 
    787     ctx->__pkg_desc = strdup(file + ret);
    788     if (ctx->__pkg_desc == NULL)
    789         goto cleanup;
    790 
    791     ret += strlen(ctx->__pkg_desc) + 1;
    792 
    793     ctx->__pkg_categ = strdup(file + ret);
    794     if (ctx->__pkg_categ == NULL)
    795         goto cleanup;
    796 
    797     ret += strlen(ctx->__pkg_categ) + 1;
    798 
    799     memcpy(&sbu, file + ret, sizeof(sbu));
    800     ctx->__pkg_sbu = ntohl(sbu);
    801     ret += sizeof(sbu);
    802 
    803     memcpy(&inst_size, file + ret, sizeof(inst_size));
    804     ctx->__pkg_inst_size = ntohl(inst_size);
    805     ret += sizeof(inst_size);
    806 
    807     return ret;
    808 
    809 cleanup:
    810     SET_ERR(ERR_MEMORY);
    811     if (ctx != NULL)
    812         packer_header_package_free(ctx->header);
    813     return 0;
    814 }
    815 
    816 MPX_STATIC bool read_conf_opt(char *file, mlist_t **list, int *ret) {
    817     u32_t               size;
    818     vector_string_t     *opt = NULL;
    819     char                *tmp = NULL, *ptr = NULL;
    820 
    821     memcpy(&size, file + *ret, sizeof(size));
    822     size = ntohl(size);
    823     *ret += sizeof(size);
    824 
    825     /* Iterate over each configure parameter */
    826     for (u32_t i = 0; i < size; i++)
    827     {
    828         tmp = file + *ret;
    829         *ret += strlen(tmp) + 1;
    830 
    831         /* Find the ':' (option:value delimeter) */
    832         ptr = strchr(tmp, ':');
    833         if (ptr == NULL)
    834         {
    835             /* If there is none, simply copy the string */
    836             opt = vector_string_init(NULL, tmp);
    837             if (opt == NULL)
    838             {
    839                 SET_ERR(ERR_MEMORY);
    840                 goto cleanup;
    841             }
    842         }
    843         else
    844         {
    845             /* Copy the name */
    846             *ptr = 0;
    847             opt = vector_string_init(tmp, ptr + 1);
    848             if (opt == NULL)
    849             {
    850                 SET_ERR(ERR_MEMORY);
    851                 goto cleanup;
    852             }
    853         }
    854 
    855         /* Add the option to the context */
    856         list_add(*(list), opt, sizeof(*opt));
    857         free(opt);
    858     }
    859 
    860     return true;
    861 
    862 cleanup:
    863     list_free(*(list), vector_string_free);
    864     *list = NULL;
    865     return false;
    866 }
    867 
    868 MPX_STATIC int read_package_header_compilation(char *file, packer_t *ctx)
    869 {
    870     int                         ret = 0;
    871 
    872     if (ctx == NULL)
    873         return ret;
    874 
    875     if (read_conf_opt(file, &ctx->header->compilation.configure, &ret) != true)
    876     {
    877         goto cleanup;
    878     }
    879 
    880     ctx->header->compilation.make = strdup(file + ret);
    881     if (ctx->header->compilation.make == NULL)
    882     {
    883         SET_ERR(ERR_MEMORY);
    884         goto cleanup;
    885     }
    886 
    887     ret += strlen(ctx->header->compilation.make) + 1;
    888 
    889     ctx->header->compilation.test = strdup(file + ret);
    890     if (ctx->header->compilation.test == NULL)
    891     {
    892         SET_ERR(ERR_MEMORY);
    893         goto cleanup;
    894     }
    895     ret += strlen(ctx->header->compilation.test) + 1;
    896 
    897     ctx->header->compilation.install = strdup(file + ret);
    898     if (ctx->header->compilation.install == NULL)
    899     {
    900         SET_ERR(ERR_MEMORY);
    901         goto cleanup;
    902     }
    903     ret += strlen(ctx->header->compilation.install) + 1;
    904 
    905     if (read_conf_opt(file, &ctx->header->compilation.env, &ret) != true)
    906         goto cleanup;
    907 
    908     return ret;
    909 
    910 cleanup:
    911     if (ctx != NULL)
    912         packer_header_comp_free(ctx->header);
    913     return 0;
    914 }
    915 
    916 MPX_STATIC int read_package_header_dependencies(const char *file, packer_t *ctx) {
    917     int                         ret = 0;
    918     u32_t                       list_len = 0;
    919     char                        *tmp = NULL;
    920 
    921     /* Get the list size */
    922     memcpy(&list_len, file, sizeof(u32_t));
    923     /* Endianness */
    924     list_len = ntohl(list_len);
    925     ret += sizeof(u32_t);
    926 
    927     /* Iterate over each string */
    928     for (u32_t i = 0; i < list_len; i++)
    929     {
    930         /* Copy the dependency string */
    931         tmp = strdup(file + ret);
    932         if (tmp == NULL)
    933         {
    934             SET_ERR(ERR_MEMORY);
    935             goto cleanup;
    936         }
    937         ret += strlen(tmp) + 1;
    938 
    939         /* Add it to the context */
    940         list_add(ctx->header->dependencies.list, tmp, strlen(tmp) + 1);
    941         free(tmp);
    942     }
    943 
    944     return ret;
    945 
    946 cleanup:
    947     if (ctx != NULL)
    948         packer_header_deps_free(ctx->header);
    949     return 0;
    950 }
    951 
    952 MPX_STATIC bool read_package_header(char *file_content, packer_t *ctx, int *s_ret)
    953 {
    954     int  ret = 0, tmp;
    955 
    956     if (file_content == NULL || ctx == NULL)
    957     {
    958         SET_ERR(ERR_BAD_PTR);
    959         return false;
    960     }
    961 
    962     /* Test the 3 bytes magic */
    963     if (strncmp(file_content, PACKER_MPX_MAGIC, sizeof(PACKER_MPX_MAGIC) - 1) != 0)
    964     {
    965         SET_ERR(ERR_NOT_A_PACKAGE);
    966         SET_ERR_STR("Not a MPX archive");
    967         goto cleanup;
    968     }
    969 
    970     ret += sizeof(PACKER_MPX_MAGIC) - 1;
    971 
    972     ctx->header = packer_header_init();
    973     if (ctx->header == NULL)
    974         goto cleanup;
    975 
    976     tmp = read_package_header_package(file_content + ret, ctx);
    977     if (tmp == 0)
    978         goto cleanup;
    979     ret += tmp;
    980 
    981     tmp = read_package_header_compilation(file_content + ret, ctx);
    982     if (tmp == 0)
    983         goto cleanup;
    984     ret += tmp;
    985 
    986     tmp = read_package_header_dependencies(file_content + ret, ctx);
    987     if (tmp == 0)
    988         goto cleanup;
    989     ret += tmp;
    990 
    991     *s_ret = ret;
    992     return true;
    993 
    994 cleanup:
    995     if (ctx != NULL)
    996     {
    997         packer_header_free(ctx->header);
    998         ctx->header = NULL;
    999     }
   1000     return false;
   1001 }
   1002 
   1003 bool packer_read_archive_header(packer_t *ctx) {
   1004     char    *archive = NULL;
   1005     bool    ret;
   1006     int     cur = 0;
   1007 
   1008     if (ctx == NULL)
   1009         return false;
   1010 
   1011     if (ctx->type != PACKER_TYPE_ARCHIVE)
   1012         return false;
   1013 
   1014     /* Get file content */
   1015     archive = mpm_read_file_from_fn(ctx->str);
   1016     if (archive == NULL)
   1017     {
   1018         SET_ERR(ERR_MEMORY);
   1019         return false;
   1020     }
   1021 
   1022     ret = read_package_header(archive, ctx, &cur);
   1023     free(archive);
   1024     return ret;
   1025 }
   1026 
   1027 bool packer_extract_archive(packer_t *ctx, const char *dir) {
   1028     int                 fd, t_ctr;
   1029     bool                ret = false;
   1030     char                *archive = NULL;
   1031     off_t               size, ctr;
   1032     char                old_pwd[PATH_MAX];
   1033 
   1034     if (ctx == NULL)
   1035         return false;
   1036 
   1037     /* Save the current working directory */
   1038     getcwd(old_pwd, sizeof(old_pwd));
   1039 
   1040     if (ctx->type != PACKER_TYPE_ARCHIVE)
   1041     {
   1042         SET_ERR(ERR_BAD_ARCHIVE_TYPE);
   1043         return false;
   1044     }
   1045 
   1046     /* Open the archive */
   1047     fd = open(ctx->str, O_RDONLY);
   1048     if (fd == -1)
   1049     {
   1050         SET_ERR(ERR_OPEN);
   1051         SET_ERR_STR_FMT("Can't open archive '%s'", ctx->str);
   1052         return false;
   1053     }
   1054 
   1055     /* Get the archive binary content */
   1056     archive = mpm_read_file_from_fd(fd);
   1057     size = mpm_get_file_size_from_fd(fd);
   1058 
   1059     if (!read_package_header(archive, ctx, &t_ctr))
   1060         goto cleanup;
   1061 
   1062     ctr = t_ctr;
   1063 
   1064     /* Open the extract directory */
   1065     DIR *p_dir = opendir(dir);
   1066 
   1067     /* If it's non-existent, create it */
   1068     if (p_dir == NULL)
   1069     {
   1070         if (mkdir(dir, S_IRWXU | S_IRWXG | S_IRWXO) == -1)
   1071         {
   1072             SET_ERR(ERR_MKDIR_FAILED);
   1073             SET_ERR_STR_FMT("Cannot create directory '%s'\n", dir);
   1074             goto cleanup;
   1075         }
   1076     }
   1077     else
   1078         closedir(p_dir);
   1079 
   1080     /* Go to the extract directory */
   1081     if (chdir(dir) == -1)
   1082     {
   1083         SET_ERR(ERR_CHDIR_FAILED);
   1084         SET_ERR_STR_FMT("Cannot go in the directory '%s'\n", dir);
   1085         goto cleanup;
   1086     }
   1087 
   1088     /* Create the package directory name */
   1089     asprintf(&ctx->out_dir, "%s/%s-%s/", dir, ctx->__pkg_name, ctx->__pkg_version);
   1090 
   1091     /* Create the actual directory */
   1092     if (mkdir(ctx->out_dir, S_IRWXU | S_IRWXG | S_IRWXO) == -1)
   1093     {
   1094         SET_ERR(ERR_MKDIR_FAILED);
   1095         SET_ERR_STR_FMT("Cannot create directory '%s'\n", ctx->out_dir);
   1096         goto cleanup;
   1097     }
   1098 
   1099     /* Go in the directory */
   1100     chdir(ctx->out_dir);
   1101 
   1102     /* Read each file, and dump them to the disk */
   1103     while (size > ctr)
   1104     {
   1105         if (packer_file_from_binary_to_disk(archive, &ctr) == false)
   1106             goto cleanup;
   1107     }
   1108 
   1109     ret = true;
   1110 
   1111 cleanup:
   1112     chdir(old_pwd);
   1113     close(fd);
   1114     free(archive);
   1115     return ret;
   1116 }