diff options
Diffstat (limited to 'lib/libalpm')
-rw-r--r-- | lib/libalpm/diskspace.c | 100 |
1 files changed, 100 insertions, 0 deletions
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; |