]> git.ipfire.org Git - pakfire.git/commitdiff
libpakfire: Implement restoring snapshots
authorMichael Tremer <michael.tremer@ipfire.org>
Mon, 22 Mar 2021 18:17:32 +0000 (18:17 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Mon, 22 Mar 2021 18:18:04 +0000 (18:18 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/_pakfire/pakfire.c
src/libpakfire/snapshot.c

index 92fba567ba53356606016dbe8493cfb5e299113e..88ef89f59e06160ee66b535250025543968c1469 100644 (file)
@@ -766,6 +766,29 @@ static PyObject* Pakfire_create_snapshot(PakfireObject* self, PyObject* args) {
        Py_RETURN_NONE;
 }
 
+static PyObject* Pakfire_restore_snapshot(PakfireObject* self, PyObject* args) {
+       const char* path = NULL;
+
+       if (!PyArg_ParseTuple(args, "s", &path))
+               return NULL;
+
+       FILE* f = fopen(path, "r");
+       if (!f) {
+               PyErr_SetFromErrno(PyExc_OSError);
+               return NULL;
+       }
+
+       int r = pakfire_snapshot_restore(self->pakfire, f);
+       fclose(f);
+
+       if (r) {
+               PyErr_SetFromErrno(PyExc_OSError);
+               return NULL;
+       }
+
+       Py_RETURN_NONE;
+}
+
 static struct PyMethodDef Pakfire_methods[] = {
        {
                "bind",
@@ -851,6 +874,12 @@ static struct PyMethodDef Pakfire_methods[] = {
                METH_VARARGS,
                NULL
        },
+       {
+               "restore_snapshot",
+               (PyCFunction)Pakfire_restore_snapshot,
+               METH_VARARGS,
+               NULL,
+       },
        {
                "version_compare",
                (PyCFunction)Pakfire_version_compare,
index 0e626acf0209013f236e9bf3c18e62f39131564d..73309a5991c3b48f03f77d20063d142e3dae2a06 100644 (file)
@@ -20,6 +20,7 @@
 
 #include <errno.h>
 #include <stdio.h>
+#include <stdlib.h>
 
 #include <archive.h>
 
@@ -155,6 +156,13 @@ PAKFIRE_EXPORT int pakfire_snapshot_create(Pakfire pakfire, FILE* f) {
                pakfire_file_unref(file);
        }
 
+       // Close archive
+       r = archive_write_close(a);
+       if (r) {
+               ERROR(pakfire, "Could not close archive: %s\n", archive_error_string(a));
+               goto ERROR;
+       }
+
        // Success
        r = 0;
 
@@ -168,5 +176,79 @@ ERROR:
 }
 
 PAKFIRE_EXPORT int pakfire_snapshot_restore(Pakfire pakfire, FILE* f) {
-       return 0;
+       int r = 1;
+
+       struct archive* a = archive_read_new();
+       if (!a)
+               return 1;
+
+       // All snapshots are tarballs
+       archive_read_support_format_tar(a);
+
+       // And they are compressed using ZSTD
+       archive_read_support_filter_zstd(a);
+
+       struct archive* disk = archive_write_disk_new();
+       if (!disk)
+               goto ERROR;
+
+       // Set flags for extracting contents
+       const int flags =
+               ARCHIVE_EXTRACT_ACL |
+               ARCHIVE_EXTRACT_OWNER |
+               ARCHIVE_EXTRACT_PERM |
+               ARCHIVE_EXTRACT_SPARSE |
+               ARCHIVE_EXTRACT_TIME |
+               ARCHIVE_EXTRACT_UNLINK |
+               ARCHIVE_EXTRACT_XATTR;
+
+       archive_write_disk_set_options(disk, flags);
+
+       // Open the given file for reading
+       r = archive_read_open_FILE(a, f);
+       if (r) {
+               ERROR(pakfire, "Could not open archive: %s\n", archive_error_string(a));
+               goto ERROR;
+       }
+
+       struct archive_entry* e = NULL;
+       while (1) {
+               r = archive_read_next_header(a, &e);
+               if (r == ARCHIVE_EOF)
+                       break;
+               else if (r) {
+                       ERROR(pakfire, "Could not read header: %s\n", archive_error_string(a));
+                       goto ERROR;
+               }
+
+               const char* path = archive_entry_pathname(e);
+
+               DEBUG(pakfire, "Extracting %s...\n", path);
+
+               // Update path
+               char* sourcepath = pakfire_make_path(pakfire, path);
+               if (!sourcepath)
+                       goto ERROR;
+
+               archive_entry_set_pathname(e, sourcepath);
+               free(sourcepath);
+
+               // Extract the file
+               r = archive_read_extract2(a, e, disk);
+               if (r) {
+                       ERROR(pakfire, "Could not extract %s: %s\n",
+                               archive_entry_pathname(e), archive_error_string(a));
+                       goto ERROR;
+               }
+       }
+
+       // Success
+       r = 0;
+
+ERROR:
+       if (disk)
+               archive_write_free(disk);
+       archive_read_free(a);
+
+       return r;
 }