From: Michael Tremer Date: Mon, 22 Mar 2021 16:45:14 +0000 (+0000) Subject: libpakfire: Add support for creating snapshots X-Git-Tag: 0.9.28~1285^2~487 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a3fa61f4caff9da3b6e890bd1a1bea1c976d2e57;p=pakfire.git libpakfire: Add support for creating snapshots Signed-off-by: Michael Tremer --- diff --git a/Makefile.am b/Makefile.am index 3d20e4bad..538ffc372 100644 --- a/Makefile.am +++ b/Makefile.am @@ -281,6 +281,7 @@ libpakfire_la_SOURCES = \ src/libpakfire/request.c \ src/libpakfire/scriptlet.c \ src/libpakfire/selector.c \ + src/libpakfire/snapshot.c \ src/libpakfire/solution.c \ src/libpakfire/step.c \ src/libpakfire/transaction.c \ @@ -316,6 +317,7 @@ pkginclude_HEADERS += \ src/libpakfire/include/pakfire/request.h \ src/libpakfire/include/pakfire/scriptlet.h \ src/libpakfire/include/pakfire/selector.h \ + src/libpakfire/include/pakfire/snapshot.h \ src/libpakfire/include/pakfire/solution.h \ src/libpakfire/include/pakfire/step.h \ src/libpakfire/include/pakfire/transaction.h \ diff --git a/src/_pakfire/pakfire.c b/src/_pakfire/pakfire.c index de46d02de..92fba567b 100644 --- a/src/_pakfire/pakfire.c +++ b/src/_pakfire/pakfire.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include "errors.h" @@ -742,6 +743,29 @@ static PyObject* Pakfire_copy_out(PakfireObject* self, PyObject* args) { Py_RETURN_NONE; } +static PyObject* Pakfire_create_snapshot(PakfireObject* self, PyObject* args) { + const char* path = NULL; + + if (!PyArg_ParseTuple(args, "s", &path)) + return NULL; + + FILE* f = fopen(path, "w"); + if (!f) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + + int r = pakfire_snapshot_create(self->pakfire, f); + fclose(f); + + if (r) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + + Py_RETURN_NONE; +} + static struct PyMethodDef Pakfire_methods[] = { { "bind", @@ -749,6 +773,12 @@ static struct PyMethodDef Pakfire_methods[] = { METH_VARARGS, NULL, }, + { + "create_snapshot", + (PyCFunction)Pakfire_create_snapshot, + METH_VARARGS, + NULL, + }, { "copy_in", (PyCFunction)Pakfire_copy_in, diff --git a/src/libpakfire/include/pakfire/snapshot.h b/src/libpakfire/include/pakfire/snapshot.h new file mode 100644 index 000000000..f060d1dcc --- /dev/null +++ b/src/libpakfire/include/pakfire/snapshot.h @@ -0,0 +1,31 @@ +/*############################################################################# +# # +# Pakfire - The IPFire package management system # +# Copyright (C) 2021 Pakfire development team # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see . # +# # +#############################################################################*/ + +#ifndef PAKFIRE_SNAPSHOT_H +#define PAKFIRE_SNAPSHOT_H + +#include + +#include + +int pakfire_snapshot_create(Pakfire pakfire, FILE* f); +int pakfire_snapshot_restore(Pakfire pakfire, FILE* f); + +#endif /* PAKFIRE_SNAPSHOT_H */ diff --git a/src/libpakfire/libpakfire.sym b/src/libpakfire/libpakfire.sym index bdcbd6582..b638d067c 100644 --- a/src/libpakfire/libpakfire.sym +++ b/src/libpakfire/libpakfire.sym @@ -372,6 +372,10 @@ global: pakfire_selector_set; pakfire_selector_unref; + # snapshot + pakfire_snapshot_create; + pakfire_snapshot_restore; + # solution pakfire_solution_create; pakfire_solution_next; diff --git a/src/libpakfire/snapshot.c b/src/libpakfire/snapshot.c new file mode 100644 index 000000000..0e626acf0 --- /dev/null +++ b/src/libpakfire/snapshot.c @@ -0,0 +1,172 @@ +/*############################################################################# +# # +# Pakfire - The IPFire package management system # +# Copyright (C) 2021 Pakfire development team # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see . # +# # +#############################################################################*/ + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +static const char* pakfire_snapshot_excludes[] = { + "/dev", + "/proc", + "/run", + "/sys", + "/var/cache/ccache", + "/var/tmp", + NULL, +}; + +static struct archive* pakfire_snapshot_create_archive(Pakfire pakfire, FILE* f) { + struct archive* a = archive_write_new(); + if (!a) { + ERROR(pakfire, "archive_write_new() failed\n"); + return NULL; + } + + // Use the PAX format + int r = archive_write_set_format_pax(a); + if (r) { + ERROR(pakfire, "Could not set format to PAX: %s\n", archive_error_string(a)); + goto ERROR; + } + + // Enable Zstd + r = archive_write_add_filter_zstd(a); + if (r) { + ERROR(pakfire, "Could not enable Zstandard compression: %s\n", + archive_error_string(a)); + goto ERROR; + } + + // Write archive to file + r = archive_write_open_FILE(a, f); + if (r) + goto ERROR; + + return a; + +ERROR: + archive_write_free(a); + + return NULL; +} + +PAKFIRE_EXPORT int pakfire_snapshot_create(Pakfire pakfire, FILE* f) { + char buffer[512 * 1024]; + const char* path = pakfire_get_path(pakfire); + + INFO(pakfire, "Creating snapshot of %s...\n", path); + + struct archive* a = pakfire_snapshot_create_archive(pakfire, f); + if (!a) { + ERROR(pakfire, "Could not open archive for writing\n"); + return 1; + } + + PakfireFilelist filelist = NULL; + int r = 1; + + r = pakfire_filelist_create(&filelist, pakfire); + if (r) + goto ERROR; + + // Search for files to package + r = pakfire_filelist_scan(filelist, path, NULL, pakfire_snapshot_excludes); + if (r) + goto ERROR; + + const size_t num_files = pakfire_filelist_size(filelist); + if (!num_files) { + ERROR(pakfire, "No files found for snapshot\n"); + goto ERROR; + } + + DEBUG(pakfire, "Found %zu file(s) to snapshot\n", num_files); + + for (unsigned int i = 0; i < num_files; i++) { + PakfireFile file = pakfire_filelist_get(filelist, i); + + struct archive_entry* entry = pakfire_file_archive_entry(file); + if (!entry) { + r = 1; + goto ERROR; + } + + // Write entry to archive + r = archive_write_header(a, entry); + if (r) { + ERROR(pakfire, "Could not write header for %s: %s\n", + pakfire_file_get_path(file), archive_error_string(a)); + pakfire_file_unref(file); + goto ERROR; + } + + // Write payload + if (archive_entry_filetype(entry) == AE_IFREG) { + f = pakfire_file_fopen(file, "r"); + if (!f) + goto ERROR; + + while (!feof(f)) { + size_t bytes_read = fread(buffer, 1, sizeof(buffer), f); + + // Check if any error occured + if (ferror(f)) { + ERROR(pakfire, "Error reading from file: %s\n", strerror(errno)); + fclose(f); + goto ERROR; + } + + ssize_t bytes_written = archive_write_data(a, buffer, bytes_read); + if (bytes_written < 0) { + ERROR(pakfire, "Error writing data: %s\n", archive_error_string(a)); + fclose(f); + goto ERROR; + } + } + + fclose(f); + } + + pakfire_file_unref(file); + } + + // Success + r = 0; + +ERROR: + if (filelist) + pakfire_filelist_unref(filelist); + + archive_write_free(a); + + return r; +} + +PAKFIRE_EXPORT int pakfire_snapshot_restore(Pakfire pakfire, FILE* f) { + return 0; +}