diff --git a/lib/package_unpack.c b/lib/package_unpack.c index c289c373..ec62a006 100644 --- a/lib/package_unpack.c +++ b/lib/package_unpack.c @@ -23,12 +23,14 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include #include #include #include #include #include #include +#include #include #include "xbps_api_impl.h" @@ -143,6 +145,33 @@ remove_metafile(const char *file, const char *pkgname, const char *version) return 0; } +static int +remove_file_wrong_hash(prop_dictionary_t d, const char *file) +{ + struct stat st; + const char *hash; + int rv = 0; + + if (stat(file, &st) == -1) + if (errno != ENOENT) + return errno; + + if (!S_ISREG(st.st_mode)) + return 0; + + /* Only check for regular files, not symlinks, dirs or conffiles. */ + hash = xbps_get_file_hash_from_dict(d, "files", file); + if (hash) { + rv = xbps_check_file_hash(file, hash); + if (rv == ERANGE) { + (void)unlink(file); + xbps_warn_printf("Removed `%s' entry with " + "with unmatched hash.\n", file); + } + } + return rv; +} + /* * Execute the unpack progress function callback if set and its * private data is also set. It's so sad that @@ -376,6 +405,21 @@ unpack_archive(prop_dictionary_t pkg_repod, continue; } } + /* + * Check if current entry already exists on disk and + * if the sha256 hash doesn't match, remove the file. + * Only do this if we are _installing_ a package. + */ + if (!update) { + rv = remove_file_wrong_hash(filesd, entry_pname); + if (rv != 0) { + xbps_dbg_printf("remove_file_wrong_hash " + "failed for `%s': %s\n", entry_pname, + strerror(rv)); + goto out; + } + } + /* * Extract entry from archive. */