xbps/lib/pkgdb_conversion.c
2020-04-24 11:44:19 +02:00

203 lines
5.4 KiB
C

/*-
* Licensed under the SPDX BSD-2-Clause identifier.
* Use is subject to license terms, as specified in the LICENSE file.
*/
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "xbps_api_impl.h"
static int
pkgdb038(struct xbps_handle *xhp, const char *opkgdb_plist)
{
xbps_dictionary_t pkgdb, opkgdb;
xbps_object_iterator_t iter;
xbps_object_t obj;
int rv = 0;
/*
* The pkgdb-0.38.plist format contains all pkg metadata objects,
* except its files list. To avoid a broken conversion, the old
* pkg metadata plists are kept, and the converted ones are written
* to another path.
*
* - <metadir>/pkgdb-0.38.plist
* - <metadir>/.<pkgname>-files.plist
*/
opkgdb = xbps_plist_dictionary_from_file(xhp, opkgdb_plist);
if (opkgdb == NULL)
return EINVAL;
pkgdb = xbps_dictionary_create();
assert(pkgdb);
/*
* Iterate over the old pkgdb dictionary and copy all pkg objects
* into the new pkgdb dictionary.
*/
iter = xbps_dictionary_iterator(opkgdb);
assert(iter);
while ((obj = xbps_object_iterator_next(iter))) {
xbps_dictionary_t pkgd, pkgfilesd, pkgmetad;
xbps_object_iterator_t iter2;
xbps_object_t obj2;
const char *pkgname, *repo;
char *pkgmeta;
pkgname = xbps_dictionary_keysym_cstring_nocopy(obj);
pkgd = xbps_dictionary_get_keysym(opkgdb, obj);
/*
* Rename "repository-origin" obj to "repository" to match
* the repository index obj.
*/
if (xbps_dictionary_get_cstring_nocopy(pkgd, "repository-origin", &repo)) {
xbps_dictionary_set_cstring(pkgd, "repository", repo);
xbps_dictionary_remove(pkgd, "repository-origin");
}
/*
* Copy old pkgdb objects to the new pkgdb.
*/
if (!xbps_dictionary_set(pkgdb, pkgname, pkgd)) {
xbps_dbg_printf(xhp, "%s: failed to copy %s pkgd "
"for pkgdb conversion\n", __func__, pkgname);
rv = EINVAL;
goto out;
}
/*
* Copy pkg metadata objs to the new pkgdb.
*/
pkgmeta = xbps_xasprintf("%s/.%s.plist", xhp->metadir, pkgname);
pkgmetad = xbps_plist_dictionary_from_file(xhp, pkgmeta);
if (pkgmetad == NULL) {
rv = EINVAL;
xbps_dbg_printf(xhp, "%s: cannot open %s: %s\n",
__func__, pkgmeta, strerror(errno));
goto out;
}
pkgfilesd = xbps_dictionary_create();
assert(pkgfilesd);
iter2 = xbps_dictionary_iterator(pkgmetad);
assert(iter2);
while ((obj2 = xbps_object_iterator_next(iter2))) {
xbps_object_t curobj;
const char *key, *excluded[] = {
"conf_files", "dirs", "files", "links"
};
bool skip = false;
key = xbps_dictionary_keysym_cstring_nocopy(obj2);
curobj = xbps_dictionary_get_keysym(pkgmetad, obj2);
for (uint8_t i = 0; i < __arraycount(excluded); i++) {
if (strcmp(excluded[i], key) == 0) {
skip = true;
break;
}
}
if (skip) {
assert(xbps_object_type(curobj) == XBPS_TYPE_ARRAY);
if (xbps_array_count(curobj))
xbps_dictionary_set(pkgfilesd, key, curobj);
continue;
}
if (!xbps_dictionary_set(pkgd, key, curobj)) {
xbps_dbg_printf(xhp, "%s: failed to copy %s "
"pkgd for pkgdb conversion\n", pkgname, key);
xbps_object_iterator_release(iter2);
xbps_object_release(pkgmetad);
free(pkgmeta);
rv = EINVAL;
goto out;
}
}
xbps_object_iterator_release(iter2);
/*
* Externalize <pkgname>-files.plist if pkg contains any file.
*/
if (xbps_dictionary_count(pkgfilesd)) {
char *pkgfiles, *sha256;
pkgfiles = xbps_xasprintf("%s/.%s-files.plist", xhp->metadir, pkgname);
if (!xbps_dictionary_externalize_to_file(pkgfilesd, pkgfiles)) {
xbps_dbg_printf(xhp, "%s: failed to "
"externalize %s: %s\n", __func__, pkgfiles, strerror(errno));
rv = EINVAL;
goto out;
}
xbps_dbg_printf(xhp, "%s: externalized %s successfully\n", __func__, pkgfiles);
/*
* Update SHA56 hash for the pkg files plist.
*/
sha256 = xbps_file_hash(pkgfiles);
assert(sha256);
xbps_dictionary_set_cstring(pkgd, "metafile-sha256", sha256);
free(sha256);
free(pkgfiles);
} else {
/* unnecessary obj if pkg contains no files */
xbps_dictionary_remove(pkgd, "metafile-sha256");
}
xbps_object_release(pkgfilesd);
xbps_object_release(pkgmetad);
free(pkgmeta);
}
/*
* Externalize the new pkgdb plist.
*/
if (!xbps_dictionary_externalize_to_file(pkgdb, xhp->pkgdb_plist)) {
xbps_dbg_printf(xhp, "%s: failed to externalize %s: "
"%s!\n", __func__, xhp->pkgdb_plist, strerror(errno));
rv = EINVAL;
goto out;
}
out:
if (iter)
xbps_object_iterator_release(iter);
if (pkgdb)
xbps_object_release(pkgdb);
if (opkgdb)
xbps_object_release(opkgdb);
return rv;
}
int HIDDEN
xbps_pkgdb_conversion(struct xbps_handle *xhp)
{
char *opkgdb = NULL;
int rv = 0;
/*
* If pkgdb-0.38.plist exists there's nothing to do.
*/
if (xhp && xhp->pkgdb_plist && (access(xhp->pkgdb_plist, R_OK) == 0))
return 0;
/*
* If pkgdb-0.21.plist does not exist there's nothing to do.
*/
opkgdb = xbps_xasprintf("%s/pkgdb-0.21.plist", xhp->metadir);
if (access(opkgdb, R_OK) == 0) {
/*
* Make the conversion and exit on success. It's just
* better to make the upgrade in two steps.
*/
xbps_set_cb_state(xhp, XBPS_STATE_PKGDB, 0, NULL, NULL);
if ((rv = pkgdb038(xhp, opkgdb)) == 0) {
xbps_set_cb_state(xhp, XBPS_STATE_PKGDB_DONE, 0, NULL, NULL);
xbps_end(xhp);
exit(EXIT_SUCCESS);
}
}
free(opkgdb);
return rv;
}