summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--configure.ac3
-rw-r--r--lib/libalpm/diskspace.c100
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;