]> git.ipfire.org Git - pakfire.git/commitdiff
archive: Implement extracting archives into arbitrary locations
authorMichael Tremer <michael.tremer@ipfire.org>
Thu, 25 May 2023 10:27:09 +0000 (10:27 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Thu, 25 May 2023 10:27:09 +0000 (10:27 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/_pakfire/archive.c
src/libpakfire/archive.c
src/libpakfire/compress.c
src/libpakfire/include/pakfire/archive.h
src/libpakfire/snapshot.c
src/libpakfire/transaction.c
src/scripts/pakfire-builder.in

index 5c70ec749ebfc5d3561b049b6a5729e8c9c5b855..73cdd080bac0917fadf46ff497d75904c5d45422 100644 (file)
@@ -136,9 +136,16 @@ static PyObject* Archive_verify(ArchiveObject* self) {
                Py_RETURN_FALSE;
 }
 
-static PyObject* Archive_extract(ArchiveObject* self) {
+static PyObject* Archive_extract(ArchiveObject* self, PyObject* args, PyObject* kwargs) {
+       char* kwlist[] = { "path", NULL };
+       const char* path = NULL;
+       const int flags = 0;
+
+       if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|z", kwlist, &path))
+               return NULL;
+
        // Extract payload
-       int r = pakfire_archive_extract(self->archive);
+       int r = pakfire_archive_extract(self->archive, path, flags);
        if (r) {
                PyErr_SetFromErrno(PyExc_OSError);
                return NULL;
@@ -211,7 +218,7 @@ static struct PyMethodDef Archive_methods[] = {
        {
                "extract",
                (PyCFunction)Archive_extract,
-               METH_NOARGS,
+               METH_VARARGS|METH_KEYWORDS,
                NULL
        },
        {
index 880c21707bba1cb56393681f412b5cd6485b14d9..a5a91ac68845dbf6d891ba8a08b78baf7a7e0b9f 100644 (file)
@@ -810,7 +810,8 @@ int pakfire_archive_link_or_copy(struct pakfire_archive* archive, const char* pa
        return r;
 }
 
-static int __pakfire_archive_extract(struct pakfire_archive* archive, int flags) {
+static int __pakfire_archive_extract(struct pakfire_archive* archive,
+               const char* path, int flags) {
        struct pakfire_filelist* filelist = NULL;
        struct pakfire_package* pkg = NULL;
        struct archive* a = NULL;
@@ -827,9 +828,21 @@ static int __pakfire_archive_extract(struct pakfire_archive* archive, int flags)
 
        DEBUG(archive->pakfire, "Extracting %s\n", archive->path);
 
+       // Copy everything to path if set
+       if (path) {
+               r = pakfire_string_set(prefix, path);
+               if (r)
+                       goto ERROR;
+
        // Set prefix for source packages
-       if (pakfire_package_is_source(pkg)) {
-               r = pakfire_string_format(prefix, "/usr/src/packages/%s", nevra);
+       } else if (pakfire_package_is_source(pkg)) {
+               r = pakfire_path(archive->pakfire, prefix, "/usr/src/packages/%s", nevra);
+               if (r)
+                       goto ERROR;
+
+       // Otherwise extract relative to the pakfire root
+       } else {
+               r = pakfire_path(archive->pakfire, prefix, "%s", "/");
                if (r)
                        goto ERROR;
        }
@@ -869,8 +882,9 @@ ERROR:
        return r;
 }
 
-PAKFIRE_EXPORT int pakfire_archive_extract(struct pakfire_archive* archive) {
-       return __pakfire_archive_extract(archive, 0);
+PAKFIRE_EXPORT int pakfire_archive_extract(struct pakfire_archive* archive,
+               const char* path, const int flags) {
+       return __pakfire_archive_extract(archive, path, flags);
 }
 
 PAKFIRE_EXPORT const char* pakfire_archive_get_path(struct pakfire_archive* archive) {
@@ -883,7 +897,7 @@ PAKFIRE_EXPORT unsigned int pakfire_archive_get_format(struct pakfire_archive* a
 
 static int pakfire_archive_load_filelist(struct pakfire_archive* archive) {
        // Perform a dry-run extraction
-       return __pakfire_archive_extract(archive,
+       return __pakfire_archive_extract(archive, NULL,
                PAKFIRE_EXTRACT_DRY_RUN|PAKFIRE_EXTRACT_NO_PROGRESS);
 }
 
index c25613837d45311d275b3f24d07130ae8c561cc9..d17da9df11e3d6865d8fdc7273c4778d24b81f36 100644 (file)
@@ -623,7 +623,7 @@ struct pakfire_extract {
        struct pakfire_filelist* filelist;
 
        // Prepend this prefix
-       char prefix[PATH_MAX];
+       const char* prefix;
 
        // The writer
        struct archive* writer;
@@ -806,14 +806,15 @@ int pakfire_extract(struct pakfire* pakfire, struct archive* archive,
                pakfire_walk_filter_callback filter_callback, int flags) {
        int r = 1;
 
-       // Use an empty string if no prefix set
+       // Use / if no prefix is set
        if (!prefix)
-               prefix = "";
+               prefix = "/";
 
        struct pakfire_extract data = {
                .pakfire  = pakfire,
                .archive  = archive,
                .filelist = filelist,
+               .prefix   = prefix,
                .flags    = flags,
                .writer   = NULL,
        };
@@ -824,11 +825,6 @@ int pakfire_extract(struct pakfire* pakfire, struct archive* archive,
        // Should we show a progress bar?
        const int no_progress = flags & PAKFIRE_EXTRACT_NO_PROGRESS;
 
-       // Set prefix (including pakfire path)
-       r = pakfire_path(pakfire, data.prefix, "%s", prefix);
-       if (r)
-               goto ERROR;
-
        // Allocate writer
        if (!dry_run) {
                data.writer = pakfire_make_archive_disk_writer(pakfire, 1);
index 9a15e0aae41186ff34f23787098e52eba0c2171d..aa4c674ae3ca15aebcf0f7299f8da9a1a63a9fed 100644 (file)
@@ -36,7 +36,8 @@ struct pakfire_archive* pakfire_archive_ref(struct pakfire_archive* archive);
 struct pakfire_archive* pakfire_archive_unref(struct pakfire_archive* archive);
 
 FILE* pakfire_archive_read(struct pakfire_archive* archive, const char* filename);
-int pakfire_archive_extract(struct pakfire_archive* archive);
+int pakfire_archive_extract(struct pakfire_archive* archive,
+       const char* path, const int flags);
 
 const char* pakfire_archive_get_path(struct pakfire_archive* archive);
 
index 30a1995e4bc49cb614135ca100dae078a8587dda..22bc34d78be59b04de075bcf97c94779d39fda36 100644 (file)
@@ -178,6 +178,8 @@ int pakfire_snapshot_extract(struct pakfire* pakfire, FILE* f) {
                return 1;
        }
 
+       const char* path = pakfire_get_path(pakfire);
+
        struct archive* archive = archive_read_new();
        if (!archive)
                return 1;
@@ -196,7 +198,7 @@ int pakfire_snapshot_extract(struct pakfire* pakfire, FILE* f) {
        }
 
        // Extract snapshot
-       r = pakfire_extract(pakfire, archive, st.st_size, NULL, NULL,
+       r = pakfire_extract(pakfire, archive, st.st_size, NULL, path,
                        _("Restoring Snapshot"), NULL, PAKFIRE_EXTRACT_SHOW_THROUGHPUT);
        if (r)
                goto ERROR;
index 6852259fcee546592676b5250231772bc1a94273..ff5d1f53e194ef77ea4dc7908f2b400d8a1a91b5 100644 (file)
@@ -718,7 +718,7 @@ static int pakfire_transaction_extract(struct pakfire_transaction* transaction,
        pakfire_transaction_status(transaction, _("Installing %s..."), nevra);
 
        // Extract payload
-       int r = pakfire_archive_extract(archive);
+       int r = pakfire_archive_extract(archive, NULL, 0);
        if (r) {
                ERROR(transaction->pakfire, "Could not extract package %s: %m\n",
                        nevra);
index 88113db384b600ff853b963b817d38dc65f63fc3..8740512e8b0b1cd3da0896ea6fdd5b40fd2a009b 100644 (file)
@@ -84,6 +84,12 @@ class Cli(object):
                dist.add_argument("--resultdir", nargs="?",
                        help=_("Path were the output files should be copied to"))
 
+               # extract
+               extract = subparsers.add_parser("extract", help=_("Extract an archive"))
+               extract.add_argument("archive", nargs=1, help=_("The path to the archive"))
+               extract.add_argument("--path", help=_("Extract the archive into this path"))
+               extract.set_defaults(func=self._extract)
+
                # info
                info = subparsers.add_parser("info",
                        help=_("Print some information about the given package(s)"))
@@ -259,6 +265,16 @@ class Cli(object):
                for pkg in pkgs:
                        p.dist(pkg, resultdir)
 
+       def _extract(self, ns):
+               # Launch Pakfire
+               p = self.pakfire(ns)
+
+               # Open the archive
+               archive = p.open(ns.archive[0])
+
+               # Extract the payload
+               archive.extract(path=ns.path)
+
        # Some common functions
 
        def _print_packages(self, packages, unique=True, long=True, **kwargs):