summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/libalpm/add.c173
-rw-r--r--lib/libalpm/alpm.h11
-rw-r--r--lib/libalpm/be_package.c6
-rw-r--r--lib/libalpm/conflict.c209
-rw-r--r--lib/libalpm/error.c2
-rw-r--r--lib/libalpm/filelist.c225
-rw-r--r--lib/libalpm/filelist.h4
-rw-r--r--lib/libalpm/package.c22
-rw-r--r--lib/libalpm/remove.c11
9 files changed, 196 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/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) */