diff options
-rw-r--r-- | configure.ac | 3 | ||||
-rw-r--r-- | lib/libalpm/diskspace.c | 100 |
2 files changed, 103 insertions, 0 deletions
diff --git a/configure.ac b/configure.ac index cf023002..56e1ed88 100644 --- a/configure.ac +++ b/configure.ac @@ -133,6 +133,9 @@ AC_PATH_PROGS([BASH_SHELL], [bash bash4 bash3], [false]) AM_GNU_GETTEXT([external]) AM_GNU_GETTEXT_VERSION(0.13.1) +# Check for lm +AC_CHECK_LIB([m], [ceil]) + # Check for libarchive AC_CHECK_LIB([archive], [archive_read_data], , AC_MSG_ERROR([libarchive is needed to compile pacman!])) diff --git a/lib/libalpm/diskspace.c b/lib/libalpm/diskspace.c index 9d153fb4..919d1590 100644 --- a/lib/libalpm/diskspace.c +++ b/lib/libalpm/diskspace.c @@ -33,6 +33,12 @@ #include <sys/statvfs.h> #endif +#include <math.h> + +/* libarchive */ +#include <archive.h> +#include <archive_entry.h> + /* libalpm */ #include "diskspace.h" #include "alpm_list.h" @@ -152,6 +158,100 @@ static alpm_list_t *match_mount_point(const alpm_list_t *mount_points, const cha return NULL; } +static int calculate_removed_size(pmpkg_t *pkg, const alpm_list_t *mount_points) +{ + alpm_list_t *file; + + alpm_list_t *files = alpm_pkg_get_files(pkg); + for(file = files; file; file = file->next) { + alpm_list_t *mp; + alpm_mountpoint_t *data; + struct stat st; + char path[PATH_MAX]; + + /* skip directories to be consistent with libarchive that reports them to be zero size + and to prevent multiple counting across packages */ + if(*((char *)(file->data) + strlen(file->data) - 1) == '/') { + continue; + } + + mp = match_mount_point(mount_points, file->data); + if(mp == NULL) { + _alpm_log(PM_LOG_WARNING, _("could not determine mount point for file %s"), (char *)(file->data)); + continue; + } + + snprintf(path, PATH_MAX, "%s%s", handle->root, (char *)file->data); + _alpm_lstat(path, &st); + + /* skip symlinks to be consistent with libarchive that reports them to be zero size */ + if(S_ISLNK(st.st_mode)) { + continue; + } + + data = mp->data; + data->blocks_needed -= ceil((double)(st.st_size) / + (double)(data->fsp->f_bsize)); + data->used = 1; + } + + return 0; +} + +static int calculate_installed_size(pmpkg_t *pkg, const alpm_list_t *mount_points) +{ + int ret=0; + struct archive *archive; + struct archive_entry *entry; + const char *file; + + if ((archive = archive_read_new()) == NULL) { + pm_errno = PM_ERR_LIBARCHIVE; + ret = -1; + goto cleanup; + } + + archive_read_support_compression_all(archive); + archive_read_support_format_all(archive); + + if(archive_read_open_filename(archive, pkg->origin_data.file, + ARCHIVE_DEFAULT_BYTES_PER_BLOCK) != ARCHIVE_OK) { + pm_errno = PM_ERR_PKG_OPEN; + ret = -1; + goto cleanup; + } + + while(archive_read_next_header(archive, &entry) == ARCHIVE_OK) { + alpm_list_t *mp; + alpm_mountpoint_t *data; + + file = archive_entry_pathname(entry); + + /* approximate space requirements for db entries */ + if(strcmp(file, ".PKGINFO") == 0 || + strcmp(file, ".INSTALL") == 0 || + strcmp(file, ".CHANGELOG") == 0) { + file = alpm_option_get_dbpath(); + } + + mp = match_mount_point(mount_points, file); + if(mp == NULL) { + _alpm_log(PM_LOG_WARNING, _("could not determine mount point for file %s"), archive_entry_pathname(entry)); + continue; + } + + data = mp->data; + data->blocks_needed += ceil((double)(archive_entry_size(entry)) / + (double)(data->fsp->f_bsize)); + data->used = 1; + } + + archive_read_finish(archive); + +cleanup: + return ret; +} + int _alpm_check_diskspace(pmtrans_t *trans, pmdb_t *db) { alpm_list_t *mount_points; |