From: Michael Tremer Date: Wed, 23 Jun 2021 17:31:24 +0000 (+0000) Subject: transaction: Actually erase files from disk when removing a package X-Git-Tag: 0.9.28~1189 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=ac71886ae7450d9d2a7f59899a7fb6394cf286bf;p=pakfire.git transaction: Actually erase files from disk when removing a package Signed-off-by: Michael Tremer --- diff --git a/src/libpakfire/db.c b/src/libpakfire/db.c index e71788663..fb75b3d88 100644 --- a/src/libpakfire/db.c +++ b/src/libpakfire/db.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -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; +} diff --git a/src/libpakfire/file.c b/src/libpakfire/file.c index 4bc14f456..fd517e986 100644 --- a/src/libpakfire/file.c +++ b/src/libpakfire/file.c @@ -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) diff --git a/src/libpakfire/include/pakfire/db.h b/src/libpakfire/include/pakfire/db.h index 4f3de1e9a..9e89592bc 100644 --- a/src/libpakfire/include/pakfire/db.h +++ b/src/libpakfire/include/pakfire/db.h @@ -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 */ diff --git a/src/libpakfire/include/pakfire/file.h b/src/libpakfire/include/pakfire/file.h index a560f5d08..a231130ce 100644 --- a/src/libpakfire/include/pakfire/file.h +++ b/src/libpakfire/include/pakfire/file.h @@ -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 diff --git a/src/libpakfire/include/pakfire/package.h b/src/libpakfire/include/pakfire/package.h index 466778d76..36304a2a5 100644 --- a/src/libpakfire/include/pakfire/package.h +++ b/src/libpakfire/include/pakfire/package.h @@ -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); diff --git a/src/libpakfire/package.c b/src/libpakfire/package.c index 80bbc37fa..30071f87b 100644 --- a/src/libpakfire/package.c +++ b/src/libpakfire/package.c @@ -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); } diff --git a/src/libpakfire/transaction.c b/src/libpakfire/transaction.c index e1fa25d3e..ede695d2d 100644 --- a/src/libpakfire/transaction.c +++ b/src/libpakfire/transaction.c @@ -27,6 +27,8 @@ #include #include #include +#include +#include #include #include #include @@ -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;