]> git.ipfire.org Git - pakfire.git/commitdiff
libpakfire: Add support for creating snapshots
authorMichael Tremer <michael.tremer@ipfire.org>
Mon, 22 Mar 2021 16:45:14 +0000 (16:45 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Mon, 22 Mar 2021 16:45:14 +0000 (16:45 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
Makefile.am
src/_pakfire/pakfire.c
src/libpakfire/include/pakfire/snapshot.h [new file with mode: 0644]
src/libpakfire/libpakfire.sym
src/libpakfire/snapshot.c [new file with mode: 0644]

index 3d20e4bad7e085d2cae409513dcd4aa367a22bc5..538ffc372b5f82ba896addbbe56768140c858b23 100644 (file)
@@ -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 \
index de46d02dee22f538b060c796c7bb6ec2d2ec66e4..92fba567ba53356606016dbe8493cfb5e299113e 100644 (file)
@@ -29,6 +29,7 @@
 #include <pakfire/pakfire.h>
 #include <pakfire/key.h>
 #include <pakfire/repo.h>
+#include <pakfire/snapshot.h>
 #include <pakfire/util.h>
 
 #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 (file)
index 0000000..f060d1d
--- /dev/null
@@ -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 <http://www.gnu.org/licenses/>.       #
+#                                                                             #
+#############################################################################*/
+
+#ifndef PAKFIRE_SNAPSHOT_H
+#define PAKFIRE_SNAPSHOT_H
+
+#include <stdio.h>
+
+#include <pakfire/types.h>
+
+int pakfire_snapshot_create(Pakfire pakfire, FILE* f);
+int pakfire_snapshot_restore(Pakfire pakfire, FILE* f);
+
+#endif /* PAKFIRE_SNAPSHOT_H */
index bdcbd6582b349ffa2730071f08026ba9dd2907f2..b638d067c8bf7d781afded4eab5ecdc16b2b65f4 100644 (file)
@@ -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 (file)
index 0000000..0e626ac
--- /dev/null
@@ -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 <http://www.gnu.org/licenses/>.       #
+#                                                                             #
+#############################################################################*/
+
+#include <errno.h>
+#include <stdio.h>
+
+#include <archive.h>
+
+#include <pakfire/file.h>
+#include <pakfire/filelist.h>
+#include <pakfire/logging.h>
+#include <pakfire/private.h>
+#include <pakfire/snapshot.h>
+#include <pakfire/types.h>
+
+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;
+}