summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/libalpm/remove.c45
-rw-r--r--lib/libalpm/util.c42
-rw-r--r--lib/libalpm/util.h1
3 files changed, 82 insertions, 6 deletions
diff --git a/lib/libalpm/remove.c b/lib/libalpm/remove.c
index b15dbaa5..c2a8ad2c 100644
--- a/lib/libalpm/remove.c
+++ b/lib/libalpm/remove.c
@@ -232,8 +232,8 @@ static void unlink_file(alpm_handle_t *handle, alpm_pkg_t *info,
* see the big comment block in db_find_fileconflicts() for an
* explanation. */
if(alpm_list_find_str(skip_remove, fileobj->name)) {
- _alpm_log(handle, ALPM_LOG_DEBUG, "%s is in skip_remove, skipping removal\n",
- file);
+ _alpm_log(handle, ALPM_LOG_DEBUG,
+ "%s is in skip_remove, skipping removal\n", file);
return;
}
@@ -247,11 +247,44 @@ static void unlink_file(alpm_handle_t *handle, alpm_pkg_t *info,
}
if(S_ISDIR(buf.st_mode)) {
- if(rmdir(file)) {
- /* this is okay, other packages are probably using it (like /usr) */
- _alpm_log(handle, ALPM_LOG_DEBUG, "keeping directory %s\n", file);
+ ssize_t files = _alpm_files_in_directory(handle, file, 0);
+ /* if we have files, no need to remove the directory */
+ if(files > 0) {
+ _alpm_log(handle, ALPM_LOG_DEBUG, "keeping directory %s (contains files)\n",
+ file);
+ } else if(files < 0) {
+ _alpm_log(handle, ALPM_LOG_DEBUG,
+ "keeping directory %s (could not count files)\n", file);
} else {
- _alpm_log(handle, ALPM_LOG_DEBUG, "removing directory %s\n", file);
+ /* one last check- does any other package own this file? */
+ alpm_list_t *local, *local_pkgs;
+ int found = 0;
+ local_pkgs = _alpm_db_get_pkgcache(handle->db_local);
+ for(local = local_pkgs; local && !found; local = local->next) {
+ alpm_pkg_t *local_pkg = local->data;
+ alpm_list_t *files;
+
+ /* we duplicated the package when we put it in the removal list, so we
+ * so we can't use direct pointer comparison here. */
+ if(_alpm_pkg_cmp(info, local_pkg) == 0) {
+ continue;
+ }
+ files = alpm_pkg_get_files(local_pkg);
+ if(_alpm_filelist_contains(files, fileobj->name)) {
+ _alpm_log(handle, ALPM_LOG_DEBUG,
+ "keeping directory %s (owned by %s)\n", file, local_pkg->name);
+ found = 1;
+ }
+ }
+ if(!found) {
+ if(rmdir(file)) {
+ _alpm_log(handle, ALPM_LOG_DEBUG,
+ "directory removal of %s failed: %s\n", file, strerror(errno));
+ } else {
+ _alpm_log(handle, ALPM_LOG_DEBUG,
+ "removed directory %s (no remaining owners)\n", file);
+ }
+ }
}
} else {
/* if the file needs backup and has been modified, back it up to .pacsave */
diff --git a/lib/libalpm/util.c b/lib/libalpm/util.c
index cd7f19c9..62313d81 100644
--- a/lib/libalpm/util.c
+++ b/lib/libalpm/util.c
@@ -388,6 +388,48 @@ int _alpm_rmrf(const char *path)
return 0;
}
+/**
+ * Determine if there are files in a directory
+ * @param handle the context handle
+ * @param path the full absolute directory path
+ * @param full_count whether to return an exact count of files
+ * @return a file count if full_count is != 0, else >0 if directory has
+ * contents, 0 if no contents, and -1 on error
+ */
+ssize_t _alpm_files_in_directory(alpm_handle_t *handle, const char *path,
+ int full_count)
+{
+ ssize_t files = 0;
+ struct dirent *ent;
+ DIR *dir = opendir(path);
+
+ if(!dir) {
+ if(errno == ENOTDIR) {
+ _alpm_log(handle, ALPM_LOG_DEBUG, "%s was not a directory\n", path);
+ } else {
+ _alpm_log(handle, ALPM_LOG_DEBUG, "could not read directory %s\n",
+ path);
+ }
+ return -1;
+ }
+ while((ent = readdir(dir)) != NULL) {
+ const char *name = ent->d_name;
+
+ if(strcmp(name, ".") == 0 || strcmp(name, "..") == 0) {
+ continue;
+ }
+
+ files++;
+
+ if(!full_count) {
+ break;
+ }
+ }
+
+ closedir(dir);
+ return files;
+}
+
int _alpm_logaction(alpm_handle_t *handle, const char *fmt, va_list args)
{
int ret = 0;
diff --git a/lib/libalpm/util.h b/lib/libalpm/util.h
index 450dac9b..d66ddee9 100644
--- a/lib/libalpm/util.h
+++ b/lib/libalpm/util.h
@@ -100,6 +100,7 @@ int _alpm_unpack_single(alpm_handle_t *handle, const char *archive,
int _alpm_unpack(alpm_handle_t *handle, const char *archive, const char *prefix,
alpm_list_t *list, int breakfirst);
int _alpm_rmrf(const char *path);
+ssize_t _alpm_files_in_directory(alpm_handle_t *handle, const char *path, int full_count);
int _alpm_logaction(alpm_handle_t *handle, const char *fmt, va_list args);
int _alpm_run_chroot(alpm_handle_t *handle, const char *path, char *const argv[]);
int _alpm_ldconfig(alpm_handle_t *handle);