We did this in some but not all cases, assuming the 0 value coming out of
libarchive would not be a problem. However, this does not work for "fake"
filesystems such as rpc_pipefs, which reports a free block and total block
count of zero.

Fix this by not ever counting symlinks or directories, and adding a note
explaining that if we someday do count directories, their size needs to be
attributed to the proper place.

Signed-off-by: Dan McGee <[email protected]>
---
 lib/libalpm/diskspace.c |   85 ++++++++++++++++++++++++-----------------------
 lib/libalpm/diskspace.h |    1 +
 2 files changed, 44 insertions(+), 42 deletions(-)

diff --git a/lib/libalpm/diskspace.c b/lib/libalpm/diskspace.c
index dfafdac..ae2edf7 100644
--- a/lib/libalpm/diskspace.c
+++ b/lib/libalpm/diskspace.c
@@ -54,7 +54,8 @@ static int mount_point_cmp(const void *p1, const void *p2)
 {
        const alpm_mountpoint_t *mp1 = p1;
        const alpm_mountpoint_t *mp2 = p2;
-       return(strcmp(mp1->mount_dir, mp2->mount_dir));
+       /* the negation will sort all mountpoints before their parent */
+       return(-strcmp(mp1->mount_dir, mp2->mount_dir));
 }
 
 static alpm_list_t *mount_point_list(void)
@@ -82,6 +83,7 @@ static alpm_list_t *mount_point_list(void)
 
                MALLOC(mp, sizeof(alpm_mountpoint_t), RET_ERR(PM_ERR_MEMORY, 
NULL));
                mp->mount_dir = strdup(mnt->mnt_dir);
+               mp->mount_dir_len = strlen(mnt->mnt_dir);
                memcpy(&(mp->fsp), &fsp, sizeof(FSSTATSTYPE));
 
                mp->blocks_needed = 0l;
@@ -105,6 +107,7 @@ static alpm_list_t *mount_point_list(void)
        for(; entries-- > 0; fsp++) {
                MALLOC(mp, sizeof(alpm_mountpoint_t), RET_ERR(PM_ERR_MEMORY, 
NULL));
                mp->mount_dir = strdup(fsp->f_mntonname);
+               mp->mount_dir_len = strlen(mnt->mnt_dir);
                memcpy(&(mp->fsp), fsp, sizeof(FSSTATSTYPE));
 
                mp->blocks_needed = 0l;
@@ -120,22 +123,18 @@ static alpm_list_t *mount_point_list(void)
        return(mount_points);
 }
 
-static alpm_list_t *match_mount_point(const alpm_list_t *mount_points,
-               const char *file)
+static alpm_mountpoint_t *match_mount_point(const alpm_list_t *mount_points,
+               const char *real_path)
 {
-       char real_path[PATH_MAX];
-       snprintf(real_path, PATH_MAX, "%s%s", handle->root, file);
+       const alpm_list_t *mp;
 
-       alpm_list_t *mp = alpm_list_last(mount_points);
-       do {
+       for(mp = mount_points; mp != NULL; mp = mp->next) {
                alpm_mountpoint_t *data = mp->data;
 
-               if(strncmp(data->mount_dir, real_path, strlen(data->mount_dir)) 
== 0) {
-                       return(mp);
+               if(strncmp(data->mount_dir, real_path, data->mount_dir_len) == 
0) {
+                       return(data);
                }
-
-               mp = mp->prev;
-       } while (mp != alpm_list_last(mount_points));
+       }
 
        /* should not get here... */
        return(NULL);
@@ -148,38 +147,30 @@ static int calculate_removed_size(const alpm_list_t 
*mount_points,
 
        alpm_list_t *files = alpm_pkg_get_files(pkg);
        for(file = files; file; file = file->next) {
-               alpm_list_t *mp;
-               alpm_mountpoint_t *data;
+               alpm_mountpoint_t *mp;
                struct stat st;
                char path[PATH_MAX];
                const char *filename = file->data;
 
-               /* skip directories to be consistent with libarchive that 
reports them
-                * to be zero size and to prevent multiple counting across 
packages */
-               if(*(filename + strlen(filename) - 1) == '/') {
+               snprintf(path, PATH_MAX, "%s%s", handle->root, filename);
+               _alpm_lstat(path, &st);
+
+               /* 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, filename);
+               mp = match_mount_point(mount_points, path);
                if(mp == NULL) {
                        _alpm_log(PM_LOG_WARNING,
                                        _("could not determine mount point for 
file %s"), filename);
                        continue;
                }
 
-               snprintf(path, PATH_MAX, "%s%s", handle->root, filename);
-               _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;
                /* the addition of (divisor - 1) performs ceil() with integer 
division */
-               data->blocks_needed -=
-                       (st.st_size + data->fsp.f_bsize - 1l) / 
data->fsp.f_bsize;
+               mp->blocks_needed -=
+                       (st.st_size + mp->fsp.f_bsize - 1l) / mp->fsp.f_bsize;
        }
 
        return(0);
@@ -191,7 +182,6 @@ static int calculate_installed_size(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;
@@ -210,28 +200,39 @@ static int calculate_installed_size(const alpm_list_t 
*mount_points,
        }
 
        while(archive_read_next_header(archive, &entry) == ARCHIVE_OK) {
-               alpm_list_t *mp;
-               alpm_mountpoint_t *data;
+               alpm_mountpoint_t *mp;
+               const char *filename;
+               mode_t mode;
+               char path[PATH_MAX];
 
-               file = archive_entry_pathname(entry);
+               filename = archive_entry_pathname(entry);
+               mode = archive_entry_mode(entry);
+
+               /* 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(mode) || S_ISLNK(mode)) {
+                       continue;
+               }
 
                /* approximate space requirements for db entries */
-               if(file[0] == '.') {
-                       file = alpm_option_get_dbpath();
+               if(filename[0] == '.') {
+                       filename = alpm_option_get_dbpath();
                }
 
-               mp = match_mount_point(mount_points, file);
+               snprintf(path, PATH_MAX, "%s%s", handle->root, filename);
+
+               mp = match_mount_point(mount_points, path);
                if(mp == NULL) {
                        _alpm_log(PM_LOG_WARNING,
-                                       _("could not determine mount point for 
file %s"), file);
+                                       _("could not determine mount point for 
file %s"), filename);
                        continue;
                }
 
-               data = mp->data;
                /* the addition of (divisor - 1) performs ceil() with integer 
division */
-               data->blocks_needed +=
-                       (archive_entry_size(entry) + data->fsp.f_bsize - 1l) / 
data->fsp.f_bsize;
-               data->used = 1;
+               mp->blocks_needed +=
+                       (archive_entry_size(entry) + mp->fsp.f_bsize - 1l) / 
mp->fsp.f_bsize;
+               mp->used = 1;
 
                if(archive_read_data_skip(archive)) {
                        _alpm_log(PM_LOG_ERROR, _("error while reading package 
%s: %s\n"),
diff --git a/lib/libalpm/diskspace.h b/lib/libalpm/diskspace.h
index 25b9cfb..ae99d0c 100644
--- a/lib/libalpm/diskspace.h
+++ b/lib/libalpm/diskspace.h
@@ -32,6 +32,7 @@
 typedef struct __alpm_mountpoint_t {
        /* mount point information */
        char *mount_dir;
+       size_t mount_dir_len;
        /* storage for additional disk usage calculations */
        long blocks_needed;
        long max_blocks_needed;
-- 
1.7.4


Reply via email to