Date: Thursday, February 8, 2007 @ 03:09:35 Author: aaron Path: /home/cvs-pacman/pacman-lib/lib/libalpm Modified: alpm.h (1.71 -> 1.72) error.c (1.16 -> 1.17) remove.c (1.60 -> 1.61) Attempt to NOT remove packages on filesystem errors (like a read-only filesystem). See FS#5887 ----------+ alpm.h | 1 error.c | 2 + remove.c | 95 +++++++++++++++++++++++++++++++++++++++++++------------------ 3 files changed, 71 insertions(+), 27 deletions(-) Index: pacman-lib/lib/libalpm/alpm.h diff -u pacman-lib/lib/libalpm/alpm.h:1.71 pacman-lib/lib/libalpm/alpm.h:1.72 --- pacman-lib/lib/libalpm/alpm.h:1.71 Sun Feb 4 03:26:52 2007 +++ pacman-lib/lib/libalpm/alpm.h Thu Feb 8 03:09:34 2007 @@ -450,6 +450,7 @@ PM_ERR_PKG_LOAD, PM_ERR_PKG_INSTALLED, PM_ERR_PKG_CANT_FRESH, + PM_ERR_PKG_CANT_REMOVE, PM_ERR_PKG_INVALID_NAME, PM_ERR_PKG_CORRUPTED, PM_ERR_PKG_REPO_NOT_FOUND, Index: pacman-lib/lib/libalpm/error.c diff -u pacman-lib/lib/libalpm/error.c:1.16 pacman-lib/lib/libalpm/error.c:1.17 --- pacman-lib/lib/libalpm/error.c:1.16 Tue Jan 30 02:47:20 2007 +++ pacman-lib/lib/libalpm/error.c Thu Feb 8 03:09:35 2007 @@ -97,6 +97,8 @@ return _("package already installed"); case PM_ERR_PKG_CANT_FRESH: return _("package not installed or lesser version"); + case PM_ERR_PKG_CANT_REMOVE: + return _("cannot remove all files for package"); case PM_ERR_PKG_INVALID_NAME: return _("package name is not valid"); case PM_ERR_PKG_CORRUPTED: Index: pacman-lib/lib/libalpm/remove.c diff -u pacman-lib/lib/libalpm/remove.c:1.60 pacman-lib/lib/libalpm/remove.c:1.61 --- pacman-lib/lib/libalpm/remove.c:1.60 Wed Jan 31 01:10:21 2007 +++ pacman-lib/lib/libalpm/remove.c Thu Feb 8 03:09:35 2007 @@ -162,8 +162,40 @@ return(strcmp(s1, s2)); } + +static int can_remove_file(const char *path) +{ + alpm_list_t *i; + char file[PATH_MAX+1]; + + snprintf(file, PATH_MAX, "%s%s", handle->root, path); + + for(i = handle->trans->skiplist; i; i = i->next) { + if(strcmp(file, i->data) == 0) { + /* skipping this file, return success because "removing" this + * file does nothing */ + return(1); + } + } + /* If we fail write permissions due to a read-only filesystem, abort. + * Assume all other possible failures are covered somewhere else */ + if(access(file, W_OK) == -1) { + if(access(file, F_OK) == 0) { + /* only return failure if the file ACTUALLY exists and we don't have + * permissions */ + _alpm_log(PM_LOG_WARNING, _("cannot remove file '%s': %s"), file, strerror(errno)); + return(0); + } + } + + return(1); +} + /* Helper function for iterating through a package's file and deleting them * Used by _alpm_remove_commit + * + * TODO the parameters are a bit out of control here. This function doesn't + * need to report PROGRESS, do it in the parent function. */ static void unlink_file(pmpkg_t *info, alpm_list_t *lp, alpm_list_t *targ, pmtrans_t *trans, int filenum, int *position) @@ -171,34 +203,35 @@ struct stat buf; int nb = 0; double percent = 0.0; - char *file = lp->data; - char line[PATH_MAX+1]; + char file[PATH_MAX+1]; char *checksum = _alpm_needbackup(lp->data, info->backup); ALPM_LOG_FUNC; - if ( *position != 0 ) { + if(*position != 0) { percent = (double)*position / filenum; - } if ( checksum ) { + } + if(checksum) { nb = 1; FREE(checksum); - } if ( !nb && trans->type == PM_TRANS_TYPE_UPGRADE ) { + } + if(!nb && trans->type == PM_TRANS_TYPE_UPGRADE) { /* check noupgrade */ - if ( alpm_list_find_str(handle->noupgrade, file) ) { + if(alpm_list_find_str(handle->noupgrade, lp->data)) { nb = 1; } } - snprintf(line, PATH_MAX, "%s%s", handle->root, file); - if ( lstat(line, &buf) ) { - _alpm_log(PM_LOG_DEBUG, _("file %s does not exist"), line); + snprintf(file, PATH_MAX, "%s%s", handle->root, (char *)lp->data); + if(lstat(file, &buf)) { + _alpm_log(PM_LOG_DEBUG, _("file %s does not exist"), file); return; } - if ( S_ISDIR(buf.st_mode) ) { - if ( rmdir(line) ) { + if(S_ISDIR(buf.st_mode)) { + if(rmdir(file)) { /* this is okay, other pakcages are probably using it (like /usr) */ - _alpm_log(PM_LOG_DEBUG, _("keeping directory %s"), line); + _alpm_log(PM_LOG_DEBUG, _("keeping directory %s"), file); } else { - _alpm_log(PM_LOG_DEBUG, _("removing directory %s"), line); + _alpm_log(PM_LOG_DEBUG, _("removing directory %s"), file); } } else { /* check the "skip list" before removing the file. @@ -206,35 +239,36 @@ * explanation. */ int skipit = 0; alpm_list_t *j; - for ( j = trans->skiplist; j; j = j->next ) { - if ( !strcmp(file, (char*)j->data) ) { + for(j = trans->skiplist; j; j = j->next) { + if(!strcmp(lp->data, (char*)j->data)) { skipit = 1; } } - if ( skipit ) { - _alpm_log(PM_LOG_DEBUG, _("skipping removal of %s as it has moved to another package"), - line); + if(skipit) { + _alpm_log(PM_LOG_WARNING, _("skipping removal of %s as it has moved to another package"), + file); } else { /* if the file is flagged, back it up to .pacsave */ - if ( nb ) { - if ( !(trans->type == PM_TRANS_TYPE_UPGRADE) ) { + if(nb) { + if(!(trans->type == PM_TRANS_TYPE_UPGRADE)) { /* if it was an upgrade, the file would be left alone because * pacman_add() would handle it */ - if ( !(trans->type & PM_TRANS_FLAG_NOSAVE) ) { + if(!(trans->type & PM_TRANS_FLAG_NOSAVE)) { char newpath[PATH_MAX]; - snprintf(newpath, PATH_MAX, "%s.pacsave", line); - rename(line, newpath); - _alpm_log(PM_LOG_WARNING, _("%s saved as %s"), line, newpath); + snprintf(newpath, PATH_MAX, "%s.pacsave", file); + rename(file, newpath); + _alpm_log(PM_LOG_WARNING, _("%s saved as %s"), file, newpath); } } } else { - _alpm_log(PM_LOG_DEBUG, _("unlinking %s"), line); + _alpm_log(PM_LOG_DEBUG, _("unlinking %s"), file); int list_count = alpm_list_count(trans->packages); /* this way we don't have to call alpm_list_count twice during PROGRESS */ + PROGRESS(trans, PM_TRANS_PROGRESS_REMOVE_START, info->name, (double)(percent * 100), list_count, (list_count - alpm_list_count(targ) + 1)); ++(*position); - if (unlink(line) == -1) { - _alpm_log(PM_LOG_ERROR, _("cannot remove file %s: %s"), file, strerror(errno)); + if(unlink(file) == -1) { + _alpm_log(PM_LOG_ERROR, _("cannot remove file %s: %s"), lp->data, strerror(errno)); } } } @@ -272,6 +306,13 @@ } if(!(trans->flags & PM_TRANS_FLAG_DBONLY)) { + for(lp = info->files; lp; lp = lp->next) { + if(!can_remove_file(lp->data)) { + _alpm_log(PM_LOG_DEBUG, _("not removing package '%s', can't remove all files"), info->name); + RET_ERR(PM_ERR_PKG_CANT_REMOVE, -1); + } + } + int filenum = alpm_list_count(info->files); _alpm_log(PM_LOG_DEBUG, _("removing files"));