From 2810874a0284f9ca7e714fadf0e7d121bb52aa1b Mon Sep 17 00:00:00 2001 From: Michael Tremer Date: Mon, 22 Mar 2021 18:17:32 +0000 Subject: [PATCH] libpakfire: Implement restoring snapshots Signed-off-by: Michael Tremer --- src/_pakfire/pakfire.c | 29 ++++++++++++++ src/libpakfire/snapshot.c | 84 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 112 insertions(+), 1 deletion(-) diff --git a/src/_pakfire/pakfire.c b/src/_pakfire/pakfire.c index 92fba567b..88ef89f59 100644 --- a/src/_pakfire/pakfire.c +++ b/src/_pakfire/pakfire.c @@ -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, diff --git a/src/libpakfire/snapshot.c b/src/libpakfire/snapshot.c index 0e626acf0..73309a599 100644 --- a/src/libpakfire/snapshot.c +++ b/src/libpakfire/snapshot.c @@ -20,6 +20,7 @@ #include #include +#include #include @@ -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; } -- 2.47.2