From: Michael Tremer Date: Mon, 27 Nov 2017 13:12:50 +0000 (+0100) Subject: libpakfire: Make archive signatures an exportable object X-Git-Tag: 0.9.28~1285^2~1277 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b7600b1d84f91b0c05ca4409680a0e9ff73fb44f;p=pakfire.git libpakfire: Make archive signatures an exportable object Signed-off-by: Michael Tremer --- diff --git a/src/_pakfire/_pakfiremodule.c b/src/_pakfire/_pakfiremodule.c index 0af859b88..a10bb233c 100644 --- a/src/_pakfire/_pakfiremodule.c +++ b/src/_pakfire/_pakfiremodule.c @@ -142,6 +142,13 @@ PyMODINIT_FUNC PyInit__pakfire(void) { Py_INCREF(&ArchiveType); PyModule_AddObject(module, "Archive", (PyObject *)&ArchiveType); + // Archive Signature + if (PyType_Ready(&ArchiveSignatureType) < 0) + return NULL; + + Py_INCREF(&ArchiveSignatureType); + PyModule_AddObject(module, "ArchiveSignature", (PyObject *)&ArchiveSignatureType); + // Key if (PyType_Ready(&KeyType) < 0) return NULL; diff --git a/src/_pakfire/archive.c b/src/_pakfire/archive.c index 439c97f6f..f66d86bf3 100644 --- a/src/_pakfire/archive.c +++ b/src/_pakfire/archive.c @@ -38,7 +38,7 @@ static PyObject* Archive_new(PyTypeObject* type, PyObject* args, PyObject* kwds) static void Archive_dealloc(ArchiveObject* self) { if (self->archive) - pakfire_archive_free(self->archive); + pakfire_archive_unref(self->archive); Py_DECREF(self->pakfire); @@ -56,6 +56,7 @@ static int Archive_init(ArchiveObject* self, PyObject* args, PyObject* kwds) { Py_INCREF(self->pakfire); self->archive = pakfire_archive_open(self->pakfire->pakfire, filename); + assert(self->archive); return 0; } @@ -116,21 +117,18 @@ static PyObject* Archive_verify(ArchiveObject* self) { static PyObject* Archive_get_signatures(ArchiveObject* self) { PyObject* list = PyList_New(0); - char** head = pakfire_archive_get_signatures(self->archive); + PakfireArchiveSignature* head = pakfire_archive_get_signatures(self->archive); - char** signatures = head; - while (*signatures) { - char* signature = *signatures++; + PakfireArchiveSignature* signatures = head; + while (signatures && *signatures) { + PakfireArchiveSignature signature = *signatures++; - PyObject* object = PyUnicode_FromString(signature); + PyObject* object = new_archive_signature(self, signature); PyList_Append(list, object); Py_DECREF(object); - pakfire_free(signature); } - pakfire_free(head); - return list; } @@ -184,3 +182,51 @@ PyTypeObject ArchiveType = { //tp_str: (reprfunc)Archive_str, //tp_richcompare: (richcmpfunc)Archive_richcompare, }; + +// Archive Signature + +static PyObject* ArchiveSignature_new(PyTypeObject* type, PyObject* args, PyObject* kwds) { + ArchiveSignatureObject* self = (ArchiveSignatureObject *)type->tp_alloc(type, 0); + if (self) { + self->signature = NULL; + } + + return (PyObject *)self; +} + +PyObject* new_archive_signature(ArchiveObject* archive, PakfireArchiveSignature signature) { + ArchiveSignatureObject* s = (ArchiveSignatureObject*)ArchiveSignature_new(&ArchiveSignatureType, NULL, NULL); + if (s) + s->signature = pakfire_archive_signature_ref(signature); + + return (PyObject *)s; +} + +static void ArchiveSignature_dealloc(ArchiveSignatureObject* self) { + if (self->signature) + pakfire_archive_signature_unref(self->signature); + + Py_TYPE(self)->tp_free((PyObject *)self); +} + +static PyObject* ArchiveSignature_str(ArchiveSignatureObject* self) { + const char* data = pakfire_archive_signature_get_data(self->signature); + + return PyUnicode_FromString(data); +} + +static struct PyGetSetDef ArchiveSignature_getsetters[] = { + { NULL }, +}; + +PyTypeObject ArchiveSignatureType = { + PyVarObject_HEAD_INIT(NULL, 0) + tp_name: "_pakfire.ArchiveSignature", + tp_basicsize: sizeof(ArchiveSignatureObject), + tp_flags: Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, + tp_new: ArchiveSignature_new, + tp_dealloc: (destructor)ArchiveSignature_dealloc, + tp_doc: "ArchiveSignature object", + tp_getset: ArchiveSignature_getsetters, + tp_str: (reprfunc)ArchiveSignature_str, +}; diff --git a/src/_pakfire/archive.h b/src/_pakfire/archive.h index 0630627c2..89cca394f 100644 --- a/src/_pakfire/archive.h +++ b/src/_pakfire/archive.h @@ -35,4 +35,13 @@ typedef struct { extern PyTypeObject ArchiveType; +typedef struct { + PyObject_HEAD + PakfireArchiveSignature signature; +} ArchiveSignatureObject; + +extern PyTypeObject ArchiveSignatureType; + +PyObject* new_archive_signature(ArchiveObject* archive, PakfireArchiveSignature signature); + #endif /* PYTHON_PAKFIRE_ARCHIVE_H */ diff --git a/src/libpakfire/archive.c b/src/libpakfire/archive.c index d97c36ccf..a89b7654e 100644 --- a/src/libpakfire/archive.c +++ b/src/libpakfire/archive.c @@ -167,24 +167,40 @@ static archive_checksum_t* pakfire_archive_checksum_find(PakfireArchive archive, return NULL; } -static archive_signature_t* pakfire_archive_signature_create(const char* sigdata) { - archive_signature_t* s = pakfire_calloc(1, sizeof(*s)); - if (s) { - s->sigdata = pakfire_strdup(sigdata); +static PakfireArchiveSignature pakfire_archive_signature_create(PakfireArchive archive, const char* sigdata) { + PakfireArchiveSignature signature = pakfire_calloc(1, sizeof(*signature)); + if (signature) { + signature->nrefs = 1; + signature->sigdata = pakfire_strdup(sigdata); } - return s; + return signature; } -static void pakfire_archive_signature_free(archive_signature_t* s) { - pakfire_free(s->sigdata); - pakfire_free(s); +static void pakfire_archive_signature_free(PakfireArchiveSignature signature) { + if (signature->key) + pakfire_key_unref(signature->key); + + pakfire_free(signature->sigdata); + pakfire_free(signature); } -size_t pakfire_archive_count_signatures(PakfireArchive archive) { +PakfireArchiveSignature pakfire_archive_signature_ref(PakfireArchiveSignature signature) { + ++signature->nrefs; + + return signature; +} + +void pakfire_archive_signature_unref(PakfireArchiveSignature signature) { + if (--signature->nrefs > 0) + return; + + pakfire_archive_signature_free(signature); +} + +size_t _pakfire_archive_count_signatures(const PakfireArchiveSignature* signatures) { size_t i = 0; - archive_signature_t** signatures = archive->signatures; while (signatures && *signatures++) { i++; } @@ -192,9 +208,16 @@ size_t pakfire_archive_count_signatures(PakfireArchive archive) { return i; } +size_t pakfire_archive_count_signatures(PakfireArchive archive) { + PakfireArchiveSignature* signatures = pakfire_archive_get_signatures(archive); + + return _pakfire_archive_count_signatures(signatures); +} + PakfireArchive pakfire_archive_create(Pakfire pakfire) { PakfireArchive archive = pakfire_calloc(1, sizeof(*archive)); if (archive) { + archive->nrefs = 1; archive->pakfire = pakfire_ref(pakfire); archive->format = -1; @@ -204,7 +227,13 @@ PakfireArchive pakfire_archive_create(Pakfire pakfire) { return archive; } -void pakfire_archive_free(PakfireArchive archive) { +PakfireArchive pakfire_archive_ref(PakfireArchive archive) { + ++archive->nrefs; + + return archive; +} + +static void pakfire_archive_free(PakfireArchive archive) { if (archive->path) pakfire_free(archive->path); @@ -214,14 +243,25 @@ void pakfire_archive_free(PakfireArchive archive) { pakfire_archive_checksum_free(*checksums++); // Free signatures - archive_signature_t** signatures = archive->signatures; - while (signatures && *signatures) - pakfire_archive_signature_free(*signatures++); + if (archive->signatures) { + PakfireArchiveSignature* signatures = archive->signatures; + while (signatures && *signatures) + pakfire_archive_signature_unref(*signatures++); + + pakfire_free(archive->signatures); + } pakfire_unref(archive->pakfire); pakfire_free(archive); } +void pakfire_archive_unref(PakfireArchive archive) { + if (--archive->nrefs > 0) + return; + + pakfire_archive_free(archive); +} + static int pakfire_archive_parse_entry_format(PakfireArchive archive, struct archive* a, struct archive_entry* e) { char format[PAKFIRE_ARCHIVE_FORMAT_SIZE + 1]; @@ -339,100 +379,80 @@ static int pakfire_archive_parse_entry_checksums(PakfireArchive archive, return 0; } -static int pakfire_archive_parse_entry_signature(PakfireArchive archive, - struct archive* a, struct archive_entry* e) { - char* data; - size_t data_size; +static int pakfire_archive_walk(PakfireArchive archive, + int (*callback)(PakfireArchive archive, struct archive* a, struct archive_entry* e, const char* pathname)) { + struct archive_entry* e; + int r = 0; - int r = archive_read(a, (void**)&data, &data_size); + // Open the archive file + struct archive* a; + r = archive_open(archive, &a); if (r) - return 1; - - // Terminate string. - data[data_size] = '\0'; + return r; - archive_signature_t* signature = pakfire_archive_signature_create(data); - if (!signature) - return 1; - - if (archive->signatures) { - // Count signatures - size_t num_signatures = pakfire_archive_count_signatures(archive) + 1; - - // Resize the array - archive->signatures = pakfire_realloc(archive->signatures, sizeof(*archive->signatures) * num_signatures); - } else { - archive->signatures = pakfire_calloc(2, sizeof(*archive->signatures)); - } + // Walk through the archive + int ret; + while ((ret = archive_read_next_header(a, &e)) == ARCHIVE_OK) { + const char* pathname = archive_entry_pathname(e); - // Look for last element - archive_signature_t** signatures = archive->signatures; - while (*signatures) { - *signatures++; + r = callback(archive, a, e, pathname); + if (r) + break; } - // Append signature - *signatures++ = signature; - - // Terminate list - *signatures = NULL; + // Close the archive again + archive_close(a); - return 0; + return r; } -static int pakfire_archive_read_metadata(PakfireArchive archive, struct archive* a) { +static int pakfire_archive_read_metadata_entry(PakfireArchive archive, struct archive* a, + struct archive_entry* e, const char* entry_name) { int ret; - struct archive_entry* entry; - while ((ret = archive_read_next_header(a, &entry)) == ARCHIVE_OK) { - const char* entry_name = archive_entry_pathname(entry); - - /* The first file in a pakfire package file must be - * the pakfire-format file, so we know with what version of - * the package format we are dealing with. - */ - if (archive->format < 0) { - if (strcmp(PAKFIRE_ARCHIVE_FN_FORMAT, entry_name) == 0) { - ret = pakfire_archive_parse_entry_format(archive, a, entry); - if (ret) - return PAKFIRE_E_PKG_INVALID; - - } else { + /* The first file in a pakfire package file must be + * the pakfire-format file, so we know with what version of + * the package format we are dealing with. + */ + if (archive->format < 0) { + if (strcmp(PAKFIRE_ARCHIVE_FN_FORMAT, entry_name) == 0) { + ret = pakfire_archive_parse_entry_format(archive, a, e); + if (ret) return PAKFIRE_E_PKG_INVALID; - } - // If the format is set, we can go on... } else { - // Parse the metadata - if (strcmp(PAKFIRE_ARCHIVE_FN_METADATA, entry_name) == 0) { - ret = pakfire_archive_parse_entry_metadata(archive, a, entry); - if (ret) - return PAKFIRE_E_PKG_INVALID; - - // Parse the filelist - } else if (strcmp(PAKFIRE_ARCHIVE_FN_FILELIST, entry_name) == 0) { - ret = pakfire_archive_parse_entry_filelist(archive, a, entry); - if (ret) - return PAKFIRE_E_PKG_INVALID; - - // Parse the checksums - } else if (strcmp(PAKFIRE_ARCHIVE_FN_CHECKSUMS, entry_name) == 0) { - ret = pakfire_archive_parse_entry_checksums(archive, a, entry); - if (ret) - return PAKFIRE_E_PKG_INVALID; - - // Parse signatures - } else if (strncmp(PAKFIRE_ARCHIVE_FN_SIGNATURES, entry_name, strlen(PAKFIRE_ARCHIVE_FN_SIGNATURES)) == 0) { - ret = pakfire_archive_parse_entry_signature(archive, a, entry); - if (ret) - return PAKFIRE_E_PKG_INVALID; - } + return PAKFIRE_E_PKG_INVALID; + } + + // If the format is set, we can go on... + } else { + // Parse the metadata + if (strcmp(PAKFIRE_ARCHIVE_FN_METADATA, entry_name) == 0) { + ret = pakfire_archive_parse_entry_metadata(archive, a, e); + if (ret) + return PAKFIRE_E_PKG_INVALID; + + // Parse the filelist + } else if (strcmp(PAKFIRE_ARCHIVE_FN_FILELIST, entry_name) == 0) { + ret = pakfire_archive_parse_entry_filelist(archive, a, e); + if (ret) + return PAKFIRE_E_PKG_INVALID; + + // Parse the checksums + } else if (strcmp(PAKFIRE_ARCHIVE_FN_CHECKSUMS, entry_name) == 0) { + ret = pakfire_archive_parse_entry_checksums(archive, a, e); + if (ret) + return PAKFIRE_E_PKG_INVALID; } } return 0; } +static int pakfire_archive_read_metadata(PakfireArchive archive, struct archive* a) { + return pakfire_archive_walk(archive, pakfire_archive_read_metadata_entry); +} + static int archive_copy_data(struct archive* in, struct archive* out) { int r; const void* buff; @@ -658,32 +678,77 @@ PakfireFile pakfire_archive_get_filelist(PakfireArchive archive) { return archive->filelist; } -char** pakfire_archive_get_signatures(PakfireArchive archive) { - size_t size = pakfire_archive_count_signatures(archive); +const char* pakfire_archive_signature_get_data(PakfireArchiveSignature signature) { + return signature->sigdata; +} - char** head = pakfire_calloc(size, sizeof(*head)); - if (!head) - return NULL; +static int pakfire_archive_parse_entry_signature(PakfireArchive archive, + struct archive* a, struct archive_entry* e) { + char* data; + size_t data_size; - char** list = head; - archive_signature_t** signatures = archive->signatures; - while (signatures && *signatures) { - archive_signature_t* signature = *signatures++; + int r = archive_read(a, (void**)&data, &data_size); + if (r) + return 1; + + // Terminate string. + data[data_size] = '\0'; + + PakfireArchiveSignature signature = pakfire_archive_signature_create(archive, data); + if (!signature) + return 1; + + if (archive->signatures) { + // Count signatures + size_t num_signatures = _pakfire_archive_count_signatures(archive->signatures) + 1; - *list++ = pakfire_strdup(signature->sigdata); + // Resize the array + archive->signatures = pakfire_realloc(archive->signatures, sizeof(*archive->signatures) * num_signatures); + } else { + archive->signatures = pakfire_calloc(2, sizeof(*archive->signatures)); } + // Look for last element + PakfireArchiveSignature* signatures = archive->signatures; + while (signatures && *signatures) { + *signatures++; + } + + // Append signature + *signatures++ = signature; + // Terminate list - *list = NULL; + *signatures = NULL; + + return 0; +} + +static int pakfire_archive_read_signature_entry(PakfireArchive archive, struct archive* a, struct archive_entry* e, const char* entry_name) { + if (strncmp(PAKFIRE_ARCHIVE_FN_SIGNATURES, entry_name, strlen(PAKFIRE_ARCHIVE_FN_SIGNATURES)) == 0) { + int ret = pakfire_archive_parse_entry_signature(archive, a, e); + if (ret) + return PAKFIRE_E_PKG_INVALID; + } + + return 0; +} + +static int pakfire_archive_load_signatures(PakfireArchive archive) { + return pakfire_archive_walk(archive, pakfire_archive_read_signature_entry); +} + +PakfireArchiveSignature* pakfire_archive_get_signatures(PakfireArchive archive) { + if (!archive->signatures_loaded++) + pakfire_archive_load_signatures(archive); - return head; + return archive->signatures; } static pakfire_archive_verify_status_t pakfire_archive_verify_checksums(PakfireArchive archive) { pakfire_archive_verify_status_t status = PAKFIRE_ARCHIVE_VERIFY_INVALID; // Cannot validate anything if no signatures are available - archive_signature_t** signatures = archive->signatures; + PakfireArchiveSignature* signatures = pakfire_archive_get_signatures(archive); if (!signatures) return PAKFIRE_ARCHIVE_VERIFY_OK; @@ -708,7 +773,7 @@ static pakfire_archive_verify_status_t pakfire_archive_verify_checksums(PakfireA // Try for each signature while (signatures && *signatures) { - archive_signature_t* signature = *signatures++; + PakfireArchiveSignature signature = *signatures++; gpgme_data_t sigdata; error = gpgme_data_new_from_mem(&sigdata, signature->sigdata, strlen(signature->sigdata), 0); diff --git a/src/libpakfire/include/pakfire/archive.h b/src/libpakfire/include/pakfire/archive.h index 48b10c1df..90c31a985 100644 --- a/src/libpakfire/include/pakfire/archive.h +++ b/src/libpakfire/include/pakfire/archive.h @@ -35,7 +35,8 @@ typedef enum pakfire_archive_verify_status { } pakfire_archive_verify_status_t; PakfireArchive pakfire_archive_create(Pakfire pakfire); -void pakfire_archive_free(PakfireArchive archive); +PakfireArchive pakfire_archive_ref(PakfireArchive archive); +void pakfire_archive_unref(PakfireArchive archive); PakfireArchive pakfire_archive_open(Pakfire pakfire, const char* path); @@ -49,12 +50,16 @@ unsigned int pakfire_archive_get_format(PakfireArchive archive); PakfireFile pakfire_archive_get_filelist(PakfireArchive archive); -size_t pakfire_archive_count_signatures(PakfireArchive archive); -char** pakfire_archive_get_signatures(PakfireArchive archive); - pakfire_archive_verify_status_t pakfire_archive_verify(PakfireArchive archive); const char* pakfire_archive_verify_strerror(pakfire_archive_verify_status_t status); +size_t pakfire_archive_count_signatures(PakfireArchive archive); +PakfireArchiveSignature* pakfire_archive_get_signatures(PakfireArchive archive); + +PakfireArchiveSignature pakfire_archive_signature_ref(PakfireArchiveSignature signature); +void pakfire_archive_signature_unref(PakfireArchiveSignature signature); +const char* pakfire_archive_signature_get_data(PakfireArchiveSignature signature); + enum pakfire_archive_flags { PAKFIRE_ARCHIVE_USE_PAYLOAD = 1 << 0, }; @@ -82,10 +87,6 @@ typedef struct archive_checksum { archive_checksum_algo_t algo; } archive_checksum_t; -typedef struct archive_signature { - char* sigdata; -} archive_signature_t; - struct _PakfireArchive { Pakfire pakfire; char* path; @@ -95,7 +96,18 @@ struct _PakfireArchive { PakfireFile filelist; archive_checksum_t** checksums; - archive_signature_t** signatures; + + // Signatures + PakfireArchiveSignature* signatures; + int signatures_loaded; + + int nrefs; +}; + +struct _PakfireArchiveSignature { + PakfireKey key; + char* sigdata; + int nrefs; }; struct payload_archive_data { diff --git a/src/libpakfire/include/pakfire/types.h b/src/libpakfire/include/pakfire/types.h index 300b8567b..2899ff2c6 100644 --- a/src/libpakfire/include/pakfire/types.h +++ b/src/libpakfire/include/pakfire/types.h @@ -23,6 +23,7 @@ typedef struct _Pakfire* Pakfire; typedef struct _PakfireArchive* PakfireArchive; +typedef struct _PakfireArchiveSignature* PakfireArchiveSignature; typedef struct _PakfireCache* PakfireCache; typedef struct _PakfireFile* PakfireFile; typedef struct _PakfireFilter* PakfireFilter; diff --git a/src/libpakfire/libpakfire.sym b/src/libpakfire/libpakfire.sym index 460b5f656..c34cf108f 100644 --- a/src/libpakfire/libpakfire.sym +++ b/src/libpakfire/libpakfire.sym @@ -32,16 +32,22 @@ global: pakfire_archive_count_signatures; pakfire_archive_create; pakfire_archive_extract; - pakfire_archive_free; pakfire_archive_get_filelist; pakfire_archive_get_format; pakfire_archive_get_path; pakfire_archive_get_signatures; pakfire_archive_open; pakfire_archive_read; + pakfire_archive_ref; + pakfire_archive_unref; pakfire_archive_verify; pakfire_archive_verify_strerror; + # archive signature + pakfire_archive_signature_get_data; + pakfire_archive_signature_ref; + pakfire_archive_signature_unref; + # file pakfire_file_append; pakfire_file_cmp;