From 61fa9b8c7e8b84ff65affda6a60f3697955e4e4f Mon Sep 17 00:00:00 2001 From: Juan RP Date: Sun, 9 Feb 2014 11:54:49 +0100 Subject: [PATCH] Improve package removal by using a two phase approach: check and removal. --- NEWS | 4 ++++ lib/package_remove.c | 43 +++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/NEWS b/NEWS index 5a7deb6d..7096164a 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,9 @@ xbps-0.32 (???): + * Do the package removal in two phases: the first phase checks the + user has write permission to the entries being removed, if this + succeeds then the package removal is performed. + * xbps-remove(8): -O now also remove obsolete pkg signatures from cachedir, and ignores pkgs of other architectures. diff --git a/lib/package_remove.c b/lib/package_remove.c index 4bd76466..022523f6 100644 --- a/lib/package_remove.c +++ b/lib/package_remove.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2009-2013 Juan Romero Pardines. + * Copyright (c) 2009-2014 Juan Romero Pardines. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -82,6 +82,33 @@ xbps_remove_pkg_files(struct xbps_handle *xhp, else if (strcmp(key, "dirs") == 0) curobj = "directory"; + /* + * Do the removal in 2 phases: + * 1- check if user has enough perms to remove entry + * 2- perform removal + */ + while ((obj = xbps_object_iterator_next(iter))) { + xbps_dictionary_get_cstring_nocopy(obj, "file", &file); + path = xbps_xasprintf("%s/%s", xhp->rootdir, file); + if (access(path, W_OK)) { + if (errno == ENOENT) { + /* ignore ENOENT, file might have dissapeared */ + continue; + } + /* + * only bail out if something else than ENOENT + * is returned. + */ + rv = errno; + xbps_set_cb_state(xhp, XBPS_STATE_REMOVE_FILE_FAIL, rv, pkgver, + "%s: cannot remove %s `%s': %s", pkgver, curobj, file, strerror(rv)); + } + } + if (rv != 0) + goto out; + + xbps_object_iterator_reset(iter); + while ((obj = xbps_object_iterator_next(iter))) { xbps_dictionary_get_cstring_nocopy(obj, "file", &file); path = xbps_xasprintf("%s/%s", xhp->rootdir, file); @@ -160,7 +187,13 @@ xbps_remove_pkg_files(struct xbps_handle *xhp, errno, pkgver, "%s: failed to remove %s `%s': %s", pkgver, curobj, file, strerror(errno)); - errno = 0; + if (errno != ENOENT) { + /* + * only bail out if something else than ENOENT + * is returned. + */ + rv = errno; + } } else { /* success */ xbps_set_cb_state(xhp, XBPS_STATE_REMOVE_FILE, @@ -168,6 +201,8 @@ xbps_remove_pkg_files(struct xbps_handle *xhp, } free(path); } + +out: xbps_object_iterator_release(iter); return rv; @@ -326,6 +361,10 @@ purge: out: if (pkgname != NULL) free(pkgname); + if (rv != 0) { + xbps_set_cb_state(xhp, XBPS_STATE_REMOVE_FAIL, rv, pkgver, + "%s: failed to remove package: %s", pkgver, strerror(rv)); + } return rv; }