]> git.ipfire.org Git - people/stevee/pakfire.git/commitdiff
transaction: Actually erase files from disk when removing a package
authorMichael Tremer <michael.tremer@ipfire.org>
Wed, 23 Jun 2021 17:31:24 +0000 (17:31 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Wed, 23 Jun 2021 17:31:24 +0000 (17:31 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/libpakfire/db.c
src/libpakfire/file.c
src/libpakfire/include/pakfire/db.h
src/libpakfire/include/pakfire/file.h
src/libpakfire/include/pakfire/package.h
src/libpakfire/package.c
src/libpakfire/transaction.c

index e717886634686a5c0fb64b38f5bcdbea60af6fab..fb75b3d883948a4a6c5c005aa58d005b2da448de 100644 (file)
@@ -29,6 +29,7 @@
 #include <pakfire/archive.h>
 #include <pakfire/db.h>
 #include <pakfire/file.h>
+#include <pakfire/filelist.h>
 #include <pakfire/logging.h>
 #include <pakfire/package.h>
 #include <pakfire/pakfire.h>
@@ -1388,91 +1389,96 @@ static int pakfire_db_load_package(struct pakfire_db* db, PakfireRepo repo, sqli
                goto ERROR;
        }
 
+       // ID
+       uint64_t id = sqlite3_column_int64(stmt, 3);
+       if (id)
+               pakfire_package_set_dbid(pkg, id);
+
        // Groups
-       const char* groups = (const char*)sqlite3_column_text(stmt, 3);
+       const char* groups = (const char*)sqlite3_column_text(stmt, 4);
        if (groups) {
                pakfire_package_set_groups(pkg, groups);
        }
 
        // Filename
-       const char* filename = (const char*)sqlite3_column_text(stmt, 4);
+       const char* filename = (const char*)sqlite3_column_text(stmt, 5);
        if (filename) {
                pakfire_package_set_filename(pkg, filename);
        }
 
        // Size
-       size_t size = sqlite3_column_int64(stmt, 5);
+       size_t size = sqlite3_column_int64(stmt, 6);
        if (size) {
                pakfire_package_set_downloadsize(pkg, size);
        }
 
        // Installed size
-       size = sqlite3_column_int64(stmt, 6);
+       size = sqlite3_column_int64(stmt, 7);
        if (size) {
                pakfire_package_set_installsize(pkg, size);
        }
 
        // Hash 1
-       const char* hash1 = (const char*)sqlite3_column_text(stmt, 7);
+       const char* hash1 = (const char*)sqlite3_column_text(stmt, 8);
        if (hash1) {
                pakfire_package_set_checksum(pkg, hash1);
        }
 
        // License
-       const char* license = (const char*)sqlite3_column_text(stmt, 8);
+       const char* license = (const char*)sqlite3_column_text(stmt, 9);
        if (license) {
                pakfire_package_set_license(pkg, license);
        }
 
        // Summary
-       const char* summary = (const char*)sqlite3_column_text(stmt, 9);
+       const char* summary = (const char*)sqlite3_column_text(stmt, 10);
        if (summary) {
                pakfire_package_set_summary(pkg, summary);
        }
 
        // Description
-       const char* description = (const char*)sqlite3_column_text(stmt, 10);
+       const char* description = (const char*)sqlite3_column_text(stmt, 11);
        if (description) {
                pakfire_package_set_description(pkg, description);
        }
 
        // UUID
-       const char* uuid = (const char*)sqlite3_column_text(stmt, 11);
+       const char* uuid = (const char*)sqlite3_column_text(stmt, 12);
        if (uuid) {
                pakfire_package_set_uuid(pkg, uuid);
        }
 
        // Vendor
-       const char* vendor = (const char*)sqlite3_column_text(stmt, 12);
+       const char* vendor = (const char*)sqlite3_column_text(stmt, 13);
        if (vendor) {
                pakfire_package_set_vendor(pkg, vendor);
        }
 
        // Build Host
-       const char* build_host = (const char*)sqlite3_column_text(stmt, 13);
+       const char* build_host = (const char*)sqlite3_column_text(stmt, 14);
        if (build_host) {
                pakfire_package_set_build_host(pkg, build_host);
        }
 
        // Build Time
-       time_t build_time = sqlite3_column_int64(stmt, 14);
+       time_t build_time = sqlite3_column_int64(stmt, 15);
        if (build_time) {
                pakfire_package_set_build_time(pkg, build_time);
        }
 
        // Install Time
-       time_t install_time = sqlite3_column_int64(stmt, 15);
+       time_t install_time = sqlite3_column_int64(stmt, 16);
        if (install_time) {
                pakfire_package_set_install_time(pkg, install_time);
        }
 
        // installed by user?
-       int userinstalled = sqlite3_column_int(stmt, 16);
+       int userinstalled = sqlite3_column_int(stmt, 17);
        if (userinstalled)
                pakfire_db_add_userinstalled(db->pakfire, name);
 
        // Files
-       const char* files = (const char*)sqlite3_column_text(stmt, 17);
+       const char* files = (const char*)sqlite3_column_text(stmt, 18);
        if (files) {
                r = pakfire_package_set_filelist_from_string(pkg, files);
                if (r)
@@ -1485,15 +1491,15 @@ static int pakfire_db_load_package(struct pakfire_db* db, PakfireRepo repo, sqli
                unsigned int field;
                void (*func)(PakfirePackage pkg, const char* dep);
        } dependencies[] = {
-               { 18, pakfire_package_add_provides },
-               { 19, pakfire_package_add_prerequires },
-               { 20, pakfire_package_add_requires },
-               { 21, pakfire_package_add_conflicts },
-               { 22, pakfire_package_add_obsoletes },
-               { 23, pakfire_package_add_recommends },
-               { 24, pakfire_package_add_suggests },
-               { 25, pakfire_package_add_supplements },
-               { 26, pakfire_package_add_enhances },
+               { 19, pakfire_package_add_provides },
+               { 20, pakfire_package_add_prerequires },
+               { 21, pakfire_package_add_requires },
+               { 22, pakfire_package_add_conflicts },
+               { 23, pakfire_package_add_obsoletes },
+               { 24, pakfire_package_add_recommends },
+               { 25, pakfire_package_add_suggests },
+               { 26, pakfire_package_add_supplements },
+               { 27, pakfire_package_add_enhances },
                { 0, NULL },
        };
 
@@ -1529,8 +1535,8 @@ int pakfire_db_load(struct pakfire_db* db, PakfireRepo repo) {
 
        const char* sql =
                "SELECT "
-                       "name, evr, arch, groups, filename, size, inst_size, hash1, license, summary, "
-                       "description, uuid, vendor, build_host, build_time, "
+                       "name, evr, arch, id, groups, filename, size, inst_size, hash1, license, "
+                       "summary, description, uuid, vendor, build_host, build_time, "
                        "strftime('%s', installed) AS installed, userinstalled, "
                        "("
                                "SELECT group_concat(path, '\n') FROM files WHERE files.pkg = packages.id"
@@ -1633,3 +1639,173 @@ ERROR:
 
        return r;
 }
+
+static int pakfire_db_load_file(struct pakfire_db* db, PakfireFilelist filelist,
+               sqlite3_stmt* stmt) {
+       struct pakfire_file* file = NULL;
+       char abspath[PATH_MAX];
+       int r;
+
+       // Create a new file object
+       r = pakfire_file_create(&file, db->pakfire);
+       if (r)
+               goto ERROR;
+
+       // Path
+       const char* path = (const char*)sqlite3_column_text(stmt, 0);
+       if (path)
+               pakfire_file_set_path(file, path);
+
+       // Abspath
+       r = pakfire_make_path(db->pakfire, abspath, path);
+       if (r < 0)
+               goto ERROR;
+
+       pakfire_file_set_abspath(file, abspath);
+
+       // Size
+       size_t size = sqlite3_column_int64(stmt, 1);
+       if (size)
+               pakfire_file_set_size(file, size);
+
+       // Mode
+       mode_t mode = sqlite3_column_int(stmt, 2);
+       if (mode)
+               pakfire_file_set_mode(file, mode);
+
+       // User
+       const char* user = (const char*)sqlite3_column_text(stmt, 3);
+       if (user)
+               pakfire_file_set_user(file, user);
+
+       // Group
+       const char* group = (const char*)sqlite3_column_text(stmt, 4);
+       if (group)
+               pakfire_file_set_group(file, group);
+
+       // ctime
+       time_t ctime = sqlite3_column_int64(stmt, 5);
+       if (ctime)
+               pakfire_file_set_ctime(file, ctime);
+
+       // mtime
+       time_t mtime = sqlite3_column_int64(stmt, 6);
+       if (mtime)
+               pakfire_file_set_mtime(file, mtime);
+
+       // Append the file to the filelist
+       r = pakfire_filelist_append(filelist, file);
+
+ERROR:
+       if (file)
+               pakfire_file_unref(file);
+
+       return r;
+}
+
+int pakfire_db_package_filelist(struct pakfire_db* db, PakfireFilelist* filelist,
+               PakfirePackage pkg) {
+       PakfireFilelist fl = NULL;
+       sqlite3_stmt* stmt = NULL;
+       int r = 1;
+
+       // Fetch the package ID
+       uint64_t id = pakfire_package_get_dbid(pkg);
+       if (!id) {
+               ERROR(db->pakfire, "Package did not have an ID\n");
+               return 1;
+       }
+
+       // Create a new filelist
+       r = pakfire_filelist_create(&fl, db->pakfire);
+       if (r) {
+               ERROR(db->pakfire, "Could not create filelist: %m\n");
+               goto ERROR;
+       }
+
+       const char* sql =
+               "SELECT "
+                       "path, "
+                       "size, "
+                       "mode, "
+                       "user, "
+                       "'group', "
+                       "ctime, "
+                       "mtime "
+               "FROM files "
+
+               // Select all files that belong to this package
+               "WHERE "
+                       "pkg = ? "
+
+               // Filter out any files that are also in a different package (i.e. an update
+               // that has already been installed and this is the cleanup of the obsolete pkg)
+               "AND "
+                       "NOT EXISTS ("
+                               "SELECT "
+                                       "1 "
+                               "FROM files AS duplicates "
+                               "WHERE "
+                                       "files.path = duplicates.path "
+                               "AND "
+                                       "files.pkg != duplicates.pkg"
+                       ") "
+
+               // Return the longest paths first
+               "ORDER BY "
+                       "length(path) DESC"
+               ";";
+
+       // Prepare the statement
+       r = sqlite3_prepare_v2(db->handle, sql, strlen(sql), &stmt, NULL);
+       if (r) {
+               ERROR(db->pakfire, "Could not prepare SQL statement: %s %s\n",
+                       sql, sqlite3_errmsg(db->handle));
+               goto ERROR;
+       }
+
+       // Bind package ID
+       r = sqlite3_bind_int64(stmt, 1, id);
+       if (r) {
+               ERROR(db->pakfire, "Could not bind package ID: %s\n", sqlite3_errmsg(db->handle));
+               goto ERROR;
+       }
+
+       for (;;) {
+               // Execute query
+               r = sqlite3_step(stmt);
+
+               switch (r) {
+                       // Retry if the database was busy
+                       case SQLITE_BUSY:
+                               continue;
+
+                       // Read a row
+                       case SQLITE_ROW:
+                               r = pakfire_db_load_file(db, fl, stmt);
+                               if (r)
+                                       goto ERROR;
+                               break;
+
+                       // All rows have been processed
+                       case SQLITE_DONE:
+                               goto END;
+
+                       // Go to error in any other cases
+                       default:
+                               goto ERROR;
+               }
+       }
+
+END:
+       *filelist = pakfire_filelist_ref(fl);
+       r = 0;
+
+ERROR:
+       if (stmt)
+               sqlite3_finalize(stmt);
+       if (fl)
+               pakfire_filelist_unref(fl);
+
+       return r;
+}
index 4bc14f4568d7cdd5ac7d2ac4e2b90355f3809655..fd517e986934e993e44231a7a3fd6b6d6bc39f8a 100644 (file)
@@ -273,15 +273,7 @@ static int pakfire_file_levels(struct pakfire_file* file) {
        return levels;
 }
 
-/*
-       This function tries to remove the file after it has been packaged.
-
-       It will try to delete any parent directories as well and ignore if directories
-       cannot be deleted because they might contain other files
-*/
-int pakfire_file_cleanup(struct pakfire_file* file) {
-       char path[PATH_MAX];
-
+int pakfire_file_remove(struct pakfire_file* file) {
        if (!*file->abspath) {
                errno = EINVAL;
                return 1;
@@ -298,6 +290,23 @@ int pakfire_file_cleanup(struct pakfire_file* file) {
                ERROR(file->pakfire, "Could not remove %s (%s): %m\n", file->path, file->abspath);
        }
 
+       return r;
+}
+
+/*
+       This function tries to remove the file after it has been packaged.
+
+       It will try to delete any parent directories as well and ignore if directories
+       cannot be deleted because they might contain other files
+*/
+int pakfire_file_cleanup(struct pakfire_file* file) {
+       char path[PATH_MAX];
+
+       // Try removing the file
+       int r = pakfire_file_remove(file);
+       if (r)
+               return r;
+
        // Create a working copy of abspath
        r = pakfire_string_set(path, file->abspath);
        if (r < 0)
index 4f3de1e9a3e771f06e95414869c2ab42706c5fbc..9e89592bc7d15f90f7e6f35cb80077e4f64cc6b8 100644 (file)
@@ -53,6 +53,9 @@ int pakfire_db_load(struct pakfire_db* db, PakfireRepo repo);
 struct pakfire_scriptlet* pakfire_db_get_scriptlet(
        struct pakfire_db* db, PakfirePackage pkg, const char* type);
 
+int pakfire_db_package_filelist(struct pakfire_db* db, PakfireFilelist* filelist,
+       PakfirePackage pkg);
+
 #endif
 
 #endif /* PAKFIRE_DB_H */
index a560f5d087f8c8f7ce50736b3e4fcb94fbc71cc4..a231130cea1e8228364f9c765b004e635354776a 100644 (file)
@@ -75,6 +75,7 @@ int pakfire_file_copy_archive_entry(struct pakfire_file* file, struct archive_en
 const char* pakfire_file_get_abspath(struct pakfire_file* file);
 int pakfire_file_set_abspath(struct pakfire_file* file, const char* path);
 
+int pakfire_file_remove(struct pakfire_file* file);
 int pakfire_file_cleanup(struct pakfire_file* file);
 
 #endif
index 466778d76e8f3072c7bee2c3e1a5b518abb18bed..36304a2a5cb8b1932db075918a49df232f8d8038 100644 (file)
@@ -113,6 +113,9 @@ enum pakfire_package_dump_flags {
 
 PakfirePackage pakfire_package_create_from_solvable(Pakfire pakfire, Id id);
 
+uint64_t pakfire_package_get_dbid(PakfirePackage pkg);
+void pakfire_package_set_dbid(PakfirePackage pkg, uint64_t id);
+
 Id pakfire_package_id(PakfirePackage pkg);
 int pakfire_package_is_source(PakfirePackage pkg);
 
index 80bbc37fa3edafb121d1d61786098c3e4ae6e64c..30071f87b05ae15c664db053644ca2be611f6dc8 100644 (file)
@@ -284,6 +284,19 @@ static void pakfire_package_internalize_repo(PakfirePackage pkg) {
        }
 }
 
+static unsigned long long pakfire_package_get_num(PakfirePackage pkg, Id type) {
+       pakfire_package_internalize_repo(pkg);
+
+       Solvable* s = get_solvable(pkg);
+       return solvable_lookup_num(s, type, 0);
+}
+
+static void pakfire_package_set_num(PakfirePackage pkg, Id type, unsigned long long value) {
+       Solvable* s = get_solvable(pkg);
+
+       solvable_set_num(s, type, value);
+}
+
 static const char* pakfire_package_get_string(PakfirePackage pkg, int key) {
        pakfire_package_internalize_repo(pkg);
 
@@ -346,6 +359,14 @@ static void pakfire_package_add_string_array(PakfirePackage pkg, Id key, const c
        solvable_add_poolstr_array(s, key, value);
 }
 
+uint64_t pakfire_package_get_dbid(PakfirePackage pkg) {
+       return pakfire_package_get_num(pkg, RPM_RPMDBID);
+}
+
+void pakfire_package_set_dbid(PakfirePackage pkg, uint64_t id) {
+       pakfire_package_set_num(pkg, RPM_RPMDBID, id);
+}
+
 PAKFIRE_EXPORT const char* pakfire_package_get_uuid(PakfirePackage pkg) {
        return pakfire_package_get_string(pkg, SOLVABLE_PKGID);
 }
@@ -539,19 +560,6 @@ PAKFIRE_EXPORT int pakfire_package_is_installed(PakfirePackage pkg) {
        return pool->installed == s->repo;
 }
 
-static unsigned long long pakfire_package_get_num(PakfirePackage pkg, Id type) {
-       pakfire_package_internalize_repo(pkg);
-
-       Solvable* s = get_solvable(pkg);
-       return solvable_lookup_num(s, type, 0);
-}
-
-static void pakfire_package_set_num(PakfirePackage pkg, Id type, unsigned long long value) {
-       Solvable* s = get_solvable(pkg);
-
-       solvable_set_num(s, type, value);
-}
-
 PAKFIRE_EXPORT unsigned long long pakfire_package_get_downloadsize(PakfirePackage pkg) {
        return pakfire_package_get_num(pkg, SOLVABLE_DOWNLOADSIZE);
 }
index e1fa25d3ec5ea7593e4393ebcbfa20e9d6f1e1dd..ede695d2d868b559deb70725805472d5baea807e 100644 (file)
@@ -27,6 +27,8 @@
 #include <pakfire/db.h>
 #include <pakfire/downloader.h>
 #include <pakfire/execute.h>
+#include <pakfire/file.h>
+#include <pakfire/filelist.h>
 #include <pakfire/i18n.h>
 #include <pakfire/logging.h>
 #include <pakfire/package.h>
@@ -539,11 +541,38 @@ static int pakfire_transaction_extract(struct pakfire_transaction* transaction,
 }
 
 static int pakfire_transaction_erase(struct pakfire_transaction* transaction,
-               PakfirePackage pkg, PakfireArchive archive) {
+               struct pakfire_db* db, PakfirePackage pkg) {
+       PakfireFilelist filelist = NULL;
+       int r;
+
+       // Fetch filelist
+       r = pakfire_db_package_filelist(db, &filelist, pkg);
+       if (r)
+               goto ERROR;
+
+       const size_t length = pakfire_filelist_size(filelist);
+
+       // Delete all files
+       for (unsigned int i = 0; i < length; i++) {
+               struct pakfire_file* file = pakfire_filelist_get(filelist, i);
+
+               // Remove the file
+               r = pakfire_file_remove(file);
+               pakfire_file_unref(file);
+
+               // Break on any errors
+               if (r)
+                       goto ERROR;
+       }
+
        // Update the runtime linker cache after all files have been removed
        pakfire_execute_ldconfig(transaction->pakfire);
 
-       return 0; // TODO
+ERROR:
+       if (filelist)
+               pakfire_filelist_unref(filelist);
+
+       return r;
 }
 
 static const char* pakfire_action_type_string(pakfire_action_type_t type) {
@@ -713,7 +742,7 @@ static int pakfire_transaction_run_step(struct pakfire_transaction* transaction,
                                        if (r)
                                                break;
 
-                                       r = pakfire_transaction_erase(transaction, pkg, archive);
+                                       r = pakfire_transaction_erase(transaction, db, pkg);
                                        if (r)
                                                break;