diff --git a/lib/libalpm/alpm.h b/lib/libalpm/alpm.h index 76564271..88aef37f 100644 --- a/lib/libalpm/alpm.h +++ b/lib/libalpm/alpm.h @@ -160,6 +160,13 @@ typedef struct _alpm_delta_t { off_t download_size; } alpm_delta_t; +/** File in a package */ +typedef struct _alpm_file_t { + char *name; + off_t size; + mode_t mode; +} alpm_file_t; + /** Local package or package file backup entry */ typedef struct _alpm_backup_t { char *name; diff --git a/lib/libalpm/be_local.c b/lib/libalpm/be_local.c index 65579673..f1056d40 100644 --- a/lib/libalpm/be_local.c +++ b/lib/libalpm/be_local.c @@ -632,9 +632,11 @@ static int local_db_read(alpm_pkg_t *info, alpm_dbinfrq_t inforeq) _alpm_strtrim(line); if(strcmp(line, "%FILES%") == 0) { while(fgets(line, sizeof(line), fp) && strlen(_alpm_strtrim(line))) { - char *linedup; - STRDUP(linedup, line, goto error); - info->files = alpm_list_add(info->files, linedup); + alpm_file_t *file; + CALLOC(file, 1, sizeof(alpm_file_t), goto error); + STRDUP(file->name, line, goto error); + /* TODO: lstat file, get mode/size */ + info->files = alpm_list_add(info->files, file); } } else if(strcmp(line, "%BACKUP%") == 0) { while(fgets(line, sizeof(line), fp) && strlen(_alpm_strtrim(line))) { @@ -835,14 +837,15 @@ int _alpm_local_db_write(alpm_db_t *db, alpm_pkg_t *info, alpm_dbinfrq_t inforeq if(info->files) { fprintf(fp, "%%FILES%%\n"); for(lp = info->files; lp; lp = lp->next) { - fprintf(fp, "%s\n", (char *)lp->data); + const alpm_file_t *file = lp->data; + fprintf(fp, "%s\n", file->name); } fprintf(fp, "\n"); } if(info->backup) { fprintf(fp, "%%BACKUP%%\n"); for(lp = info->backup; lp; lp = lp->next) { - alpm_backup_t *backup = lp->data; + const alpm_backup_t *backup = lp->data; fprintf(fp, "%s\t%s\n", backup->name, backup->hash); } fprintf(fp, "\n"); diff --git a/lib/libalpm/be_package.c b/lib/libalpm/be_package.c index a4c6c559..da5076e5 100644 --- a/lib/libalpm/be_package.c +++ b/lib/libalpm/be_package.c @@ -328,7 +328,12 @@ alpm_pkg_t *_alpm_pkg_load_internal(alpm_handle_t *handle, const char *pkgfile, * already been handled (for future possibilities) */ } else if(full) { /* Keep track of all files for filelist generation */ - newpkg->files = alpm_list_add(newpkg->files, strdup(entry_name)); + alpm_file_t *file; + CALLOC(file, 1, sizeof(alpm_file_t), goto error); + STRDUP(file->name, entry_name, goto error); + file->size = archive_entry_size(entry); + file->mode = archive_entry_mode(entry); + newpkg->files = alpm_list_add(newpkg->files, file); files_count++; } @@ -368,11 +373,14 @@ alpm_pkg_t *_alpm_pkg_load_internal(alpm_handle_t *handle, const char *pkgfile, if(full) { /* "checking for conflicts" requires a sorted list, ensure that here */ _alpm_log(handle, PM_LOG_DEBUG, "sorting package filelist for %s\n", pkgfile); - newpkg->files = alpm_list_msort(newpkg->files, files_count, _alpm_str_cmp); + newpkg->files = alpm_list_msort(newpkg->files, files_count, + _alpm_files_cmp); newpkg->infolevel = INFRQ_ALL; } else { /* get rid of any partial filelist we may have collected, it is invalid */ - FREELIST(newpkg->files); + alpm_list_free_inner(newpkg->files, (alpm_list_fn_free)_alpm_files_free); + alpm_list_free(newpkg->files); + newpkg->files = NULL; newpkg->infolevel = INFRQ_BASE | INFRQ_DESC; } diff --git a/lib/libalpm/conflict.c b/lib/libalpm/conflict.c index 5d9bbf23..6ed9981e 100644 --- a/lib/libalpm/conflict.c +++ b/lib/libalpm/conflict.c @@ -34,6 +34,7 @@ /* libalpm */ #include "conflict.h" #include "alpm_list.h" +#include "alpm.h" #include "handle.h" #include "trans.h" #include "util.h" @@ -222,6 +223,7 @@ static const int DIFFERENCE = 0; static const int INTERSECT = 1; /* Returns a set operation on the provided two lists of files. * Pre-condition: both lists are sorted! + * When done, free the list but NOT the contained data. * * Operations: * DIFFERENCE - a difference operation is performed. filesA - filesB. @@ -234,8 +236,10 @@ static alpm_list_t *filelist_operation(alpm_list_t *filesA, alpm_list_t *filesB, alpm_list_t *pA = filesA, *pB = filesB; while(pA && pB) { - const char *strA = pA->data; - const char *strB = pB->data; + alpm_file_t *fileA = pA->data; + alpm_file_t *fileB = pB->data; + const char *strA = fileA->name; + const char *strB = fileB->name; /* skip directories, we don't care about them */ if(strA[strlen(strA)-1] == '/') { pA = pA->next; @@ -246,7 +250,7 @@ static alpm_list_t *filelist_operation(alpm_list_t *filesA, alpm_list_t *filesB, if(cmp < 0) { if(operation == DIFFERENCE) { /* item only in filesA, qualifies as a difference */ - ret = alpm_list_add(ret, strdup(strA)); + ret = alpm_list_add(ret, fileA); } pA = pA->next; } else if(cmp > 0) { @@ -254,7 +258,7 @@ static alpm_list_t *filelist_operation(alpm_list_t *filesA, alpm_list_t *filesB, } else { if(operation == INTERSECT) { /* item in both, qualifies as an intersect */ - ret = alpm_list_add(ret, strdup(strA)); + ret = alpm_list_add(ret, fileA); } pA = pA->next; pB = pB->next; @@ -264,10 +268,11 @@ static alpm_list_t *filelist_operation(alpm_list_t *filesA, alpm_list_t *filesB, /* if doing a difference, ensure we have completely emptied pA */ while(operation == DIFFERENCE && pA) { - const char *strA = pA->data; + alpm_file_t *fileA = pA->data; + const char *strA = fileA->name; /* skip directories */ if(strA[strlen(strA)-1] != '/') { - ret = alpm_list_add(ret, strdup(strA)); + ret = alpm_list_add(ret, fileA); } pA = pA->next; } @@ -314,13 +319,27 @@ void _alpm_fileconflict_free(alpm_fileconflict_t *conflict) FREE(conflict); } +const alpm_file_t *_alpm_filelist_contains(const alpm_list_t *haystack, + const char *needle) +{ + const alpm_list_t *lp = haystack; + while(lp) { + const alpm_file_t *file = lp->data; + if(strcmp(file->name, needle) == 0) { + return file; + } + lp = lp->next; + } + return NULL; +} + static int dir_belongsto_pkg(const char *root, const char *dirpath, alpm_pkg_t *pkg) { - struct dirent *ent = NULL; struct stat sbuf; char path[PATH_MAX]; char abspath[PATH_MAX]; + struct dirent *ent = NULL; DIR *dir; snprintf(abspath, PATH_MAX, "%s%s", root, dirpath); @@ -328,6 +347,7 @@ static int dir_belongsto_pkg(const char *root, const char *dirpath, if(dir == NULL) { return 1; } + while((ent = readdir(dir)) != NULL) { const char *name = ent->d_name; @@ -347,7 +367,7 @@ static int dir_belongsto_pkg(const char *root, const char *dirpath, return 0; } } else { - if(alpm_list_find_str(alpm_pkg_get_files(pkg), path)) { + if(_alpm_filelist_contains(alpm_pkg_get_files(pkg), path)) { continue; } else { closedir(dir); @@ -415,7 +435,7 @@ alpm_list_t *_alpm_db_find_fileconflicts(alpm_handle_t *handle, return NULL; } } - FREELIST(common_files); + alpm_list_free(common_files); } } @@ -440,7 +460,9 @@ alpm_list_t *_alpm_db_find_fileconflicts(alpm_handle_t *handle, for(j = tmpfiles; j; j = j->next) { struct stat lsbuf; - const char *filestr = j->data, *relative_path; + alpm_file_t *file = j->data; + const char *filestr = file->name; + const char *relative_path; /* have we acted on this conflict? */ int resolved_conflict = 0; @@ -475,7 +497,8 @@ alpm_list_t *_alpm_db_find_fileconflicts(alpm_handle_t *handle, /* Check remove list (will we remove the conflicting local file?) */ for(k = remove; k && !resolved_conflict; k = k->next) { alpm_pkg_t *rempkg = k->data; - if(alpm_list_find_str(alpm_pkg_get_files(rempkg), relative_path)) { + if(rempkg && _alpm_filelist_contains(alpm_pkg_get_files(rempkg), + relative_path)) { _alpm_log(handle, PM_LOG_DEBUG, "local file will be removed, not a conflict: %s\n", relative_path); @@ -492,7 +515,7 @@ alpm_list_t *_alpm_db_find_fileconflicts(alpm_handle_t *handle, alpm_pkg_t *localp2 = _alpm_db_get_pkgfromcache(handle->db_local, p2->name); /* localp2->files will be removed (target conflicts are handled by CHECK 1) */ - if(localp2 && alpm_list_find_str(alpm_pkg_get_files(localp2), filestr)) { + if(localp2 && _alpm_filelist_contains(alpm_pkg_get_files(localp2), filestr)) { /* 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 */ @@ -509,7 +532,7 @@ alpm_list_t *_alpm_db_find_fileconflicts(alpm_handle_t *handle, if(!resolved_conflict && S_ISDIR(lsbuf.st_mode) && dbpkg) { char *dir = malloc(strlen(filestr) + 2); sprintf(dir, "%s/", filestr); - if(alpm_list_find_str(alpm_pkg_get_files(dbpkg),dir)) { + if(_alpm_filelist_contains(alpm_pkg_get_files(dbpkg), dir)) { _alpm_log(handle, PM_LOG_DEBUG, "check if all files in %s belongs to %s\n", dir, dbpkg->name); @@ -526,7 +549,7 @@ alpm_list_t *_alpm_db_find_fileconflicts(alpm_handle_t *handle, continue; } relative_rpath = rpath + strlen(handle->root); - if(alpm_list_find_str(alpm_pkg_get_files(dbpkg), relative_rpath)) { + if(_alpm_filelist_contains(alpm_pkg_get_files(dbpkg), relative_rpath)) { resolved_conflict = 1; } free(rpath); @@ -539,7 +562,7 @@ alpm_list_t *_alpm_db_find_fileconflicts(alpm_handle_t *handle, FREELIST(conflicts); if(dbpkg) { /* only freed if it was generated from filelist_operation() */ - FREELIST(tmpfiles); + alpm_list_free(tmpfiles); } return NULL; } @@ -547,7 +570,7 @@ alpm_list_t *_alpm_db_find_fileconflicts(alpm_handle_t *handle, } if(dbpkg) { /* only freed if it was generated from filelist_operation() */ - FREELIST(tmpfiles); + alpm_list_free(tmpfiles); } } PROGRESS(trans, PM_TRANS_PROGRESS_CONFLICTS_START, "", 100, diff --git a/lib/libalpm/conflict.h b/lib/libalpm/conflict.h index 6c13cb28..f2ab6258 100644 --- a/lib/libalpm/conflict.h +++ b/lib/libalpm/conflict.h @@ -33,6 +33,9 @@ alpm_list_t *_alpm_db_find_fileconflicts(alpm_handle_t *handle, void _alpm_fileconflict_free(alpm_fileconflict_t *conflict); +const alpm_file_t *_alpm_filelist_contains(const alpm_list_t *haystack, + const char *needle); + #endif /* _ALPM_CONFLICT_H */ /* vim: set ts=2 sw=2 noet: */ diff --git a/lib/libalpm/diskspace.c b/lib/libalpm/diskspace.c index 7ca72c3c..5fb36eb4 100644 --- a/lib/libalpm/diskspace.c +++ b/lib/libalpm/diskspace.c @@ -151,14 +151,15 @@ static alpm_mountpoint_t *match_mount_point(const alpm_list_t *mount_points, static int calculate_removed_size(alpm_handle_t *handle, const alpm_list_t *mount_points, alpm_pkg_t *pkg) { - alpm_list_t *file; + alpm_list_t *i; alpm_list_t *files = alpm_pkg_get_files(pkg); - for(file = files; file; file = file->next) { + for(i = files; i; i = i->next) { alpm_mountpoint_t *mp; struct stat st; char path[PATH_MAX]; - const char *filename = file->data; + const alpm_file_t *file = i->data; + const char *filename = file->name; snprintf(path, PATH_MAX, "%s%s", handle->root, filename); _alpm_lstat(path, &st); diff --git a/lib/libalpm/package.c b/lib/libalpm/package.c index 21984b37..f69ba0b3 100644 --- a/lib/libalpm/package.c +++ b/lib/libalpm/package.c @@ -427,6 +427,33 @@ alpm_list_t SYMEXPORT *alpm_pkg_compute_requiredby(alpm_pkg_t *pkg) /** @} */ +void _alpm_files_free(alpm_file_t *file) +{ + free(file->name); + free(file); +} + +alpm_file_t *_alpm_files_dup(const alpm_file_t *file) +{ + alpm_file_t *newfile; + CALLOC(newfile, 1, sizeof(alpm_file_t), return NULL); + + STRDUP(newfile->name, file->name, return NULL); + newfile->size = file->size; + newfile->mode = file->mode; + + return newfile; +} + +/* Helper function for comparing files list entries + */ +int _alpm_files_cmp(const void *f1, const void *f2) +{ + const alpm_file_t *file1 = f1; + const alpm_file_t *file2 = f2; + return strcmp(file1->name, file2->name); +} + alpm_pkg_t *_alpm_pkg_new(void) { alpm_pkg_t* pkg; @@ -466,7 +493,9 @@ alpm_pkg_t *_alpm_pkg_dup(alpm_pkg_t *pkg) newpkg->licenses = alpm_list_strdup(pkg->licenses); newpkg->replaces = alpm_list_strdup(pkg->replaces); newpkg->groups = alpm_list_strdup(pkg->groups); - newpkg->files = alpm_list_strdup(pkg->files); + for(i = pkg->files; i; i = alpm_list_next(i)) { + newpkg->files = alpm_list_add(newpkg->files, _alpm_files_dup(i->data)); + } for(i = pkg->backup; i; i = alpm_list_next(i)) { newpkg->backup = alpm_list_add(newpkg->backup, _alpm_backup_dup(i->data)); } @@ -516,7 +545,8 @@ void _alpm_pkg_free(alpm_pkg_t *pkg) FREELIST(pkg->licenses); FREELIST(pkg->replaces); FREELIST(pkg->groups); - FREELIST(pkg->files); + alpm_list_free_inner(pkg->files, (alpm_list_fn_free)_alpm_files_free); + alpm_list_free(pkg->files); alpm_list_free_inner(pkg->backup, (alpm_list_fn_free)_alpm_backup_free); alpm_list_free(pkg->backup); alpm_list_free_inner(pkg->depends, (alpm_list_fn_free)_alpm_dep_free); @@ -566,8 +596,8 @@ int _alpm_pkg_compare_versions(alpm_pkg_t *spkg, alpm_pkg_t *localpkg) */ int _alpm_pkg_cmp(const void *p1, const void *p2) { - alpm_pkg_t *pkg1 = (alpm_pkg_t *)p1; - alpm_pkg_t *pkg2 = (alpm_pkg_t *)p2; + const alpm_pkg_t *pkg1 = p1; + const alpm_pkg_t *pkg2 = p2; return strcoll(pkg1->name, pkg2->name); } diff --git a/lib/libalpm/package.h b/lib/libalpm/package.h index 772c2f62..b6021939 100644 --- a/lib/libalpm/package.h +++ b/lib/libalpm/package.h @@ -139,6 +139,10 @@ struct __alpm_pkg_t { struct pkg_operations *ops; }; +void _alpm_files_free(alpm_file_t *file); +alpm_file_t *_alpm_files_dup(const alpm_file_t *file); +int _alpm_files_cmp(const void *f1, const void *f2); + alpm_pkg_t* _alpm_pkg_new(void); alpm_pkg_t *_alpm_pkg_dup(alpm_pkg_t *pkg); void _alpm_pkg_free(alpm_pkg_t *pkg); diff --git a/lib/libalpm/remove.c b/lib/libalpm/remove.c index 48adf045..d967780c 100644 --- a/lib/libalpm/remove.c +++ b/lib/libalpm/remove.c @@ -43,6 +43,7 @@ #include "db.h" #include "deps.h" #include "handle.h" +#include "conflict.h" int SYMEXPORT alpm_remove_pkg(alpm_handle_t *handle, alpm_pkg_t *pkg) { @@ -191,25 +192,25 @@ int _alpm_remove_prepare(alpm_handle_t *handle, alpm_list_t **data) return 0; } -static int can_remove_file(alpm_handle_t *handle, const char *path, +static int can_remove_file(alpm_handle_t *handle, const alpm_file_t *file, alpm_list_t *skip_remove) { - char file[PATH_MAX]; + char filepath[PATH_MAX]; - snprintf(file, PATH_MAX, "%s%s", handle->root, path); + snprintf(filepath, PATH_MAX, "%s%s", handle->root, file->name); - if(alpm_list_find_str(skip_remove, file)) { + if(alpm_list_find_str(skip_remove, filepath)) { /* return success because we will never actually remove this file */ 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(errno != EACCES && errno != ETXTBSY && access(file, F_OK) == 0) { + if(access(filepath, W_OK) == -1) { + if(errno != EACCES && errno != ETXTBSY && access(filepath, F_OK) == 0) { /* only return failure if the file ACTUALLY exists and we can't write to * it - ignore "chmod -w" simple permission failures */ _alpm_log(handle, PM_LOG_ERROR, _("cannot remove file '%s': %s\n"), - file, strerror(errno)); + filepath, strerror(errno)); return 0; } } @@ -219,18 +220,18 @@ static int can_remove_file(alpm_handle_t *handle, const char *path, /* Helper function for iterating through a package's file and deleting them * Used by _alpm_remove_commit. */ -static void unlink_file(alpm_handle_t *handle, alpm_pkg_t *info, const char *filename, - alpm_list_t *skip_remove, int nosave) +static void unlink_file(alpm_handle_t *handle, alpm_pkg_t *info, + const alpm_file_t *fileobj, alpm_list_t *skip_remove, int nosave) { struct stat buf; char file[PATH_MAX]; - snprintf(file, PATH_MAX, "%s%s", handle->root, filename); + snprintf(file, PATH_MAX, "%s%s", handle->root, fileobj->name); /* check the remove skip list before removing the file. * see the big comment block in db_find_fileconflicts() for an * explanation. */ - if(alpm_list_find_str(skip_remove, filename)) { + if(alpm_list_find_str(skip_remove, fileobj->name)) { _alpm_log(handle, PM_LOG_DEBUG, "%s is in skip_remove, skipping removal\n", file); return; @@ -254,7 +255,7 @@ static void unlink_file(alpm_handle_t *handle, alpm_pkg_t *info, const char *fil } } else { /* if the file needs backup and has been modified, back it up to .pacsave */ - alpm_backup_t *backup = _alpm_needbackup(filename, alpm_pkg_get_backup(info)); + alpm_backup_t *backup = _alpm_needbackup(fileobj->name, alpm_pkg_get_backup(info)); if(backup) { if(nosave) { _alpm_log(handle, PM_LOG_DEBUG, "transaction is set to NOSAVE, not backing up '%s'\n", file); @@ -277,7 +278,7 @@ static void unlink_file(alpm_handle_t *handle, alpm_pkg_t *info, const char *fil if(unlink(file) == -1) { _alpm_log(handle, PM_LOG_ERROR, _("cannot remove file '%s': %s\n"), - filename, strerror(errno)); + file, strerror(errno)); } } } @@ -308,7 +309,7 @@ int _alpm_upgraderemove_package(alpm_handle_t *handle, for(b = alpm_pkg_get_backup(newpkg); b; b = b->next) { const alpm_backup_t *backup = b->data; /* safety check (fix the upgrade026 pactest) */ - if(!alpm_list_find_str(filelist, backup->name)) { + if(!_alpm_filelist_contains(filelist, backup->name)) { continue; } _alpm_log(handle, PM_LOG_DEBUG, "adding %s to the skip_remove array\n", diff --git a/src/pacman/package.c b/src/pacman/package.c index 6b480873..c394bf9a 100644 --- a/src/pacman/package.c +++ b/src/pacman/package.c @@ -218,7 +218,7 @@ void dump_pkg_backups(alpm_pkg_t *pkg) */ void dump_pkg_files(alpm_pkg_t *pkg, int quiet) { - const char *pkgname, *root, *filestr; + const char *pkgname, *root; alpm_list_t *i, *pkgfiles; pkgname = alpm_pkg_get_name(pkg); @@ -226,11 +226,11 @@ void dump_pkg_files(alpm_pkg_t *pkg, int quiet) root = alpm_option_get_root(config->handle); for(i = pkgfiles; i; i = alpm_list_next(i)) { - filestr = alpm_list_getdata(i); + const alpm_file_t *file = alpm_list_getdata(i); if(!quiet){ - fprintf(stdout, "%s %s%s\n", pkgname, root, filestr); + fprintf(stdout, "%s %s%s\n", pkgname, root, file->name); } else { - fprintf(stdout, "%s%s\n", root, filestr); + fprintf(stdout, "%s%s\n", root, file->name); } } diff --git a/src/pacman/query.c b/src/pacman/query.c index 826c2262..1547c247 100644 --- a/src/pacman/query.c +++ b/src/pacman/query.c @@ -193,7 +193,8 @@ static int query_fileowner(alpm_list_t *targets) for(j = alpm_pkg_get_files(info); j && !found; j = alpm_list_next(j)) { char *ppath, *pdname; - const char *pkgfile = alpm_list_getdata(j); + const alpm_file_t *file = alpm_list_getdata(j); + const char *pkgfile = file->name; /* avoid the costly resolve_path usage if the basenames don't match */ if(strcmp(mbasename(pkgfile), bname) != 0) { @@ -416,7 +417,8 @@ static int check(alpm_pkg_t *pkg) const char *pkgname = alpm_pkg_get_name(pkg); for(i = alpm_pkg_get_files(pkg); i; i = alpm_list_next(i)) { struct stat st; - const char *path = alpm_list_getdata(i); + const alpm_file_t *file = alpm_list_getdata(i); + const char *path = file->name; if(rootlen + 1 + strlen(path) > PATH_MAX) { pm_fprintf(stderr, PM_LOG_WARNING, _("path too long: %s%s\n"), root, path);