mirror of
https://github.com/freebsd/freebsd-src.git
synced 2026-11-07 04:36:52 -10:00
Obtained from https://github.com/pkgconf/pkgconf/archive/refs/tags/pkgconf-3.0.9.tar.gz SHA1: a390f016a7a5ff419c9eef9e2b2c01fe86c11971 - SHA256: 32310a33bb97425ebc0707cb5af59f9dc05d10282dcd4db628a45ed904993dc6 - SHA512: 30776d31f860910286b96fbf60a19b5a6d1e73cb6a1077a019d763ae6e5ed1e8d81bc3649978c83f40e5e90ae779f7e530c513b700c8e73bb6399883dd6ef7ab - Sponsored by: The FreeBSD Foundation
592 lines
17 KiB
C
592 lines
17 KiB
C
/*
|
||
* SPDX-License-Identifier: BSD-2-Clause
|
||
*
|
||
* Copyright (c) 2025 The FreeBSD Foundation
|
||
*
|
||
* Portions of this software were developed by
|
||
* Tuukka Pasanen <[email protected]> under sponsorship from
|
||
* the FreeBSD Foundation
|
||
*/
|
||
|
||
#include <stdlib.h>
|
||
#include <string.h>
|
||
#include <libpkgconf/libpkgconf.h>
|
||
#include "util.h"
|
||
#include "serialize.h"
|
||
#include "software.h"
|
||
#include "core.h"
|
||
|
||
static char *
|
||
relationship_spdx_id(pkgconf_client_t *client, const char *from, const char *to, char sep)
|
||
{
|
||
pkgconf_buffer_t relationship_buf = PKGCONF_BUFFER_INITIALIZER;
|
||
char *spdx_id = NULL;
|
||
|
||
if (!pkgconf_buffer_append_fmt(&relationship_buf, "%s%cdependsOn%c%s", from, sep, sep, to))
|
||
goto out;
|
||
|
||
if (pkgconf_buffer_len(&relationship_buf) == 0)
|
||
goto out;
|
||
|
||
spdx_id = spdxtool_util_get_spdx_id_string(client, "Relationship", pkgconf_buffer_str(&relationship_buf));
|
||
|
||
out:
|
||
pkgconf_buffer_finalize(&relationship_buf);
|
||
return spdx_id;
|
||
}
|
||
|
||
/*
|
||
* !doc
|
||
*
|
||
* .. c:function:: spdxtool_software_sbom_t *spdxtool_software_sbom_new(pkgconf_client_t *client, const char *spdx_id, const char *creation_id, const char *sbom_type)
|
||
*
|
||
* Create new /Software/Sbom struct
|
||
*
|
||
* :param pkgconf_client_t *client: The pkgconf client being accessed.
|
||
* :param const char *spdx_id: spdxId for this SBOM element
|
||
* :param const char *creation_id: id for CreationInfo
|
||
* :param const char *sbom_type: Sbom types can be found SPDX documentation
|
||
* :return: NULL if some problem occurs and Sbom struct if not
|
||
*/
|
||
spdxtool_software_sbom_t *
|
||
spdxtool_software_sbom_new(pkgconf_client_t *client, const char *spdx_id, const char *creation_id, const char *sbom_type)
|
||
{
|
||
if (!client || !spdx_id || !creation_id || !sbom_type)
|
||
return NULL;
|
||
|
||
spdxtool_software_sbom_t *sbom = calloc(1, sizeof(spdxtool_software_sbom_t));
|
||
if (!sbom)
|
||
goto err;
|
||
|
||
sbom->type = "software_Sbom";
|
||
sbom->spdx_id = strdup(spdx_id);
|
||
sbom->creation_info = strdup(creation_id);
|
||
sbom->sbom_type = strdup(sbom_type);
|
||
|
||
if (!sbom->spdx_id || !sbom->creation_info || !sbom->sbom_type)
|
||
goto err;
|
||
|
||
return sbom;
|
||
|
||
err:
|
||
pkgconf_error(client, "spdxtool_software_sbom_new: out of memory");
|
||
spdxtool_software_sbom_free(sbom);
|
||
return NULL;
|
||
}
|
||
|
||
/*
|
||
* !doc
|
||
*
|
||
* .. c:function:: void spdxtool_software_sbom_free(spdxtool_software_sbom_t *sbom)
|
||
*
|
||
* Free /Software/Sbom struct
|
||
*
|
||
* :param spdxtool_software_sbom_t *sbom: Sbom struct to be freed.
|
||
* :return: nothing
|
||
*/
|
||
void
|
||
spdxtool_software_sbom_free(spdxtool_software_sbom_t *sbom)
|
||
{
|
||
if(!sbom)
|
||
return;
|
||
|
||
free(sbom->spdx_id);
|
||
free(sbom->creation_info);
|
||
free(sbom->sbom_type);
|
||
|
||
free(sbom);
|
||
}
|
||
|
||
/*
|
||
* !doc
|
||
*
|
||
* .. c:function:: spdxtool_serialize_value_t *spdxtool_software_sbom_to_object(pkgconf_client_t *client, spdxtool_software_sbom_t *sbom)
|
||
*
|
||
* Serialize /Software/Sbom struct to a JSON value tree. As a side effect,
|
||
* the package associated with the SBOM's rootElement is registered on the
|
||
* document via spdxtool_core_spdx_document_add_package, and relationship
|
||
* element IDs are registered via spdxtool_core_spdx_document_add_element.
|
||
*
|
||
* :param pkgconf_client_t *client: The pkgconf client being accessed.
|
||
* :param spdxtool_software_sbom_t *sbom: Sbom struct to be serialized.
|
||
* :return: spdxtool_serialize_value_t * representing the Sbom object.
|
||
*/
|
||
spdxtool_serialize_value_t *
|
||
spdxtool_software_sbom_to_object(pkgconf_client_t *client, spdxtool_software_sbom_t *sbom)
|
||
{
|
||
spdxtool_serialize_value_t *ret = NULL;
|
||
spdxtool_serialize_object_list_t *object_list = NULL;
|
||
spdxtool_serialize_array_t *sbom_type_array = NULL;
|
||
spdxtool_serialize_array_t *root_element_array = NULL;
|
||
spdxtool_serialize_array_t *element_array = NULL;
|
||
char *spdx_id = NULL;
|
||
|
||
char sep = spdxtool_util_get_uri_separator(client);
|
||
|
||
spdx_id = spdxtool_util_tuple_lookup(client, &sbom->rootElement->vars, "spdxId");
|
||
if (!spdx_id)
|
||
goto err;
|
||
|
||
object_list = spdxtool_serialize_object_list_new();
|
||
if (!object_list)
|
||
goto err;
|
||
|
||
sbom_type_array = spdxtool_serialize_array_new();
|
||
if (!sbom_type_array)
|
||
goto err;
|
||
|
||
if (!spdxtool_serialize_array_add_string(sbom_type_array, sbom->sbom_type))
|
||
goto err;
|
||
|
||
root_element_array = spdxtool_serialize_array_new();
|
||
if (!root_element_array)
|
||
goto err;
|
||
|
||
if (!spdxtool_serialize_array_add_string(root_element_array, spdx_id))
|
||
goto err;
|
||
|
||
element_array = spdxtool_serialize_array_new();
|
||
if (!element_array)
|
||
goto err;
|
||
|
||
pkgconf_node_t *node = NULL;
|
||
PKGCONF_FOREACH_LIST_ENTRY(sbom->rootElement->required.head, node)
|
||
{
|
||
pkgconf_dependency_t *dep = node->data;
|
||
pkgconf_pkg_t *match = dep->match;
|
||
|
||
/* an unresolved (but tolerated) dependency has no match */
|
||
if (match == NULL)
|
||
continue;
|
||
|
||
char *spdx_id_relation = relationship_spdx_id(client, sbom->rootElement->id, match->id, sep);
|
||
if (!spdx_id_relation)
|
||
goto err;
|
||
|
||
if (!spdxtool_serialize_array_add_string(element_array, spdx_id_relation))
|
||
{
|
||
free(spdx_id_relation);
|
||
goto err;
|
||
}
|
||
|
||
if (!spdxtool_core_spdx_document_add_element(client, sbom->spdx_document, spdx_id_relation))
|
||
{
|
||
free(spdx_id_relation);
|
||
goto err;
|
||
}
|
||
|
||
free(spdx_id_relation);
|
||
}
|
||
|
||
PKGCONF_FOREACH_LIST_ENTRY(sbom->rootElement->requires_private.head, node)
|
||
{
|
||
pkgconf_dependency_t *dep = node->data;
|
||
pkgconf_pkg_t *match = dep->match;
|
||
|
||
/* an unresolved (but tolerated) dependency has no match */
|
||
if (match == NULL)
|
||
continue;
|
||
|
||
char *spdx_id_relation = relationship_spdx_id(client, sbom->rootElement->id, match->id, sep);
|
||
if (!spdx_id_relation)
|
||
goto err;
|
||
|
||
if (!spdxtool_serialize_array_add_string(element_array, spdx_id_relation))
|
||
{
|
||
free(spdx_id_relation);
|
||
goto err;
|
||
}
|
||
|
||
if (!spdxtool_core_spdx_document_add_element(client, sbom->spdx_document, spdx_id_relation))
|
||
{
|
||
free(spdx_id_relation);
|
||
goto err;
|
||
}
|
||
|
||
free(spdx_id_relation);
|
||
}
|
||
|
||
char *value = spdxtool_util_tuple_lookup(client, &sbom->rootElement->vars, "hasDeclaredLicense");
|
||
if (value)
|
||
{
|
||
if (!spdxtool_serialize_array_add_string(element_array, value))
|
||
{
|
||
free(value);
|
||
goto err;
|
||
}
|
||
|
||
if (!spdxtool_core_spdx_document_add_element(client, sbom->spdx_document, value))
|
||
{
|
||
free(value);
|
||
goto err;
|
||
}
|
||
|
||
free(value);
|
||
}
|
||
|
||
value = spdxtool_util_tuple_lookup(client, &sbom->rootElement->vars, "hasConcludedLicense");
|
||
if (value)
|
||
{
|
||
if (!spdxtool_serialize_array_add_string(element_array, value))
|
||
{
|
||
free(value);
|
||
goto err;
|
||
}
|
||
|
||
if (!spdxtool_core_spdx_document_add_element(client, sbom->spdx_document, value))
|
||
{
|
||
free(value);
|
||
goto err;
|
||
}
|
||
|
||
free(value);
|
||
}
|
||
|
||
if (!(spdxtool_serialize_object_add_string(object_list, "type", sbom->type) &&
|
||
spdxtool_serialize_object_add_string(object_list, "creationInfo", sbom->creation_info) &&
|
||
spdxtool_serialize_object_add_string(object_list, "spdxId", sbom->spdx_id)))
|
||
{
|
||
goto err;
|
||
}
|
||
|
||
/* object_add_array always takes ownership of the array (it is freed even on
|
||
* failure), so clear our reference before checking the result to avoid a
|
||
* double free at the error label.
|
||
*/
|
||
bool ok = spdxtool_serialize_object_add_array(object_list, "software_sbomType", sbom_type_array);
|
||
sbom_type_array = NULL;
|
||
if (!ok)
|
||
goto err;
|
||
|
||
ok = spdxtool_serialize_object_add_array(object_list, "rootElement", root_element_array);
|
||
root_element_array = NULL;
|
||
if (!ok)
|
||
goto err;
|
||
|
||
ok = spdxtool_serialize_object_add_array(object_list, "element", element_array);
|
||
element_array = NULL;
|
||
if (!ok)
|
||
goto err;
|
||
|
||
if (!spdxtool_core_spdx_document_add_package(client, sbom->spdx_document, sbom->rootElement))
|
||
goto err;
|
||
|
||
ret = spdxtool_serialize_value_object(object_list);
|
||
object_list = NULL;
|
||
|
||
err:
|
||
if (!ret)
|
||
pkgconf_error(client, "spdxtool_software_sbom_to_object: out of memory");
|
||
|
||
free(spdx_id);
|
||
spdxtool_serialize_object_list_free(object_list);
|
||
spdxtool_serialize_array_free(sbom_type_array);
|
||
spdxtool_serialize_array_free(root_element_array);
|
||
spdxtool_serialize_array_free(element_array);
|
||
return ret;
|
||
}
|
||
|
||
static bool
|
||
serialize_copyright_lines_to_object(spdxtool_serialize_object_list_t *object_list, const pkgconf_list_t *copyright_lines)
|
||
{
|
||
pkgconf_buffer_t copyright_buf = PKGCONF_BUFFER_INITIALIZER;
|
||
const pkgconf_node_t *node;
|
||
|
||
if (copyright_lines->head == NULL)
|
||
return spdxtool_serialize_object_add_string(object_list, "software_copyrightText", "NOASSERTION") != NULL;
|
||
|
||
PKGCONF_FOREACH_LIST_ENTRY(copyright_lines->head, node)
|
||
{
|
||
const pkgconf_bufferset_t *set = node->data;
|
||
if (!pkgconf_buffer_join(©right_buf, '\n', pkgconf_buffer_str_or_empty(&set->buffer), NULL))
|
||
{
|
||
pkgconf_buffer_finalize(©right_buf);
|
||
return false;
|
||
}
|
||
}
|
||
|
||
bool ok = spdxtool_serialize_object_add_string(object_list, "software_copyrightText", pkgconf_buffer_str_or_empty(©right_buf)) != NULL;
|
||
pkgconf_buffer_finalize(©right_buf);
|
||
return ok;
|
||
}
|
||
|
||
/*
|
||
* !doc
|
||
*
|
||
* .. c:function:: spdxtool_serialize_value_t *spdxtool_software_package_to_object(pkgconf_client_t *client, pkgconf_pkg_t *pkg, spdxtool_core_spdx_document_t *spdx)
|
||
*
|
||
* Serialize /Software/Package struct to a JSON value tree. As a side effect,
|
||
* any license and dependency relationships generated during serialization are
|
||
* added to the document via spdxtool_core_spdx_document_add_relationship.
|
||
*
|
||
* :param pkgconf_client_t *client: The pkgconf client being accessed.
|
||
* :param pkgconf_pkg_t *pkg: Package struct to be serialized.
|
||
* :param spdxtool_core_spdx_document_t *spdx: SpdxDocument to which generated relationships are added.
|
||
* :return: spdxtool_serialize_value_t * representing the Package object.
|
||
*/
|
||
spdxtool_serialize_value_t *
|
||
spdxtool_software_package_to_object(pkgconf_client_t *client, pkgconf_pkg_t *pkg, spdxtool_core_spdx_document_t *spdx)
|
||
{
|
||
spdxtool_serialize_value_t *ret = NULL;
|
||
spdxtool_serialize_object_list_t *object_list = NULL;
|
||
spdxtool_serialize_array_t *originated_by = NULL;
|
||
char *creation_info = NULL;
|
||
char *spdx_id = NULL;
|
||
char *agent = NULL;
|
||
char *supplier = NULL;
|
||
char *spdx_id_license = NULL;
|
||
pkgconf_list_t relations = PKGCONF_LIST_INITIALIZER;
|
||
pkgconf_list_t *cpy_relations = NULL;
|
||
pkgconf_node_t *node = NULL;
|
||
char sep = spdxtool_util_get_uri_separator(client);
|
||
|
||
creation_info = spdxtool_util_tuple_lookup(client, &pkg->vars, "creationInfo");
|
||
spdx_id = spdxtool_util_tuple_lookup(client, &pkg->vars, "spdxId");
|
||
agent = spdxtool_util_tuple_lookup(client, &pkg->vars, "agent");
|
||
|
||
if (!creation_info || !spdx_id || !agent)
|
||
goto err;
|
||
|
||
object_list = spdxtool_serialize_object_list_new();
|
||
if (!object_list)
|
||
goto err;
|
||
|
||
originated_by = spdxtool_serialize_array_new();
|
||
if (!originated_by)
|
||
goto err;
|
||
|
||
if (!spdxtool_serialize_array_add_string(originated_by, agent))
|
||
goto err;
|
||
|
||
if (!(spdxtool_serialize_object_add_string(object_list, "type", "software_Package") &&
|
||
spdxtool_serialize_object_add_string(object_list, "creationInfo", creation_info) &&
|
||
spdxtool_serialize_object_add_string(object_list, "spdxId", spdx_id) &&
|
||
spdxtool_serialize_object_add_string(object_list, "name", pkg->realname)))
|
||
{
|
||
goto err;
|
||
}
|
||
|
||
/* object_add_array always takes ownership of the array (it is freed even on
|
||
* failure), so clear our reference before checking the result to avoid a
|
||
* double free at the error label.
|
||
*/
|
||
bool ok = spdxtool_serialize_object_add_array(object_list, "originatedBy", originated_by);
|
||
originated_by = NULL;
|
||
if (!ok)
|
||
goto err;
|
||
|
||
supplier = spdxtool_util_tuple_lookup(client, &pkg->vars, "suppliedBy");
|
||
if (supplier && !spdxtool_serialize_object_add_string(object_list, "suppliedBy", supplier))
|
||
goto err;
|
||
|
||
if (!serialize_copyright_lines_to_object(object_list, &pkg->copyright))
|
||
goto err;
|
||
|
||
if (!spdxtool_serialize_object_add_string(object_list, "software_homePage",
|
||
pkg->url ? pkg->url : ""))
|
||
{
|
||
goto err;
|
||
}
|
||
|
||
if (!spdxtool_serialize_object_add_string(object_list, "software_downloadLocation",
|
||
pkg->source ? pkg->source : ""))
|
||
{
|
||
goto err;
|
||
}
|
||
|
||
if (!spdxtool_serialize_object_add_string(object_list, "software_packageVersion", pkg->version))
|
||
goto err;
|
||
|
||
PKGCONF_FOREACH_LIST_ENTRY(pkg->license.head, node)
|
||
{
|
||
const pkgconf_license_t *license = node->data;
|
||
if (license->type == PKGCONF_LICENSE_EXPRESSION)
|
||
{
|
||
spdx_id_license = spdxtool_util_get_spdx_id_string(client, "simplelicensing_LicenseExpression", license->data);
|
||
if (!spdx_id_license)
|
||
goto err;
|
||
|
||
if (!pkgconf_license_insert(client, &relations, PKGCONF_LICENSE_UNKNOWN, spdx_id_license))
|
||
goto err;
|
||
free(spdx_id_license);
|
||
spdx_id_license = NULL;
|
||
}
|
||
}
|
||
|
||
char *tuple_license = spdxtool_util_tuple_lookup(client, &pkg->vars, "hasDeclaredLicense");
|
||
if (tuple_license)
|
||
{
|
||
cpy_relations = calloc(1, sizeof(pkgconf_list_t));
|
||
if (!cpy_relations)
|
||
{
|
||
free(tuple_license);
|
||
goto err;
|
||
}
|
||
|
||
if (!pkgconf_license_copy_list(client, cpy_relations, &relations))
|
||
{
|
||
free(tuple_license);
|
||
goto err;
|
||
}
|
||
spdxtool_core_relationship_t *relationship = spdxtool_core_relationship_new(client, creation_info, tuple_license, spdx_id, cpy_relations, "hasDeclaredLicense");
|
||
free(tuple_license);
|
||
if (!relationship)
|
||
goto err;
|
||
cpy_relations = NULL;
|
||
if (!spdxtool_core_spdx_document_add_relationship(client, spdx, relationship))
|
||
{
|
||
spdxtool_core_relationship_free(relationship);
|
||
goto err;
|
||
}
|
||
}
|
||
|
||
tuple_license = spdxtool_util_tuple_lookup(client, &pkg->vars, "hasConcludedLicense");
|
||
if (tuple_license)
|
||
{
|
||
cpy_relations = calloc(1, sizeof(pkgconf_list_t));
|
||
if (!cpy_relations)
|
||
{
|
||
free(tuple_license);
|
||
goto err;
|
||
}
|
||
|
||
if (!pkgconf_license_copy_list(client, cpy_relations, &relations))
|
||
{
|
||
free(tuple_license);
|
||
goto err;
|
||
}
|
||
spdxtool_core_relationship_t *relationship = spdxtool_core_relationship_new(client, creation_info, tuple_license, spdx_id, cpy_relations, "hasConcludedLicense");
|
||
free(tuple_license);
|
||
if (!relationship)
|
||
goto err;
|
||
cpy_relations = NULL;
|
||
if (!spdxtool_core_spdx_document_add_relationship(client, spdx, relationship))
|
||
{
|
||
spdxtool_core_relationship_free(relationship);
|
||
goto err;
|
||
}
|
||
}
|
||
pkgconf_license_free(&relations);
|
||
|
||
PKGCONF_FOREACH_LIST_ENTRY(pkg->required.head, node)
|
||
{
|
||
pkgconf_dependency_t *dep = node->data;
|
||
pkgconf_pkg_t *match = dep->match;
|
||
|
||
/* an unresolved (but tolerated) dependency has no match */
|
||
if (match == NULL)
|
||
continue;
|
||
|
||
char *spdx_id_relation = relationship_spdx_id(client, pkg->id, match->id, sep);
|
||
if (!spdx_id_relation)
|
||
goto err;
|
||
|
||
char *spdx_id_package = spdxtool_util_get_spdx_id_string(client, "Package", match->id);
|
||
if (!spdx_id_package)
|
||
{
|
||
free(spdx_id_relation);
|
||
goto err;
|
||
}
|
||
|
||
cpy_relations = calloc(1, sizeof(pkgconf_list_t));
|
||
if (!cpy_relations)
|
||
{
|
||
free(spdx_id_relation);
|
||
free(spdx_id_package);
|
||
goto err;
|
||
}
|
||
|
||
if (!pkgconf_license_insert(client, cpy_relations, PKGCONF_LICENSE_UNKNOWN, spdx_id_package))
|
||
{
|
||
free(spdx_id_relation);
|
||
free(spdx_id_package);
|
||
goto err;
|
||
}
|
||
spdxtool_core_relationship_t *relationship = spdxtool_core_relationship_new(client, creation_info, spdx_id_relation, spdx_id, cpy_relations, "dependsOn");
|
||
free(spdx_id_relation);
|
||
free(spdx_id_package);
|
||
if (!relationship)
|
||
goto err;
|
||
cpy_relations = NULL;
|
||
if (!spdxtool_core_spdx_document_add_relationship(client, spdx, relationship))
|
||
{
|
||
spdxtool_core_relationship_free(relationship);
|
||
goto err;
|
||
}
|
||
}
|
||
|
||
PKGCONF_FOREACH_LIST_ENTRY(pkg->requires_private.head, node)
|
||
{
|
||
pkgconf_dependency_t *dep = node->data;
|
||
pkgconf_pkg_t *match = dep->match;
|
||
|
||
/* an unresolved (but tolerated) dependency has no match */
|
||
if (match == NULL)
|
||
continue;
|
||
|
||
char *spdx_id_relation = relationship_spdx_id(client, pkg->id, match->id, sep);
|
||
if (!spdx_id_relation)
|
||
goto err;
|
||
|
||
char *spdx_id_package = spdxtool_util_get_spdx_id_string(client, "Package", match->id);
|
||
if (!spdx_id_package)
|
||
{
|
||
free(spdx_id_relation);
|
||
goto err;
|
||
}
|
||
|
||
cpy_relations = calloc(1, sizeof(pkgconf_list_t));
|
||
if (!cpy_relations)
|
||
{
|
||
free(spdx_id_relation);
|
||
free(spdx_id_package);
|
||
goto err;
|
||
}
|
||
|
||
if (!pkgconf_license_insert(client, cpy_relations, PKGCONF_LICENSE_UNKNOWN, spdx_id_package))
|
||
{
|
||
free(spdx_id_relation);
|
||
free(spdx_id_package);
|
||
goto err;
|
||
}
|
||
spdxtool_core_relationship_t *relationship = spdxtool_core_relationship_new(client, creation_info, spdx_id_relation, spdx_id, cpy_relations, "dependsOn");
|
||
free(spdx_id_relation);
|
||
free(spdx_id_package);
|
||
if (!relationship)
|
||
goto err;
|
||
cpy_relations = NULL;
|
||
if (!spdxtool_core_relationship_set_scope(client, relationship, "development"))
|
||
{
|
||
spdxtool_core_relationship_free(relationship);
|
||
goto err;
|
||
}
|
||
if (!spdxtool_core_spdx_document_add_relationship(client, spdx, relationship))
|
||
{
|
||
spdxtool_core_relationship_free(relationship);
|
||
goto err;
|
||
}
|
||
}
|
||
|
||
ret = spdxtool_serialize_value_object(object_list);
|
||
object_list = NULL;
|
||
|
||
err:
|
||
if (!ret)
|
||
pkgconf_error(client, "spdxtool_software_package_to_object: out of memory");
|
||
|
||
free(creation_info);
|
||
free(spdx_id);
|
||
free(agent);
|
||
free(supplier);
|
||
free(spdx_id_license);
|
||
pkgconf_license_free(&relations);
|
||
if (cpy_relations != NULL)
|
||
{
|
||
pkgconf_license_free(cpy_relations);
|
||
free(cpy_relations);
|
||
}
|
||
spdxtool_serialize_object_list_free(object_list);
|
||
spdxtool_serialize_array_free(originated_by);
|
||
return ret;
|
||
}
|