diff options
Diffstat (limited to 'lib/libalpm')
-rw-r--r-- | lib/libalpm/add.c | 173 | ||||
-rw-r--r-- | lib/libalpm/alpm.h | 11 | ||||
-rw-r--r-- | lib/libalpm/alpm_list.c | 4 | ||||
-rw-r--r-- | lib/libalpm/alpm_list.h | 4 | ||||
-rw-r--r-- | lib/libalpm/be_package.c | 6 | ||||
-rw-r--r-- | lib/libalpm/conflict.c | 209 | ||||
-rw-r--r-- | lib/libalpm/error.c | 2 | ||||
-rw-r--r-- | lib/libalpm/filelist.c | 225 | ||||
-rw-r--r-- | lib/libalpm/filelist.h | 4 | ||||
-rw-r--r-- | lib/libalpm/package.c | 22 | ||||
-rw-r--r-- | lib/libalpm/remove.c | 11 |
11 files changed, 204 insertions, 467 deletions
diff --git a/lib/libalpm/add.c b/lib/libalpm/add.c index 3ef81e37..c20e7c61 100644 --- a/lib/libalpm/add.c +++ b/lib/libalpm/add.c @@ -197,30 +197,25 @@ static int extract_single_file(alpm_handle_t *handle, struct archive *archive, * to get 'right'. Here are the possibilities, with the filesystem * on the left and the package on the top: * (F=file, N=node, S=symlink, D=dir) - * | F/N | S | D - * non-existent | 1 | 2 | 3 - * F/N | 4 | 5 | 6 - * S | 7 | 8 | 9 - * D | 10 | 11 | 12 + * | F/N | D + * non-existent | 1 | 2 + * F/N | 3 | 4 + * D | 5 | 6 * - * 1,2,3- extract, no magic necessary. lstat (_alpm_lstat) will fail here. - * 4,5,6,7,8- conflict checks should have caught this. either overwrite + * 1,2- extract, no magic necessary. lstat (_alpm_lstat) will fail here. + * 3,4- conflict checks should have caught this. either overwrite * or backup the file. - * 9- follow the symlink, hopefully it is a directory, check it. - * 10- file replacing directory- don't allow it. - * 11- don't extract symlink- a dir exists here. we don't want links to - * links, etc. - * 12- skip extraction, dir already exists. + * 5- file replacing directory- don't allow it. + * 6- skip extraction, dir already exists. */ - /* do both a lstat and a stat, so we can see what symlinks point to */ - struct stat lsbuf, sbuf; - if(_alpm_lstat(filename, &lsbuf) != 0 || stat(filename, &sbuf) != 0) { - /* cases 1,2,3: couldn't stat an existing file, skip all backup checks */ + struct stat lsbuf; + if(_alpm_lstat(filename, &lsbuf) != 0) { + /* cases 1,2: file doesn't exist, skip all backup checks */ } else { if(S_ISDIR(lsbuf.st_mode)) { if(S_ISDIR(entrymode)) { - /* case 12: existing dir, ignore it */ + /* case 6: existing dir, ignore it */ if(lsbuf.st_mode != entrymode) { /* if filesystem perms are different than pkg perms, warn user */ mode_t mask = 07777; @@ -237,33 +232,18 @@ static int extract_single_file(alpm_handle_t *handle, struct archive *archive, archive_read_data_skip(archive); return 0; } else { - /* case 10/11: trying to overwrite dir with file/symlink, don't allow it */ + /* case 5: trying to overwrite dir with file, don't allow it */ _alpm_log(handle, ALPM_LOG_ERROR, _("extract: not overwriting dir with file %s\n"), filename); archive_read_data_skip(archive); return 1; } - } else if(S_ISLNK(lsbuf.st_mode) && S_ISDIR(entrymode)) { - /* case 9: existing symlink, dir in package */ - if(S_ISDIR(sbuf.st_mode)) { - /* the symlink on FS is to a directory, so we'll use it */ - _alpm_log(handle, ALPM_LOG_DEBUG, "extract: skipping symlink overwrite of %s\n", - filename); - archive_read_data_skip(archive); - return 0; - } else { - /* this is BAD. symlink was not to a directory */ - _alpm_log(handle, ALPM_LOG_ERROR, _("extract: symlink %s does not point to dir\n"), - filename); - archive_read_data_skip(archive); - return 1; - } - } else if(S_ISREG(lsbuf.st_mode) && S_ISDIR(entrymode)) { - /* case 6: trying to overwrite file with dir */ + } else if(S_ISDIR(entrymode)) { + /* case 4: trying to overwrite file with dir */ _alpm_log(handle, ALPM_LOG_DEBUG, "extract: overwriting file with dir %s\n", filename); - } else if(S_ISREG(entrymode)) { - /* case 4,7: */ + } else { + /* case 3: */ /* if file is in NoUpgrade, don't touch it */ if(alpm_list_find(handle->noupgrade, entryname, _alpm_fnmatch)) { notouch = 1; @@ -273,8 +253,6 @@ static int extract_single_file(alpm_handle_t *handle, struct archive *archive, /* check newpkg first, so that adding backup files is retroactive */ backup = _alpm_needbackup(entryname, newpkg); if(backup) { - /* if we force hash_orig to be non-NULL retroactive backup works */ - hash_orig = ""; needbackup = 1; } @@ -288,8 +266,6 @@ static int extract_single_file(alpm_handle_t *handle, struct archive *archive, } } } - /* else if(S_ISLNK(entrymode)) */ - /* case 5,8: don't need to do anything special */ } /* we need access to the original entryname later after calls to @@ -332,81 +308,80 @@ static int extract_single_file(alpm_handle_t *handle, struct archive *archive, _alpm_log(handle, ALPM_LOG_DEBUG, "new: %s\n", hash_pkg); _alpm_log(handle, ALPM_LOG_DEBUG, "original: %s\n", hash_orig); - if(!oldpkg) { - if(hash_local && hash_pkg && strcmp(hash_local, hash_pkg) != 0) { - /* looks like we have a local file that has a different hash as the - * file in the package, move it to a .pacorig */ + if(hash_local && hash_pkg && strcmp(hash_local, hash_pkg) == 0) { + /* local and new files are the same, no sense in installing the file + * over itself, regardless of what the original file was */ + _alpm_log(handle, ALPM_LOG_DEBUG, + "action: leaving existing file in place\n"); + unlink(checkfile); + } else if(hash_orig && hash_pkg && strcmp(hash_orig, hash_pkg) == 0) { + /* original and new files are the same, leave the local version alone, + * including any user changes */ + _alpm_log(handle, ALPM_LOG_DEBUG, + "action: leaving existing file in place\n"); + unlink(checkfile); + } else if(hash_orig && hash_local && strcmp(hash_orig, hash_local) == 0) { + /* installed file has NOT been changed by user, + * update to the new version */ + _alpm_log(handle, ALPM_LOG_DEBUG, "action: installing new file: %s\n", + entryname_orig); + if(try_rename(handle, checkfile, filename)) { + errors++; + } + } else { + /* none of the three files matched another, unpack the new file alongside + * the local file */ + + if(oldpkg) { + char *newpath; + size_t newlen = strlen(filename) + strlen(".pacnew") + 1; + + _alpm_log(handle, ALPM_LOG_DEBUG, + "action: keeping current file and installing" + " new one with .pacnew ending\n"); + + MALLOC(newpath, newlen, + errors++; handle->pm_errno = ALPM_ERR_MEMORY; goto needbackup_cleanup); + snprintf(newpath, newlen, "%s.pacnew", filename); + + if(try_rename(handle, checkfile, newpath)) { + errors++; + } else { + _alpm_log(handle, ALPM_LOG_WARNING, _("%s installed as %s\n"), + filename, newpath); + alpm_logaction(handle, ALPM_CALLER_PREFIX, + "warning: %s installed as %s\n", filename, newpath); + } + + free(newpath); + } else { char *newpath; - size_t newlen = strlen(filename) + 9; + size_t newlen = strlen(filename) + strlen(".pacorig") + 1; + + _alpm_log(handle, ALPM_LOG_DEBUG, + "action: saving existing file with a .pacorig ending" + " and installing a new one\n"); + MALLOC(newpath, newlen, errors++; handle->pm_errno = ALPM_ERR_MEMORY; goto needbackup_cleanup); snprintf(newpath, newlen, "%s.pacorig", filename); /* move the existing file to the "pacorig" */ if(try_rename(handle, filename, newpath)) { - errors++; - errors++; + errors++; /* failed rename filename -> filename.pacorig */ + errors++; /* failed rename checkfile -> filename */ } else { /* rename the file we extracted to the real name */ if(try_rename(handle, checkfile, filename)) { errors++; } else { - _alpm_log(handle, ALPM_LOG_WARNING, _("%s saved as %s\n"), filename, newpath); + _alpm_log(handle, ALPM_LOG_WARNING, + _("%s saved as %s\n"), filename, newpath); alpm_logaction(handle, ALPM_CALLER_PREFIX, "warning: %s saved as %s\n", filename, newpath); } } - free(newpath); - } else { - /* local file is identical to pkg one, so just remove pkg one */ - unlink(checkfile); - } - } else if(hash_orig) { - /* the fun part */ - - if(hash_local && strcmp(hash_orig, hash_local) == 0) { - /* installed file has NOT been changed by user */ - if(hash_pkg && strcmp(hash_orig, hash_pkg) != 0) { - _alpm_log(handle, ALPM_LOG_DEBUG, "action: installing new file: %s\n", - entryname_orig); - if(try_rename(handle, checkfile, filename)) { - errors++; - } - } else { - /* no sense in installing the same file twice, install - * ONLY if the original and package hashes differ */ - _alpm_log(handle, ALPM_LOG_DEBUG, "action: leaving existing file in place\n"); - unlink(checkfile); - } - } else if(hash_pkg && strcmp(hash_orig, hash_pkg) == 0) { - /* originally installed file and new file are the same - this - * implies the case above failed - i.e. the file was changed by a - * user */ - _alpm_log(handle, ALPM_LOG_DEBUG, "action: leaving existing file in place\n"); - unlink(checkfile); - } else if(hash_local && hash_pkg && strcmp(hash_local, hash_pkg) == 0) { - /* this would be magical. The above two cases failed, but the - * user changes just so happened to make the new file exactly the - * same as the one in the package... skip it */ - _alpm_log(handle, ALPM_LOG_DEBUG, "action: leaving existing file in place\n"); - unlink(checkfile); - } else { - char *newpath; - size_t newlen = strlen(filename) + 8; - _alpm_log(handle, ALPM_LOG_DEBUG, "action: keeping current file and installing" - " new one with .pacnew ending\n"); - MALLOC(newpath, newlen, - errors++; handle->pm_errno = ALPM_ERR_MEMORY; goto needbackup_cleanup); - snprintf(newpath, newlen, "%s.pacnew", filename); - if(try_rename(handle, checkfile, newpath)) { - errors++; - } else { - _alpm_log(handle, ALPM_LOG_WARNING, _("%s installed as %s\n"), - filename, newpath); - alpm_logaction(handle, ALPM_CALLER_PREFIX, - "warning: %s installed as %s\n", filename, newpath); - } free(newpath); } } diff --git a/lib/libalpm/alpm.h b/lib/libalpm/alpm.h index ccbdd1c6..c6d97c59 100644 --- a/lib/libalpm/alpm.h +++ b/lib/libalpm/alpm.h @@ -217,7 +217,6 @@ typedef struct _alpm_file_t { typedef struct _alpm_filelist_t { size_t count; alpm_file_t *files; - char **resolved_path; } alpm_filelist_t; /** Local package or package file backup entry */ @@ -405,10 +404,9 @@ typedef enum _alpm_question_t { ALPM_QUESTION_REPLACE_PKG = (1 << 1), ALPM_QUESTION_CONFLICT_PKG = (1 << 2), ALPM_QUESTION_CORRUPTED_PKG = (1 << 3), - ALPM_QUESTION_LOCAL_NEWER = (1 << 4), - ALPM_QUESTION_REMOVE_PKGS = (1 << 5), - ALPM_QUESTION_SELECT_PROVIDER = (1 << 6), - ALPM_QUESTION_IMPORT_KEY = (1 << 7) + ALPM_QUESTION_REMOVE_PKGS = (1 << 4), + ALPM_QUESTION_SELECT_PROVIDER = (1 << 5), + ALPM_QUESTION_IMPORT_KEY = (1 << 6) } alpm_question_t; /** Question callback */ @@ -1043,7 +1041,7 @@ int alpm_pkg_set_reason(alpm_pkg_t *pkg, alpm_pkgreason_t reason); * @param path the path to search for in the package * @return a pointer to the matching file or NULL if not found */ -char *alpm_filelist_contains(alpm_filelist_t *filelist, const char *path); +alpm_file_t *alpm_filelist_contains(alpm_filelist_t *filelist, const char *path); /* * Signatures @@ -1268,6 +1266,7 @@ typedef enum _alpm_errno_t { ALPM_ERR_PKG_INVALID, ALPM_ERR_PKG_INVALID_CHECKSUM, ALPM_ERR_PKG_INVALID_SIG, + ALPM_ERR_PKG_MISSING_SIG, ALPM_ERR_PKG_OPEN, ALPM_ERR_PKG_CANT_REMOVE, ALPM_ERR_PKG_INVALID_NAME, diff --git a/lib/libalpm/alpm_list.c b/lib/libalpm/alpm_list.c index bcd42b87..59f99f9b 100644 --- a/lib/libalpm/alpm_list.c +++ b/lib/libalpm/alpm_list.c @@ -21,6 +21,10 @@ #include <stdlib.h> #include <string.h> +/* Note: alpm_list.{c,h} are intended to be standalone files. Do not include + * any other libalpm headers. + */ + /* libalpm */ #include "alpm_list.h" diff --git a/lib/libalpm/alpm_list.h b/lib/libalpm/alpm_list.h index 72c73785..3f3566b7 100644 --- a/lib/libalpm/alpm_list.h +++ b/lib/libalpm/alpm_list.h @@ -22,6 +22,10 @@ #include <stdlib.h> /* size_t */ +/* Note: alpm_list.{c,h} are intended to be standalone files. Do not include + * any other libalpm headers. + */ + #ifdef __cplusplus extern "C" { #endif diff --git a/lib/libalpm/be_package.c b/lib/libalpm/be_package.c index cfe5fb36..5a709680 100644 --- a/lib/libalpm/be_package.c +++ b/lib/libalpm/be_package.c @@ -323,9 +323,13 @@ int _alpm_pkg_validate_internal(alpm_handle_t *handle, } /* even if we don't have a sig, run the check code if level tells us to */ - if(has_sig || level & ALPM_SIG_PACKAGE) { + if(level & ALPM_SIG_PACKAGE) { const char *sig = syncpkg ? syncpkg->base64_sig : NULL; _alpm_log(handle, ALPM_LOG_DEBUG, "sig data: %s\n", sig ? sig : "<from .sig>"); + if(!has_sig && !(level & ALPM_SIG_PACKAGE_OPTIONAL)) { + handle->pm_errno = ALPM_ERR_PKG_MISSING_SIG; + return -1; + } if(_alpm_check_pgp_helper(handle, pkgfile, sig, level & ALPM_SIG_PACKAGE_OPTIONAL, level & ALPM_SIG_PACKAGE_MARGINAL_OK, level & ALPM_SIG_PACKAGE_UNKNOWN_OK, sigdata)) { diff --git a/lib/libalpm/conflict.c b/lib/libalpm/conflict.c index 18e29a89..a00efe5c 100644 --- a/lib/libalpm/conflict.c +++ b/lib/libalpm/conflict.c @@ -299,97 +299,73 @@ void _alpm_fileconflict_free(alpm_fileconflict_t *conflict) } /** - * @brief Recursively checks if a package owns all subdirectories and files in - * a directory. + * @brief Recursively checks if a set of packages own all subdirectories and + * files in a directory. * * @param handle the context handle * @param dirpath path of the directory to check - * @param pkg package being checked against + * @param pkgs packages being checked against * - * @return 1 if a package owns all subdirectories and files or a directory - * cannot be opened, 0 otherwise + * @return 1 if a package owns all subdirectories and files, 0 otherwise */ -static int dir_belongsto_pkg(alpm_handle_t *handle, const char *dirpath, - alpm_pkg_t *pkg) +static int dir_belongsto_pkgs(alpm_handle_t *handle, const char *dirpath, + alpm_list_t *pkgs) { - alpm_list_t *i; - struct stat sbuf; - char path[PATH_MAX]; - char abspath[PATH_MAX]; + char path[PATH_MAX], full_path[PATH_MAX]; DIR *dir; struct dirent *ent = NULL; - const char *root = handle->root; - - /* check directory is actually in package - used for subdirectory checks */ - _alpm_filelist_resolve(handle, alpm_pkg_get_files(pkg)); - if(!alpm_filelist_contains(alpm_pkg_get_files(pkg), dirpath)) { - _alpm_log(handle, ALPM_LOG_DEBUG, - "directory %s not in package %s\n", dirpath, pkg->name); - return 0; - } - - /* TODO: this is an overly strict check but currently pacman will not - * overwrite a directory with a file (case 10/11 in add.c). Adjusting that - * is not simple as even if the directory is being unowned by a conflicting - * package, pacman does not sort this to ensure all required directory - * "removals" happen before installation of file/symlink */ - - /* check that no other _installed_ package owns the directory */ - for(i = _alpm_db_get_pkgcache(handle->db_local); i; i = i->next) { - if(pkg == i->data) { - continue; - } - _alpm_filelist_resolve(handle, alpm_pkg_get_files(i->data)); - if(alpm_filelist_contains(alpm_pkg_get_files(i->data), dirpath)) { - _alpm_log(handle, ALPM_LOG_DEBUG, - "file %s also in package %s\n", dirpath, - ((alpm_pkg_t*)i->data)->name); - return 0; - } - } - - /* check all files in directory are owned by the package */ - snprintf(abspath, PATH_MAX, "%s%s", root, dirpath); - dir = opendir(abspath); + snprintf(full_path, PATH_MAX, "%s%s", handle->root, dirpath); + dir = opendir(full_path); if(dir == NULL) { - return 1; + return 0; } while((ent = readdir(dir)) != NULL) { const char *name = ent->d_name; + int owned = 0; + alpm_list_t *i; + struct stat sbuf; if(strcmp(name, ".") == 0 || strcmp(name, "..") == 0) { continue; } + snprintf(path, PATH_MAX, "%s%s", dirpath, name); - snprintf(abspath, PATH_MAX, "%s%s", root, path); - if(stat(abspath, &sbuf) != 0) { - continue; - } - if(S_ISDIR(sbuf.st_mode)) { - if(dir_belongsto_pkg(handle, path, pkg)) { - continue; - } else { - closedir(dir); - return 0; - } - } else { - _alpm_filelist_resolve(handle, alpm_pkg_get_files(pkg)); - if(alpm_filelist_contains(alpm_pkg_get_files(pkg), path)) { - continue; - } else { - closedir(dir); - _alpm_log(handle, ALPM_LOG_DEBUG, - "unowned file %s found in directory\n", path); - return 0; + snprintf(full_path, PATH_MAX, "%s%s", handle->root, path); + + for(i = pkgs; i && !owned; i = i->next) { + if(alpm_filelist_contains(alpm_pkg_get_files(i->data), path)) { + owned = 1; } } + + if(owned && stat(full_path, &sbuf) != 0 && S_ISDIR(sbuf.st_mode)) { + owned = dir_belongsto_pkgs(handle, path, pkgs); + } + + if(!owned) { + closedir(dir); + _alpm_log(handle, ALPM_LOG_DEBUG, + "unowned file %s found in directory\n", path); + return 0; + } } closedir(dir); return 1; } +static alpm_list_t *alpm_db_find_file_owners(alpm_db_t* db, const char *path) +{ + alpm_list_t *i, *owners = NULL; + for(i = alpm_db_get_pkgcache(db); i; i = i->next) { + if(alpm_filelist_contains(alpm_pkg_get_files(i->data), path)) { + owners = alpm_list_add(owners, i->data); + } + } + return owners; +} + /** * @brief Find file conflicts that may occur during the transaction. * @@ -417,11 +393,6 @@ alpm_list_t *_alpm_db_find_fileconflicts(alpm_handle_t *handle, rootlen = strlen(handle->root); - /* make sure all files to be installed have been resolved */ - for(i = upgrade; i; i = i->next) { - _alpm_filelist_resolve(handle, alpm_pkg_get_files(i->data)); - } - /* TODO this whole function needs a huge change, which hopefully will * be possible with real transactions. Right now we only do half as much * here as we do when we actually extract files in add.c with our 12 @@ -491,7 +462,6 @@ alpm_list_t *_alpm_db_find_fileconflicts(alpm_handle_t *handle, * be freed. */ if(dbpkg) { /* older ver of package currently installed */ - _alpm_filelist_resolve(handle, alpm_pkg_get_files(dbpkg)); tmpfiles = _alpm_filelist_difference(alpm_pkg_get_files(p1), alpm_pkg_get_files(dbpkg)); } else { @@ -499,7 +469,7 @@ alpm_list_t *_alpm_db_find_fileconflicts(alpm_handle_t *handle, alpm_filelist_t *fl = alpm_pkg_get_files(p1); size_t filenum; for(filenum = 0; filenum < fl->count; filenum++) { - tmpfiles = alpm_list_add(tmpfiles, fl->resolved_path[filenum]); + tmpfiles = alpm_list_add(tmpfiles, fl->files[filenum].name); } } @@ -514,6 +484,7 @@ alpm_list_t *_alpm_db_find_fileconflicts(alpm_handle_t *handle, size_t pathlen; pathlen = snprintf(path, PATH_MAX, "%s%s", handle->root, filestr); + relative_path = path + rootlen; /* stat the file - if it exists, do some checks */ if(_alpm_lstat(path, &lsbuf) != 0) { @@ -522,30 +493,38 @@ alpm_list_t *_alpm_db_find_fileconflicts(alpm_handle_t *handle, _alpm_log(handle, ALPM_LOG_DEBUG, "checking possible conflict: %s\n", path); - if(filestr[strlen(filestr) - 1] == '/') { - struct stat sbuf; + if(path[pathlen - 1] == '/') { if(S_ISDIR(lsbuf.st_mode)) { _alpm_log(handle, ALPM_LOG_DEBUG, "file is a directory, not a conflict\n"); continue; } - stat(path, &sbuf); - if(S_ISLNK(lsbuf.st_mode) && S_ISDIR(sbuf.st_mode)) { - _alpm_log(handle, ALPM_LOG_DEBUG, - "file is a symlink to a dir, hopefully not a conflict\n"); - continue; - } /* if we made it to here, we want all subsequent path comparisons to * not include the trailing slash. This allows things like file -> * directory replacements. */ path[pathlen - 1] = '\0'; - } - relative_path = path + rootlen; + /* Check if the directory was a file in dbpkg */ + if(alpm_filelist_contains(alpm_pkg_get_files(dbpkg), relative_path)) { + size_t fslen = strlen(filestr); + _alpm_log(handle, ALPM_LOG_DEBUG, + "replacing package file with a directory, not a conflict\n"); + resolved_conflict = 1; + + /* go ahead and skip any files inside filestr as they will + * necessarily be resolved by replacing the file with a dir + * NOTE: afterward, j will point to the last file inside filestr */ + for( ; j->next; j = j->next) { + const char *filestr2 = j->next->data; + if(strncmp(filestr, filestr2, fslen) != 0) { + break; + } + } + } + } /* Check remove list (will we remove the conflicting local file?) */ for(k = rem; k && !resolved_conflict; k = k->next) { alpm_pkg_t *rempkg = k->data; - _alpm_filelist_resolve(handle, alpm_pkg_get_files(rempkg)); if(rempkg && alpm_filelist_contains(alpm_pkg_get_files(rempkg), relative_path)) { _alpm_log(handle, ALPM_LOG_DEBUG, @@ -556,20 +535,21 @@ alpm_list_t *_alpm_db_find_fileconflicts(alpm_handle_t *handle, /* Look at all the targets to see if file has changed hands */ for(k = upgrade; k && !resolved_conflict; k = k->next) { - alpm_pkg_t *p2 = k->data; - if(!p2 || strcmp(p1->name, p2->name) == 0) { + alpm_pkg_t *localp2, *p2 = k->data; + if(!p2 || p1 == p2) { + /* skip p1; both p1 and p2 come directly from the upgrade list + * so they can be compared directly */ continue; } - alpm_pkg_t *localp2 = _alpm_db_get_pkgfromcache(handle->db_local, p2->name); + localp2 = _alpm_db_get_pkgfromcache(handle->db_local, p2->name); /* localp2->files will be removed (target conflicts are handled by CHECK 1) */ - _alpm_filelist_resolve(handle, alpm_pkg_get_files(localp2)); - if(localp2 && alpm_filelist_contains(alpm_pkg_get_files(localp2), filestr)) { + if(localp2 && alpm_filelist_contains(alpm_pkg_get_files(localp2), relative_path)) { /* skip removal of file, but not add. this will prevent a second * package from removing the file when it was already installed * by its new owner (whether the file is in backup array or not */ handle->trans->skip_remove = - alpm_list_add(handle->trans->skip_remove, strdup(filestr)); + alpm_list_add(handle->trans->skip_remove, strdup(relative_path)); _alpm_log(handle, ALPM_LOG_DEBUG, "file changed packages, adding to remove skiplist\n"); resolved_conflict = 1; @@ -577,41 +557,42 @@ alpm_list_t *_alpm_db_find_fileconflicts(alpm_handle_t *handle, } /* check if all files of the dir belong to the installed pkg */ - if(!resolved_conflict && S_ISDIR(lsbuf.st_mode) && dbpkg) { - char *dir = malloc(strlen(filestr) + 2); - sprintf(dir, "%s/", filestr); - if(alpm_filelist_contains(alpm_pkg_get_files(dbpkg), dir)) { - _alpm_log(handle, ALPM_LOG_DEBUG, - "checking if all files in %s belong to %s\n", - dir, dbpkg->name); - resolved_conflict = dir_belongsto_pkg(handle, dir, dbpkg); - } - free(dir); - } + if(!resolved_conflict && S_ISDIR(lsbuf.st_mode)) { + alpm_list_t *owners; + char *dir = malloc(strlen(relative_path) + 2); + sprintf(dir, "%s/", relative_path); + + owners = alpm_db_find_file_owners(handle->db_local, dir); + if(owners) { + alpm_list_t *pkgs = NULL, *diff; - /* check if a component of the filepath was a link. canonicalize the path - * and look for it in the old package. note that the actual file under - * consideration cannot itself be a link, as it might be unowned- path - * components can be safely checked as all directories are "unowned". */ - if(!resolved_conflict && dbpkg && !S_ISLNK(lsbuf.st_mode)) { - char rpath[PATH_MAX]; - if(realpath(path, rpath)) { - const char *relative_rpath = rpath + rootlen; - if(alpm_filelist_contains(alpm_pkg_get_files(dbpkg), relative_rpath)) { + if(dbpkg) { + pkgs = alpm_list_add(pkgs, dbpkg); + } + pkgs = alpm_list_join(pkgs, alpm_list_copy(rem)); + if((diff = alpm_list_diff(owners, pkgs, _alpm_pkg_cmp))) { + /* dir is owned by files we aren't removing */ + /* TODO: with better commit ordering, we may be able to check + * against upgrades as well */ + alpm_list_free(diff); + } else { _alpm_log(handle, ALPM_LOG_DEBUG, - "package contained the resolved realpath\n"); - resolved_conflict = 1; + "checking if all files in %s belong to removed packages\n", + dir); + resolved_conflict = dir_belongsto_pkgs(handle, dir, owners); } + alpm_list_free(pkgs); + alpm_list_free(owners); } + free(dir); } /* is the file unowned and in the backup list of the new package? */ - if(!resolved_conflict && _alpm_needbackup(filestr, p1)) { + if(!resolved_conflict && _alpm_needbackup(relative_path, p1)) { alpm_list_t *local_pkgs = _alpm_db_get_pkgcache(handle->db_local); int found = 0; for(k = local_pkgs; k && !found; k = k->next) { - _alpm_filelist_resolve(handle, alpm_pkg_get_files(k->data)); - if(alpm_filelist_contains(alpm_pkg_get_files(k->data), filestr)) { + if(alpm_filelist_contains(alpm_pkg_get_files(k->data), relative_path)) { found = 1; } } diff --git a/lib/libalpm/error.c b/lib/libalpm/error.c index a59f4fe1..86221807 100644 --- a/lib/libalpm/error.c +++ b/lib/libalpm/error.c @@ -111,6 +111,8 @@ const char SYMEXPORT *alpm_strerror(alpm_errno_t err) return _("invalid or corrupted package (checksum)"); case ALPM_ERR_PKG_INVALID_SIG: return _("invalid or corrupted package (PGP signature)"); + case ALPM_ERR_PKG_MISSING_SIG: + return _("package missing required signature"); case ALPM_ERR_PKG_OPEN: return _("cannot open package file"); case ALPM_ERR_PKG_CANT_REMOVE: diff --git a/lib/libalpm/filelist.c b/lib/libalpm/filelist.c index 697dd23b..f8db9a33 100644 --- a/lib/libalpm/filelist.c +++ b/lib/libalpm/filelist.c @@ -25,199 +25,6 @@ #include "filelist.h" #include "util.h" -/** Helper function for comparing strings when sorting */ -static int _alpm_filelist_strcmp(const void *s1, const void *s2) -{ - return strcmp(*(char **)s1, *(char **)s2); -} - -/* TODO make sure callers check the return value so we can bail on errors. - * For now we soldier on as best we can, skipping paths that are too long to - * resolve and using the original filenames on memory errors. */ -/** - * @brief Resolves a symlink and its children. - * - * @attention Pre-condition: files must be sorted! - * - * @param files filelist to resolve - * @param i pointer to the index in files to start processing, will point to - * the last file processed on return - * @param path absolute path for the symlink being resolved - * @param root_len length of the root portion of path - * @param resolving is file \i in \files a symlink that needs to be resolved - * - * @return 0 on success, -1 on error - */ -int _alpm_filelist_resolve_link(alpm_filelist_t *files, size_t *i, - char *path, size_t root_len, int resolving) -{ - char *causal_dir = NULL; /* symlink being resolved */ - char *filename_r = NULL; /* resolved filename */ - size_t causal_dir_len = 0, causal_dir_r_len = 0; - - if(resolving) { - /* deal with the symlink being resolved */ - MALLOC(filename_r, PATH_MAX, goto error); - causal_dir = files->files[*i].name; - causal_dir_len = strlen(causal_dir); - if(realpath(path, filename_r) == NULL) { - files->resolved_path[*i] = causal_dir; - FREE(filename_r); - return -1; - } - causal_dir_r_len = strlen(filename_r + root_len) + 1; - if(causal_dir_r_len >= PATH_MAX) { - files->resolved_path[*i] = causal_dir; - FREE(filename_r); - return -1; - } - /* remove root_r from filename_r */ - memmove(filename_r, filename_r + root_len, causal_dir_r_len); - filename_r[causal_dir_r_len - 1] = '/'; - filename_r[causal_dir_r_len] = '\0'; - STRDUP(files->resolved_path[*i], filename_r, goto error); - (*i)++; - } - - for(; *i < files->count; (*i)++) { - char *filename = files->files[*i].name; - size_t filename_len = strlen(filename); - size_t filename_r_len = filename_len; - struct stat sbuf; - int exists; - - if(resolving) { - if(filename_len < causal_dir_len || strncmp(filename, causal_dir, causal_dir_len) != 0) { - /* not inside causal_dir anymore */ - break; - } - - filename_r_len = filename_len + causal_dir_r_len - causal_dir_len; - if(filename_r_len >= PATH_MAX) { - /* resolved path is too long */ - files->resolved_path[*i] = filename; - continue; - } - - strcpy(filename_r + causal_dir_r_len, filename + causal_dir_len); - } - - /* deal with files and paths too long to resolve*/ - if(filename[filename_len - 1] != '/' || root_len + filename_r_len >= PATH_MAX) { - if(resolving) { - STRDUP(files->resolved_path[*i], filename_r, goto error); - } else { - files->resolved_path[*i] = filename; - } - continue; - } - - /* construct absolute path and stat() */ - strcpy(path + root_len, resolving ? filename_r : filename); - exists = !_alpm_lstat(path, &sbuf); - - /* deal with symlinks */ - if(exists && S_ISLNK(sbuf.st_mode)) { - _alpm_filelist_resolve_link(files, i, path, root_len, 1); - continue; - } - - /* deal with normal directories */ - if(resolving) { - STRDUP(files->resolved_path[*i], filename_r, goto error); - } else { - files->resolved_path[*i] = filename; - } - - /* deal with children of non-existent directories to reduce lstat() calls */ - if(!exists) { - for((*i)++; *i < files->count; (*i)++) { - char *f = files->files[*i].name; - size_t f_len = strlen(f); - size_t f_r_len; - - if(f_len < filename_len || strncmp(f, filename, filename_len) != 0) { - /* not inside the non-existent dir anymore */ - break; - } - - f_r_len = f_len + causal_dir_r_len - causal_dir_len; - if(resolving && f_r_len <= PATH_MAX) { - strcpy(filename_r + causal_dir_r_len, f + causal_dir_len); - STRDUP(files->resolved_path[*i], filename_r, goto error); - } else { - files->resolved_path[*i] = f; - } - } - (*i)--; - } - } - (*i)--; - - FREE(filename_r); - - return 0; - -error: - FREE(filename_r); - /* out of memory, set remaining files to their original names */ - for(; *i < files->count; (*i)++) { - files->resolved_path[*i] = files->files[*i].name; - } - (*i)--; - return -1; -} - -/** - * @brief Takes a file list and resolves all directory paths according to the - * filesystem - * - * @attention Pre-condition: files must be sorted! - * - * @note A symlink and directory at the same path in two difference packages - * causes a conflict so the filepath can not change as packages get installed - * - * @param handle the context handle - * @param files list of files to resolve - * - * @return 0 on success, -1 on error - */ -int _alpm_filelist_resolve(alpm_handle_t *handle, alpm_filelist_t *files) -{ - char path[PATH_MAX]; - size_t root_len, i = 0; - int ret = 0; - - if(!files || files->resolved_path) { - return 0; - } - - CALLOC(files->resolved_path, files->count, sizeof(char *), return -1); - - /* not much point in going on if we can't even resolve root */ - if(realpath(handle->root, path) == NULL){ - return -1; - } - root_len = strlen(path); - if(root_len + 1 >= PATH_MAX) { - return -1; - } - /* append '/' if root is not "/" */ - if(path[root_len - 1] != '/') { - path[root_len] = '/'; - root_len++; - path[root_len] = '\0'; - } - - ret = _alpm_filelist_resolve_link(files, &i, path, root_len, 0); - - qsort(files->resolved_path, files->count, sizeof(char *), - _alpm_filelist_strcmp); - - return ret; -} - - /* Returns the difference of the provided two lists of files. * Pre-condition: both lists are sorted! * When done, free the list but NOT the contained data. @@ -229,8 +36,8 @@ alpm_list_t *_alpm_filelist_difference(alpm_filelist_t *filesA, size_t ctrA = 0, ctrB = 0; while(ctrA < filesA->count && ctrB < filesB->count) { - char *strA = filesA->resolved_path[ctrA]; - char *strB = filesB->resolved_path[ctrB]; + char *strA = filesA->files[ctrA].name; + char *strB = filesB->files[ctrB].name; int cmp = strcmp(strA, strB); if(cmp < 0) { @@ -247,7 +54,7 @@ alpm_list_t *_alpm_filelist_difference(alpm_filelist_t *filesA, /* ensure we have completely emptied pA */ while(ctrA < filesA->count) { - ret = alpm_list_add(ret, filesA->resolved_path[ctrA]); + ret = alpm_list_add(ret, filesA->files[ctrA].name); ctrA++; } @@ -269,17 +76,17 @@ alpm_list_t *_alpm_filelist_intersection(alpm_filelist_t *filesA, char *strA, *strB; isdirA = 0; - strA = filesA->resolved_path[ctrA]; + strA = filesA->files[ctrA].name; if(strA[strlen(strA)-1] == '/') { isdirA = 1; - strA = strndup(filesA->resolved_path[ctrA], strlen(strA)-1); + strA = strndup(strA, strlen(strA)-1); } isdirB = 0; - strB = filesB->resolved_path[ctrB]; + strB = filesB->files[ctrB].name; if(strB[strlen(strB)-1] == '/') { isdirB = 1; - strB = strndup(filesB->resolved_path[ctrB], strlen(strB)-1); + strB = strndup(strB, strlen(strB)-1); } cmp = strcmp(strA, strB); @@ -297,7 +104,7 @@ alpm_list_t *_alpm_filelist_intersection(alpm_filelist_t *filesA, /* when not directories, item in both qualifies as an intersect */ if(! (isdirA && isdirB)) { - ret = alpm_list_add(ret, filesA->resolved_path[ctrA]); + ret = alpm_list_add(ret, filesA->files[ctrA].name); } ctrA++; ctrB++; @@ -323,11 +130,10 @@ int _alpm_files_cmp(const void *f1, const void *f2) return strcmp(file1->name, file2->name); } - -char SYMEXPORT *alpm_filelist_contains(alpm_filelist_t *filelist, +alpm_file_t SYMEXPORT *alpm_filelist_contains(alpm_filelist_t *filelist, const char *path) { - alpm_file_t key, *match; + alpm_file_t key; if(!filelist) { return NULL; @@ -335,17 +141,8 @@ char SYMEXPORT *alpm_filelist_contains(alpm_filelist_t *filelist, key.name = (char *)path; - match = bsearch(&key, filelist->files, filelist->count, + return bsearch(&key, filelist->files, filelist->count, sizeof(alpm_file_t), _alpm_files_cmp); - - if(match) { - return match->name; - } else if(filelist->resolved_path) { - return bsearch(&path, filelist->resolved_path, filelist->count, - sizeof(char *), _alpm_filelist_strcmp); - } else { - return NULL; - } } /* vim: set ts=2 sw=2 noet: */ diff --git a/lib/libalpm/filelist.h b/lib/libalpm/filelist.h index bfab4165..66501f36 100644 --- a/lib/libalpm/filelist.h +++ b/lib/libalpm/filelist.h @@ -21,10 +21,6 @@ #include "alpm.h" -int _alpm_filelist_resolve_link(alpm_filelist_t *files, size_t *i, - char *path, size_t root_len, int resolving); -int _alpm_filelist_resolve(alpm_handle_t *handle, alpm_filelist_t *files); - alpm_list_t *_alpm_filelist_difference(alpm_filelist_t *filesA, alpm_filelist_t *filesB); diff --git a/lib/libalpm/package.c b/lib/libalpm/package.c index 098c8677..cfdbb3f8 100644 --- a/lib/libalpm/package.c +++ b/lib/libalpm/package.c @@ -606,9 +606,6 @@ int _alpm_pkg_dup(alpm_pkg_t *pkg, alpm_pkg_t **new_ptr) } } newpkg->files.count = pkg->files.count; - /* deliberately do not copy resolved_path as this is only used - * during conflict checking and the sorting of list does not readily - * allow keeping its efficient memory usage when copying */ } /* internal */ @@ -657,22 +654,9 @@ void _alpm_pkg_free(alpm_pkg_t *pkg) free_deplist(pkg->replaces); FREELIST(pkg->groups); if(pkg->files.count) { - size_t i, j, k; - if(pkg->files.resolved_path) { - for(i = 0, j = 0; i < pkg->files.count; i++) { - for(k = j; k <= pkg->files.count; k++) { - if(pkg->files.resolved_path[i] == pkg->files.files[k].name) { - pkg->files.files[k].name = NULL; - j = k + 1; - break; - } - } - free(pkg->files.resolved_path[i]); - } - free(pkg->files.resolved_path); - } - for(j = 0; j < pkg->files.count; j++) { - FREE(pkg->files.files[j].name); + size_t i; + for(i = 0; i < pkg->files.count; i++) { + FREE(pkg->files.files[i].name); } free(pkg->files.files); } diff --git a/lib/libalpm/remove.c b/lib/libalpm/remove.c index d0cd613c..0b4f80cd 100644 --- a/lib/libalpm/remove.c +++ b/lib/libalpm/remove.c @@ -442,11 +442,7 @@ static int unlink_file(alpm_handle_t *handle, alpm_pkg_t *oldpkg, return 1; } - /* we want to do a lstat here, and not a _alpm_lstat. - * if a directory in the package is actually a directory symlink on the - * filesystem, we want to work with the linked directory instead of the - * actual symlink */ - if(lstat(file, &buf)) { + if(_alpm_lstat(file, &buf)) { _alpm_log(handle, ALPM_LOG_DEBUG, "file %s does not exist\n", file); return 1; } @@ -462,7 +458,6 @@ static int unlink_file(alpm_handle_t *handle, alpm_pkg_t *oldpkg, "keeping directory %s (could not count files)\n", file); } else if(newpkg && alpm_filelist_contains(alpm_pkg_get_files(newpkg), fileobj->name)) { - /* newpkg's filelist should have already been resolved by the caller */ _alpm_log(handle, ALPM_LOG_DEBUG, "keeping directory %s (in new package)\n", file); } else if(dir_is_mountpoint(handle, file, &buf)) { @@ -484,9 +479,6 @@ static int unlink_file(alpm_handle_t *handle, alpm_pkg_t *oldpkg, continue; } filelist = alpm_pkg_get_files(local_pkg); - /* This is too slow and only covers a rare case - Disable for now... */ - /* _alpm_filelist_resolve(handle, filelist); */ if(alpm_filelist_contains(filelist, fileobj->name)) { _alpm_log(handle, ALPM_LOG_DEBUG, "keeping directory %s (owned by %s)\n", file, local_pkg->name); @@ -584,7 +576,6 @@ static int remove_package_files(alpm_handle_t *handle, * so this removal operation doesn't kill them */ /* old package backup list */ newfiles = alpm_pkg_get_files(newpkg); - _alpm_filelist_resolve(handle, newfiles); for(b = alpm_pkg_get_backup(newpkg); b; b = b->next) { const alpm_backup_t *backup = b->data; /* safety check (fix the upgrade026 pactest) */ |