static PyObject* pyalpm_package_get_files(AlpmPackage *self, void *closure) { const alpm_filelist_t *flist = NULL; PyObject *result = NULL; CHECK_IF_INITIALIZED(); flist = alpm_pkg_get_files(self->c_data); if (!flist) Py_RETURN_NONE; else { ssize_t i; result = PyList_New((Py_ssize_t)flist->count); for (i = 0; i < (ssize_t)flist->count; i++) { const alpm_file_t *file = flist->files + i; PyObject *filename = PyUnicode_DecodeFSDefault(file->name); PyObject *filesize = PyLong_FromLongLong(file->size); PyObject *filemode = PyLong_FromUnsignedLong(file->mode); PyObject *item = PyTuple_New(3); if (item && filename && filesize && filemode) { PyTuple_SET_ITEM(item, 0, filename); PyTuple_SET_ITEM(item, 1, filesize); PyTuple_SET_ITEM(item, 2, filemode); PyList_SET_ITEM(result, i, item); } else { Py_CLEAR(item); Py_CLEAR(filename); Py_CLEAR(filesize); Py_CLEAR(filemode); return NULL; } } } return result; }
static int calculate_removed_size(alpm_handle_t *handle, const alpm_list_t *mount_points, alpm_pkg_t *pkg) { size_t i; alpm_filelist_t *filelist = alpm_pkg_get_files(pkg); if(!filelist->count) { return 0; } for(i = 0; i < filelist->count; i++) { const alpm_file_t *file = filelist->files + i; alpm_mountpoint_t *mp; struct stat st; char path[PATH_MAX]; blkcnt_t remove_size; const char *filename = file->name; snprintf(path, PATH_MAX, "%s%s", handle->root, filename); if(llstat(path, &st) == -1) { _alpm_log(handle, ALPM_LOG_WARNING, _("could not get file information for %s\n"), filename); continue; } /* skip directories and symlinks to be consistent with libarchive that * reports them to be zero size */ if(S_ISDIR(st.st_mode) || S_ISLNK(st.st_mode)) { continue; } mp = match_mount_point(mount_points, path); if(mp == NULL) { _alpm_log(handle, ALPM_LOG_WARNING, _("could not determine mount point for file %s\n"), filename); continue; } /* don't check a mount that we know we can't stat */ if(mp && mp->fsinfo_loaded == MOUNT_FSINFO_FAIL) { continue; } /* lazy load filesystem info */ if(mp->fsinfo_loaded == MOUNT_FSINFO_UNLOADED) { if(mount_point_load_fsinfo(handle, mp) < 0) { continue; } } /* the addition of (divisor - 1) performs ceil() with integer division */ remove_size = (st.st_size + mp->fsp.f_bsize - 1) / mp->fsp.f_bsize; mp->blocks_needed -= remove_size; mp->used |= USED_REMOVE; } return 0; }
static void dump_pkg_machinereadable(alpm_db_t *db, alpm_pkg_t *pkg) { alpm_filelist_t *pkgfiles = alpm_pkg_get_files(pkg); for(size_t filenum = 0; filenum < pkgfiles->count; filenum++) { const alpm_file_t *file = pkgfiles->files + filenum; print_line_machinereadable(db, pkg, file->name); } }
static int calculate_installed_size(alpm_handle_t *handle, const alpm_list_t *mount_points, alpm_pkg_t *pkg) { size_t i; alpm_filelist_t *filelist = alpm_pkg_get_files(pkg); if(!filelist->count) { return 0; } for(i = 0; i < filelist->count; i++) { const alpm_file_t *file = filelist->files + i; alpm_mountpoint_t *mp; char path[PATH_MAX]; blkcnt_t install_size; const char *filename = file->name; /* libarchive reports these as zero size anyways */ /* NOTE: if we do start accounting for directory size, a dir matching a * mountpoint needs to be attributed to the parent, not the mountpoint. */ if(S_ISDIR(file->mode) || S_ISLNK(file->mode)) { continue; } /* approximate space requirements for db entries */ if(filename[0] == '.') { filename = handle->dbpath; } snprintf(path, PATH_MAX, "%s%s", handle->root, filename); mp = match_mount_point(mount_points, path); if(mp == NULL) { _alpm_log(handle, ALPM_LOG_WARNING, _("could not determine mount point for file %s\n"), filename); continue; } /* don't check a mount that we know we can't stat */ if(mp && mp->fsinfo_loaded == MOUNT_FSINFO_FAIL) { continue; } /* lazy load filesystem info */ if(mp->fsinfo_loaded == MOUNT_FSINFO_UNLOADED) { if(mount_point_load_fsinfo(handle, mp) < 0) { continue; } } /* the addition of (divisor - 1) performs ceil() with integer division */ install_size = (file->size + mp->fsp.f_bsize - 1) / mp->fsp.f_bsize; mp->blocks_needed += install_size; mp->used |= USED_INSTALL; } return 0; }
/* Loop through the files of the package to check if they exist. */ int check_pkg_fast(alpm_pkg_t *pkg) { const char *root, *pkgname; size_t errors = 0; size_t rootlen; char filepath[PATH_MAX]; alpm_filelist_t *filelist; size_t i; root = alpm_option_get_root(config->handle); rootlen = strlen(root); if(rootlen + 1 > PATH_MAX) { /* we are in trouble here */ pm_printf(ALPM_LOG_ERROR, _("path too long: %s%s\n"), root, ""); return 1; } strcpy(filepath, root); pkgname = alpm_pkg_get_name(pkg); filelist = alpm_pkg_get_files(pkg); for(i = 0; i < filelist->count; i++) { const alpm_file_t *file = filelist->files + i; struct stat st; int exists; const char *path = file->name; size_t plen = strlen(path); if(rootlen + 1 + plen > PATH_MAX) { pm_printf(ALPM_LOG_WARNING, _("path too long: %s%s\n"), root, path); continue; } strcpy(filepath + rootlen, path); exists = check_file_exists(pkgname, filepath, rootlen, &st); if(exists == 0) { int expect_dir = path[plen - 1] == '/' ? 1 : 0; int is_dir = S_ISDIR(st.st_mode) ? 1 : 0; if(expect_dir != is_dir) { pm_printf(ALPM_LOG_WARNING, _("%s: %s (File type mismatch)\n"), pkgname, filepath); ++errors; } } else if(exists == 1) { ++errors; } } if(!config->quiet) { printf(_n("%s: %jd total file, ", "%s: %jd total files, ", (unsigned long)filelist->count), pkgname, (intmax_t)filelist->count); printf(_n("%jd missing file\n", "%jd missing files\n", (unsigned long)errors), (intmax_t)errors); } return (errors != 0 ? 1 : 0); }
static int files_fileowner(alpm_list_t *syncs, alpm_list_t *targets) { int ret = 0; alpm_list_t *t; for(t = targets; t; t = alpm_list_next(t)) { char *filename = NULL, *f; int found = 0; alpm_list_t *s; size_t len; if((filename = strdup(t->data)) == NULL) { goto notfound; } len = strlen(filename); f = filename; while(len > 1 && f[0] == '/') { f = f + 1; len--; } for(s = syncs; s; s = alpm_list_next(s)) { alpm_list_t *p; alpm_db_t *repo = s->data; alpm_list_t *packages = alpm_db_get_pkgcache(repo); for(p = packages; p; p = alpm_list_next(p)) { alpm_pkg_t *pkg = p->data; alpm_filelist_t *files = alpm_pkg_get_files(pkg); if(alpm_filelist_contains(files, f)) { if(!config->quiet) { printf(_("%s is owned by %s/%s %s\n"), f, alpm_db_get_name(repo), alpm_pkg_get_name(pkg), alpm_pkg_get_version(pkg)); } else { printf("%s/%s\n", alpm_db_get_name(repo), alpm_pkg_get_name(pkg)); } found = 1; } } } free(filename); notfound: if(!found) { ret++; } } return 0; }
alpm_list_t* alpm_pkg_get_files_list (alpm_pkg_t* pkg) { alpm_list_t *list = NULL; alpm_filelist_t *pkgfiles; size_t i; pkgfiles = alpm_pkg_get_files(pkg); for(i = 0; i < pkgfiles->count; i++) { const alpm_file_t *file = pkgfiles->files + i; list = alpm_list_add(list, file); } return list; }
/* Loop through the packages. For each package, * loop through files to check if they exist. */ static int check(alpm_pkg_t *pkg) { const char *root, *pkgname; size_t errors = 0; size_t rootlen; char f[PATH_MAX]; alpm_filelist_t *filelist; size_t i; root = alpm_option_get_root(config->handle); rootlen = strlen(root); if(rootlen + 1 > PATH_MAX) { /* we are in trouble here */ pm_fprintf(stderr, ALPM_LOG_ERROR, _("path too long: %s%s\n"), root, ""); return 1; } strcpy(f, root); pkgname = alpm_pkg_get_name(pkg); filelist = alpm_pkg_get_files(pkg); for(i = 0; i < filelist->count; i++) { const alpm_file_t *file = filelist->files + i; struct stat st; const char *path = file->name; if(rootlen + 1 + strlen(path) > PATH_MAX) { pm_fprintf(stderr, ALPM_LOG_WARNING, _("path too long: %s%s\n"), root, path); continue; } strcpy(f + rootlen, path); /* use lstat to prevent errors from symlinks */ if(lstat(f, &st) != 0) { if(config->quiet) { printf("%s %s\n", pkgname, f); } else { pm_printf(ALPM_LOG_WARNING, "%s: %s (%s)\n", pkgname, f, strerror(errno)); } errors++; } } if(!config->quiet) { printf(_n("%s: %jd total file, ", "%s: %jd total files, ", (unsigned long)filelist->count), pkgname, (intmax_t)filelist->count); printf(_n("%jd missing file\n", "%jd missing files\n", (unsigned long)errors), (intmax_t)errors); } return (errors != 0 ? 1 : 0); }
static int files_fileowner(alpm_list_t *syncs, alpm_list_t *targets) { int ret = 0; alpm_list_t *t; for(t = targets; t; t = alpm_list_next(t)) { char *filename = t->data; int found = 0; alpm_list_t *s; size_t len = strlen(filename); while(len > 1 && filename[0] == '/') { filename++; len--; } for(s = syncs; s; s = alpm_list_next(s)) { alpm_list_t *p; alpm_db_t *repo = s->data; alpm_list_t *packages = alpm_db_get_pkgcache(repo); for(p = packages; p; p = alpm_list_next(p)) { alpm_pkg_t *pkg = p->data; alpm_filelist_t *files = alpm_pkg_get_files(pkg); if(alpm_filelist_contains(files, filename)) { if(config->op_f_machinereadable) { print_line_machinereadable(repo, pkg, filename); } else if(!config->quiet) { const colstr_t *colstr = &config->colstr; printf(_("%s is owned by %s%s/%s%s %s%s\n"), filename, colstr->repo, alpm_db_get_name(repo), colstr->title, alpm_pkg_get_name(pkg), colstr->version, alpm_pkg_get_version(pkg)); } else { printf("%s/%s\n", alpm_db_get_name(repo), alpm_pkg_get_name(pkg)); } found = 1; } } } if(!found) { ret++; } } return 0; }
static gboolean pk_alpm_search_is_application (alpm_pkg_t *pkg) { guint i; alpm_filelist_t *filelist; GRegex _cleanup_regex_unref_ *regex = NULL; filelist = alpm_pkg_get_files (pkg); regex = g_regex_new ("^usr/share/applications/.*\\.desktop$", 0, 0, NULL); for (i = 0; i < filelist->count; i++) { const alpm_file_t *file = filelist->files + i; if (g_regex_match (regex, file->name, 0, NULL)) { return TRUE; } } return FALSE; }
static gboolean pk_backend_get_files_thread (PkBackend *self) { gchar **packages; GError *error = NULL; g_return_val_if_fail (self != NULL, FALSE); g_return_val_if_fail (alpm != NULL, FALSE); packages = pk_backend_get_strv (self, "package_ids"); g_return_val_if_fail (packages != NULL, FALSE); for (; *packages != NULL; ++packages) { alpm_pkg_t *pkg; const gchar *root; GString *files; alpm_filelist_t *filelist; gsize i; if (pk_backend_cancelled (self)) { break; } pkg = pk_backend_find_pkg (self, *packages, &error); if (pkg == NULL) { break; } root = alpm_option_get_root (alpm); files = g_string_new (""); filelist = alpm_pkg_get_files (pkg); for (i = 0; i < filelist->count; ++i) { const gchar *file = filelist->files[i].name; g_string_append_printf (files, "%s%s;", root, file); } g_string_truncate (files, MAX (files->len, 1) - 1); pk_backend_job_files (self, *packages, files->str); g_string_free (files, TRUE); } return pk_backend_finish (self, error); }
/* Loop through the files of the package to check if they exist. */ int check_pkg_fast(alpm_pkg_t *pkg) { const char *root, *pkgname; size_t errors = 0; size_t rootlen; char filepath[PATH_MAX]; alpm_filelist_t *filelist; size_t i; root = alpm_option_get_root(config->handle); rootlen = strlen(root); if(rootlen + 1 > PATH_MAX) { /* we are in trouble here */ pm_printf(ALPM_LOG_ERROR, _("path too long: %s%s\n"), root, ""); return 1; } strcpy(filepath, root); pkgname = alpm_pkg_get_name(pkg); filelist = alpm_pkg_get_files(pkg); for(i = 0; i < filelist->count; i++) { const alpm_file_t *file = filelist->files + i; struct stat st; const char *path = file->name; if(rootlen + 1 + strlen(path) > PATH_MAX) { pm_printf(ALPM_LOG_WARNING, _("path too long: %s%s\n"), root, path); continue; } strcpy(filepath + rootlen, path); errors += check_file_exists(pkgname, filepath, &st); } if(!config->quiet) { printf(_n("%s: %jd total file, ", "%s: %jd total files, ", (unsigned long)filelist->count), pkgname, (intmax_t)filelist->count); printf(_n("%jd missing file\n", "%jd missing files\n", (unsigned long)errors), (intmax_t)errors); } return (errors != 0 ? 1 : 0); }
static void dump_file_list(alpm_pkg_t *pkg) { const char *pkgname; alpm_filelist_t *pkgfiles; size_t i; pkgname = alpm_pkg_get_name(pkg); pkgfiles = alpm_pkg_get_files(pkg); for(i = 0; i < pkgfiles->count; i++) { const alpm_file_t *file = pkgfiles->files + i; /* Regular: '<pkgname> <filepath>\n' * Quiet : '<filepath>\n' */ if(!config->quiet) { printf("%s%s%s ", config->colstr.title, pkgname, config->colstr.nocolor); } printf("%s\n", file->name); } fflush(stdout); }
static gboolean asb_package_alpm_ensure_filelists (AsbPackage *pkg, GError **error) { AsbPackageAlpm *pkg_alpm = ASB_PACKAGE_ALPM (pkg); AsbPackageAlpmPrivate *priv = GET_PRIVATE (pkg_alpm); alpm_filelist_t *pkgfiles = alpm_pkg_get_files (priv->package); guint i; GPtrArray *filelist = g_ptr_array_new_with_free_func (g_free); for (i = 0; i < pkgfiles->count; i++) { const alpm_file_t *file = pkgfiles->files + i; g_ptr_array_add (filelist, g_strconcat ("/", file->name, NULL)); } g_ptr_array_add (filelist, NULL); asb_package_set_filelist (pkg, (gchar **)(filelist->pdata)); g_ptr_array_free (filelist, TRUE); return TRUE; }
/* verify that the filesystem matches the package database */ static int check_files(alpm_pkg_t *pkg) { alpm_filelist_t *filelist = alpm_pkg_get_files(pkg); char path[PATH_MAX], *rel; const char *pkgname = alpm_pkg_get_name(pkg); unsigned int i; int ret = 0; size_t space; strncpy(path, alpm_option_get_root(handle), PATH_MAX); rel = path + strlen(path); space = PATH_MAX - (rel - path); for(i = 0; i < filelist->count; ++i) { alpm_file_t file = filelist->files[i]; int isdir = 0; size_t len; if(skip_noextract && match_noextract(handle, file.name)) { continue; } strncpy(rel, file.name, space); len = strlen(file.name); if(rel[len - 1] == '/') { isdir = 1; rel[len - 1] = '\0'; } if(check_file(pkgname, path, isdir) != 0) { ret = 1; } } if(include_db_files && check_db_files(pkg) != 0) { ret = 1; } if(!quiet && !ret) { eprintf("%s: all files match database\n", alpm_pkg_get_name(pkg)); } return ret; }
static gboolean pk_backend_match_file (alpm_pkg_t *pkg, const gchar *needle) { alpm_filelist_t *files; gsize i; g_return_val_if_fail (pkg != NULL, FALSE); g_return_val_if_fail (needle != NULL, FALSE); files = alpm_pkg_get_files (pkg); /* match any file the package contains */ if (G_IS_DIR_SEPARATOR (*needle)) { for (i = 0; i < files->count; ++i) { const gchar *file = files->files[i].name; /* match the full path of file */ if (g_strcmp0 (file, needle + 1) == 0) return TRUE; } } else { for (i = 0; i < files->count; ++i) { const gchar *file = files->files[i].name; const gchar *name = strrchr (file, G_DIR_SEPARATOR); if (name == NULL) { name = file; } else { ++name; } /* match the basename of file */ if (g_strcmp0 (name, needle) == 0) return TRUE; } } return FALSE; }
/* List all files contained in a package */ void dump_pkg_files(alpm_pkg_t *pkg, int quiet) { const char *pkgname, *root; alpm_filelist_t *pkgfiles; size_t i; pkgname = alpm_pkg_get_name(pkg); pkgfiles = alpm_pkg_get_files(pkg); root = alpm_option_get_root(config->handle); for(i = 0; i < pkgfiles->count; i++) { const alpm_file_t *file = pkgfiles->files + i; /* Regular: '<pkgname> <root><filepath>\n' * Quiet : '<root><filepath>\n' */ if(!quiet) { printf("%s%s%s ", config->colstr.title, pkgname, config->colstr.nocolor); } printf("%s%s\n", root, file->name); } fflush(stdout); }
static int print_pkg(alpm_pkg_t *pkg, const char *format) { const char *f, *end; char fmt[64], buf[64]; int len, out = 0; end = format + strlen(format); for (f = format; f < end; f++) { len = 0; if (*f == '%') { len = strspn(f + 1 + len, printf_flags); len += strspn(f + 1 + len, digits); snprintf(fmt, len + 3, "%ss", f); fmt[len + 1] = 's'; f += len + 1; switch (*f) { /* simple attributes */ case 'f': /* filename */ out += printf(fmt, alpm_pkg_get_filename(pkg)); break; case 'n': /* package name */ out += printf(fmt, alpm_pkg_get_name(pkg)); break; case 'v': /* version */ out += printf(fmt, alpm_pkg_get_version(pkg)); break; case 'd': /* description */ out += printf(fmt, alpm_pkg_get_desc(pkg)); break; case 'u': /* project url */ out += printf(fmt, alpm_pkg_get_url(pkg)); break; case 'p': /* packager name */ out += printf(fmt, alpm_pkg_get_packager(pkg)); break; case 's': /* md5sum */ out += printf(fmt, alpm_pkg_get_md5sum(pkg)); break; case 'a': /* architecutre */ out += printf(fmt, alpm_pkg_get_arch(pkg)); break; case 'i': /* has install scriptlet? */ out += printf(fmt, alpm_pkg_has_scriptlet(pkg) ? "yes" : "no"); break; case 'r': /* repo */ out += printf(fmt, alpm_db_get_name(alpm_pkg_get_db(pkg))); break; case 'w': /* install reason */ out += printf(fmt, alpm_pkg_get_reason(pkg) ? "dependency" : "explicit"); break; case '!': /* result number */ snprintf(buf, sizeof(buf), "%d", opt_pkgcounter++); out += printf(fmt, buf); break; case 'g': /* base64 gpg sig */ out += printf(fmt, alpm_pkg_get_base64_sig(pkg)); break; case 'h': /* sha256sum */ out += printf(fmt, alpm_pkg_get_sha256sum(pkg)); break; /* times */ case 'b': /* build date */ out += print_time(alpm_pkg_get_builddate(pkg)); break; case 'l': /* install date */ out += print_time(alpm_pkg_get_installdate(pkg)); break; /* sizes */ case 'k': /* download size */ out += printf(fmt, size_to_string(alpm_pkg_get_size(pkg))); break; case 'm': /* install size */ out += printf(fmt, size_to_string(alpm_pkg_get_isize(pkg))); break; /* lists */ case 'F': /* files */ out += print_filelist(alpm_pkg_get_files(pkg)); break; case 'N': /* requiredby */ out += print_list(alpm_pkg_compute_requiredby(pkg), NULL); break; case 'L': /* licenses */ out += print_list(alpm_pkg_get_licenses(pkg), NULL); break; case 'G': /* groups */ out += print_list(alpm_pkg_get_groups(pkg), NULL); break; case 'E': /* depends (shortdeps) */ out += print_list(alpm_pkg_get_depends(pkg), (extractfn)alpm_dep_get_name); break; case 'D': /* depends */ out += print_list(alpm_pkg_get_depends(pkg), (extractfn)alpm_dep_compute_string); break; case 'O': /* optdepends */ out += print_list(alpm_pkg_get_optdepends(pkg), (extractfn)format_optdep); break; case 'o': /* optdepends (shortdeps) */ out += print_list(alpm_pkg_get_optdepends(pkg), (extractfn)alpm_dep_get_name); break; case 'C': /* conflicts */ out += print_list(alpm_pkg_get_conflicts(pkg), (extractfn)alpm_dep_get_name); break; case 'S': /* provides (shortdeps) */ out += print_list(alpm_pkg_get_provides(pkg), (extractfn)alpm_dep_get_name); break; case 'P': /* provides */ out += print_list(alpm_pkg_get_provides(pkg), (extractfn)alpm_dep_compute_string); break; case 'R': /* replaces */ out += print_list(alpm_pkg_get_replaces(pkg), (extractfn)alpm_dep_get_name); break; case 'B': /* backup */ out += print_list(alpm_pkg_get_backup(pkg), alpm_backup_get_name); break; case 'V': /* package validation */ out += print_allocated_list(get_validation_method(pkg), NULL); break; case 'M': /* modified */ out += print_allocated_list(get_modified_files(pkg), NULL); break; case '%': fputc('%', stdout); out++; break; default: fputc('?', stdout); out++; break; } } else if (*f == '\\') { char esc[3] = { f[0], f[1], '\0' }; out += print_escaped(esc); ++f; } else { fputc(*f, stdout); out++; } } /* only print a delimeter if any package data was outputted */ if (out > 0) { print_escaped(opt_delim); } return !out; }
/** * @brief Remove a package's files, optionally skipping its replacement's * files. * * @param handle the context handle * @param oldpkg package to remove * @param newpkg package to replace \a oldpkg (optional) * @param targ_count current index within the transaction (1-based) * @param pkg_count the number of packages affected by the transaction * * @return 0 on success, -1 if alpm lacks permission to delete some of the * files, >0 the number of files alpm was unable to delete */ static int remove_package_files(alpm_handle_t *handle, alpm_pkg_t *oldpkg, alpm_pkg_t *newpkg, size_t targ_count, size_t pkg_count) { alpm_list_t *skip_remove; alpm_filelist_t *filelist; size_t i; int err = 0; int nosave = handle->trans->flags & ALPM_TRANS_FLAG_NOSAVE; if(newpkg) { alpm_filelist_t *newfiles; alpm_list_t *b; skip_remove = alpm_list_join( alpm_list_strdup(handle->trans->skip_remove), alpm_list_strdup(handle->noupgrade)); /* Add files in the NEW backup array to the skip_remove array * so this removal operation doesn't kill them */ /* old package backup list */ newfiles = alpm_pkg_get_files(newpkg); 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_filelist_contains(newfiles, backup->name)) { continue; } _alpm_log(handle, ALPM_LOG_DEBUG, "adding %s to the skip_remove array\n", backup->name); skip_remove = alpm_list_add(skip_remove, strdup(backup->name)); } } else { skip_remove = alpm_list_strdup(handle->trans->skip_remove); } filelist = alpm_pkg_get_files(oldpkg); for(i = 0; i < filelist->count; i++) { alpm_file_t *file = filelist->files + i; if(!can_remove_file(handle, file, skip_remove)) { _alpm_log(handle, ALPM_LOG_DEBUG, "not removing package '%s', can't remove all files\n", oldpkg->name); FREELIST(skip_remove); RET_ERR(handle, ALPM_ERR_PKG_CANT_REMOVE, -1); } } _alpm_log(handle, ALPM_LOG_DEBUG, "removing %zd files\n", filelist->count); if(!newpkg) { /* init progress bar, but only on true remove transactions */ PROGRESS(handle, ALPM_PROGRESS_REMOVE_START, oldpkg->name, 0, pkg_count, targ_count); } /* iterate through the list backwards, unlinking files */ for(i = filelist->count; i > 0; i--) { alpm_file_t *file = filelist->files + i - 1; if(unlink_file(handle, oldpkg, newpkg, file, skip_remove, nosave) < 0) { err++; } if(!newpkg) { /* update progress bar after each file */ int percent = ((filelist->count - i) * 100) / filelist->count; PROGRESS(handle, ALPM_PROGRESS_REMOVE_START, oldpkg->name, percent, pkg_count, targ_count); } } FREELIST(skip_remove); if(!newpkg) { /* set progress to 100% after we finish unlinking files */ PROGRESS(handle, ALPM_PROGRESS_REMOVE_START, oldpkg->name, 100, pkg_count, targ_count); } return err; }
/** * @brief Unlink a package file, backing it up if necessary. * * @param handle the context handle * @param oldpkg the package being removed * @param newpkg the package replacing \a oldpkg * @param fileobj file to remove * @param skip_remove list of files that shouldn't be removed * @param nosave whether files should be backed up * * @return 0 on success, -1 if there was an error unlinking the file, 1 if the * file was skipped or did not exist */ static int unlink_file(alpm_handle_t *handle, alpm_pkg_t *oldpkg, alpm_pkg_t *newpkg, 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, 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(skip_remove, fileobj->name, _alpm_fnmatch)) { _alpm_log(handle, ALPM_LOG_DEBUG, "%s is in skip_remove, skipping removal\n", file); return 1; } if(_alpm_lstat(file, &buf)) { _alpm_log(handle, ALPM_LOG_DEBUG, "file %s does not exist\n", file); return 1; } if(S_ISDIR(buf.st_mode)) { ssize_t files = _alpm_files_in_directory(handle, file, 0); /* if we have files, no need to remove the directory */ if(files > 0) { _alpm_log(handle, ALPM_LOG_DEBUG, "keeping directory %s (contains files)\n", file); } else if(files < 0) { _alpm_log(handle, ALPM_LOG_DEBUG, "keeping directory %s (could not count files)\n", file); } else if(newpkg && alpm_filelist_contains(alpm_pkg_get_files(newpkg), fileobj->name)) { _alpm_log(handle, ALPM_LOG_DEBUG, "keeping directory %s (in new package)\n", file); } else if(dir_is_mountpoint(handle, file, &buf)) { _alpm_log(handle, ALPM_LOG_DEBUG, "keeping directory %s (mountpoint)\n", file); } else { /* one last check- does any other package own this file? */ alpm_list_t *local, *local_pkgs; int found = 0; local_pkgs = _alpm_db_get_pkgcache(handle->db_local); for(local = local_pkgs; local && !found; local = local->next) { alpm_pkg_t *local_pkg = local->data; alpm_filelist_t *filelist; /* we duplicated the package when we put it in the removal list, so we * so we can't use direct pointer comparison here. */ if(oldpkg->name_hash == local_pkg->name_hash && strcmp(oldpkg->name, local_pkg->name) == 0) { continue; } filelist = alpm_pkg_get_files(local_pkg); if(alpm_filelist_contains(filelist, fileobj->name)) { _alpm_log(handle, ALPM_LOG_DEBUG, "keeping directory %s (owned by %s)\n", file, local_pkg->name); found = 1; } } if(!found) { if(rmdir(file)) { _alpm_log(handle, ALPM_LOG_DEBUG, "directory removal of %s failed: %s\n", file, strerror(errno)); return -1; } else { _alpm_log(handle, ALPM_LOG_DEBUG, "removed directory %s (no remaining owners)\n", file); } } } } else { /* if the file needs backup and has been modified, back it up to .pacsave */ alpm_backup_t *backup = _alpm_needbackup(fileobj->name, oldpkg); if(backup) { if(nosave) { _alpm_log(handle, ALPM_LOG_DEBUG, "transaction is set to NOSAVE, not backing up '%s'\n", file); } else { char *filehash = alpm_compute_md5sum(file); int cmp = filehash ? strcmp(filehash, backup->hash) : 0; FREE(filehash); if(cmp != 0) { char *newpath; size_t len = strlen(file) + 8 + 1; MALLOC(newpath, len, RET_ERR(handle, ALPM_ERR_MEMORY, -1)); shift_pacsave(handle, file); snprintf(newpath, len, "%s.pacsave", file); if(rename(file, newpath)) { _alpm_log(handle, ALPM_LOG_ERROR, _("could not rename %s to %s (%s)\n"), file, newpath, strerror(errno)); alpm_logaction(handle, ALPM_CALLER_PREFIX, "error: could not rename %s to %s (%s)\n", file, newpath, strerror(errno)); free(newpath); return -1; } _alpm_log(handle, ALPM_LOG_WARNING, _("%s saved as %s\n"), file, newpath); alpm_logaction(handle, ALPM_CALLER_PREFIX, "warning: %s saved as %s\n", file, newpath); free(newpath); return 0; } } } _alpm_log(handle, ALPM_LOG_DEBUG, "unlinking %s\n", file); if(unlink(file) == -1) { _alpm_log(handle, ALPM_LOG_ERROR, _("cannot remove %s (%s)\n"), file, strerror(errno)); alpm_logaction(handle, ALPM_CALLER_PREFIX, "error: cannot remove %s (%s)\n", file, strerror(errno)); return -1; } } return 0; }
static int query_fileowner(alpm_list_t *targets) { int ret = 0; char path[PATH_MAX]; const char *root; size_t rootlen; alpm_list_t *t; alpm_db_t *db_local; /* This code is here for safety only */ if(targets == NULL) { pm_fprintf(stderr, ALPM_LOG_ERROR, _("no file was specified for --owns\n")); return 1; } /* Set up our root path buffer. We only need to copy the location of root in * once, then we can just overwrite whatever file was there on the previous * iteration. */ root = alpm_option_get_root(config->handle); rootlen = strlen(root); if(rootlen + 1 > PATH_MAX) { /* we are in trouble here */ pm_fprintf(stderr, ALPM_LOG_ERROR, _("path too long: %s%s\n"), root, ""); return 1; } strcpy(path, root); db_local = alpm_option_get_localdb(config->handle); for(t = targets; t; t = alpm_list_next(t)) { char *filename, *dname, *rpath; const char *bname; struct stat buf; alpm_list_t *i; int found = 0; filename = strdup(alpm_list_getdata(t)); if(lstat(filename, &buf) == -1) { /* if it is not a path but a program name, then check in PATH */ if(strchr(filename, '/') == NULL) { if(search_path(&filename, &buf) == -1) { pm_fprintf(stderr, ALPM_LOG_ERROR, _("failed to find '%s' in PATH: %s\n"), filename, strerror(errno)); ret++; free(filename); continue; } } else { pm_fprintf(stderr, ALPM_LOG_ERROR, _("failed to read file '%s': %s\n"), filename, strerror(errno)); ret++; free(filename); continue; } } if(S_ISDIR(buf.st_mode)) { pm_fprintf(stderr, ALPM_LOG_ERROR, _("cannot determine ownership of directory '%s'\n"), filename); ret++; free(filename); continue; } bname = mbasename(filename); dname = mdirname(filename); /* for files in '/', there is no directory name to match */ if(strcmp(dname, "") == 0) { rpath = NULL; } else { rpath = resolve_path(dname); if(!rpath) { pm_fprintf(stderr, ALPM_LOG_ERROR, _("cannot determine real path for '%s': %s\n"), filename, strerror(errno)); free(filename); free(dname); free(rpath); ret++; continue; } } free(dname); for(i = alpm_db_get_pkgcache(db_local); i && !found; i = alpm_list_next(i)) { alpm_pkg_t *info = alpm_list_getdata(i); alpm_filelist_t *filelist = alpm_pkg_get_files(info); size_t j; for(j = 0; j < filelist->count; j++) { const alpm_file_t *file = filelist->files + j; char *ppath, *pdname; const char *pkgfile = file->name; /* avoid the costly resolve_path usage if the basenames don't match */ if(strcmp(mbasename(pkgfile), bname) != 0) { continue; } /* for files in '/', there is no directory name to match */ if(!rpath) { print_query_fileowner(filename, info); found = 1; continue; } if(rootlen + 1 + strlen(pkgfile) > PATH_MAX) { pm_fprintf(stderr, ALPM_LOG_ERROR, _("path too long: %s%s\n"), root, pkgfile); } /* concatenate our file and the root path */ strcpy(path + rootlen, pkgfile); pdname = mdirname(path); ppath = resolve_path(pdname); free(pdname); if(ppath && strcmp(ppath, rpath) == 0) { print_query_fileowner(filename, info); found = 1; } free(ppath); } } if(!found) { pm_fprintf(stderr, ALPM_LOG_ERROR, _("No package owns %s\n"), filename); ret++; } free(filename); free(rpath); } return ret; }
/* Find file conflicts that may occur during the transaction with two checks: * 1: check every target against every target * 2: check every target against the filesystem */ alpm_list_t *_alpm_db_find_fileconflicts(pmdb_t *db, pmtrans_t *trans, char *root) { alpm_list_t *i, *conflicts = NULL; alpm_list_t *targets = trans->packages; int numtargs = alpm_list_count(targets); int current; ALPM_LOG_FUNC; if(db == NULL || targets == NULL || root == NULL) { return(NULL); } /* 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 * different cases. */ for(current = 1, i = targets; i; i = i->next, current++) { alpm_list_t *j, *k, *tmpfiles = NULL; pmpkg_t *p1, *p2, *dbpkg; char path[PATH_MAX+1]; p1 = i->data; if(!p1) { continue; } double percent = (double)current / numtargs; PROGRESS(trans, PM_TRANS_PROGRESS_CONFLICTS_START, "", (percent * 100), numtargs, current); /* CHECK 1: check every target against every target */ _alpm_log(PM_LOG_DEBUG, "searching for file conflicts: %s\n", alpm_pkg_get_name(p1)); for(j = i->next; j; j = j->next) { p2 = j->data; if(!p2) { continue; } tmpfiles = chk_fileconflicts(alpm_pkg_get_files(p1), alpm_pkg_get_files(p2)); if(tmpfiles) { for(k = tmpfiles; k; k = k->next) { snprintf(path, PATH_MAX, "%s%s", root, (char *)k->data); conflicts = add_fileconflict(conflicts, PM_FILECONFLICT_TARGET, path, alpm_pkg_get_name(p1), alpm_pkg_get_name(p2)); } FREELIST(tmpfiles); } } /* declarations for second check */ struct stat lsbuf, sbuf; char *filestr = NULL; /* CHECK 2: check every target against the filesystem */ _alpm_log(PM_LOG_DEBUG, "searching for filesystem conflicts: %s\n", p1->name); dbpkg = _alpm_db_get_pkgfromcache(db, p1->name); /* Do two different checks here. f the package is currently installed, * then only check files that are new in the new package. If the package * is not currently installed, then simply stat the whole filelist */ if(dbpkg) { /* older ver of package currently installed */ tmpfiles = chk_filedifference(alpm_pkg_get_files(p1), alpm_pkg_get_files(dbpkg)); } else { /* no version of package currently installed */ tmpfiles = alpm_list_strdup(alpm_pkg_get_files(p1)); } /* loop over each file to be installed */ for(j = tmpfiles; j; j = j->next) { int skip_conflict = 0; filestr = j->data; snprintf(path, PATH_MAX, "%s%s", root, filestr); /* stat the file - if it exists, do some checks */ if(_alpm_lstat(path, &lsbuf) != 0) { continue; } stat(path, &sbuf); if(path[strlen(path)-1] == '/') { if(S_ISDIR(lsbuf.st_mode)) { _alpm_log(PM_LOG_DEBUG, "%s is a directory, not a conflict\n", path); skip_conflict = 1; } else if(S_ISLNK(lsbuf.st_mode) && S_ISDIR(sbuf.st_mode)) { _alpm_log(PM_LOG_DEBUG, "%s is a symlink to a dir, hopefully not a conflict\n", path); skip_conflict = 1; } } if(!skip_conflict) { _alpm_log(PM_LOG_DEBUG, "checking possible conflict: %s\n", path); /* Look at all the targets to see if file has changed hands */ int resolved_conflict = 0; /* have we acted on this conflict? */ for(k = targets; k; k = k->next) { p2 = k->data; if(!p2 || strcmp(p1->name, p2->name) == 0) { continue; } pmpkg_t *localp2 = _alpm_db_get_pkgfromcache(db, p2->name); /* Check if it used to exist in a package, but doesn't anymore */ alpm_list_t *pkgfiles, *localfiles; /* added for readability */ pkgfiles = alpm_pkg_get_files(p2); localfiles = alpm_pkg_get_files(localp2); if(localp2 && !alpm_list_find_str(pkgfiles, filestr) && alpm_list_find_str(localfiles, 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 */ trans->skip_remove = alpm_list_add(trans->skip_remove, strdup(path)); _alpm_log(PM_LOG_DEBUG, "file changed packages, adding to remove skiplist: %s\n", filestr); resolved_conflict = 1; break; } } if(!resolved_conflict) { _alpm_log(PM_LOG_DEBUG, "file found in conflict: %s\n", path); conflicts = add_fileconflict(conflicts, PM_FILECONFLICT_FILESYSTEM, path, p1->name, NULL); } } } FREELIST(tmpfiles); } return(conflicts); }
static int files_search(alpm_list_t *syncs, alpm_list_t *targets, int regex) { int ret = 0; alpm_list_t *t; const colstr_t *colstr = &config->colstr; for(t = targets; t; t = alpm_list_next(t)) { char *targ = t->data; alpm_list_t *s; int found = 0; regex_t reg; if(regex) { if(regcomp(®, targ, REG_EXTENDED | REG_NOSUB | REG_ICASE | REG_NEWLINE) != 0) { /* TODO: error message */ goto notfound; } } for(s = syncs; s; s = alpm_list_next(s)) { alpm_list_t *p; alpm_db_t *repo = s->data; alpm_list_t *packages = alpm_db_get_pkgcache(repo); int m; for(p = packages; p; p = alpm_list_next(p)) { size_t f = 0; char* c; alpm_pkg_t *pkg = p->data; alpm_filelist_t *files = alpm_pkg_get_files(pkg); alpm_list_t *match = NULL; while(f < files->count) { c = strrchr(files->files[f].name, '/'); if(c && *(c + 1)) { if(regex) { m = regexec(®, (c + 1), 0, 0, 0); } else { m = strcmp(c + 1, targ); } if(m == 0) { match = alpm_list_add(match, files->files[f].name); found = 1; } } f++; } if(match != NULL) { if(config->op_f_machinereadable) { alpm_list_t *ml; for(ml = match; ml; ml = alpm_list_next(ml)) { char *filename = ml->data; print_line_machinereadable(repo, pkg, filename); } } else if(config->quiet) { printf("%s/%s\n", alpm_db_get_name(repo), alpm_pkg_get_name(pkg)); } else { alpm_list_t *ml; printf("%s%s/%s%s %s%s%s\n", colstr->repo, alpm_db_get_name(repo), colstr->title, alpm_pkg_get_name(pkg), colstr->version, alpm_pkg_get_version(pkg), colstr->nocolor); for(ml = match; ml; ml = alpm_list_next(ml)) { c = ml->data; printf(" %s\n", c); } } alpm_list_free(match); } } } if(regex) { regfree(®); } notfound: if(!found) { ret++; } } return 0; }