#include <pakfire/pakfire.h>
#include <pakfire/key.h>
#include <pakfire/repo.h>
+#include <pakfire/snapshot.h>
#include <pakfire/util.h>
#include "errors.h"
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",
METH_VARARGS,
NULL,
},
+ {
+ "create_snapshot",
+ (PyCFunction)Pakfire_create_snapshot,
+ METH_VARARGS,
+ NULL,
+ },
{
"copy_in",
(PyCFunction)Pakfire_copy_in,
--- /dev/null
+/*#############################################################################
+# #
+# 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 */
--- /dev/null
+/*#############################################################################
+# #
+# 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;
+}