Skip diskspace checking for symlinks and directories in all cases

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.

This patch also includes a few cleanups/performance tweaks- avoid calling
strlen() on the mountpoint directory string as much by storing this size in
our mountpoint struct, and push the snprintf() call up to the calculate
functions since we were already doing it here in the remove case.

Signed-off-by: Dan McGee <dan@archlinux.org>
This commit is contained in:
Dan McGee 2011-02-07 21:33:30 -06:00
parent da3b934602
commit 942bb9e64a
2 changed files with 49 additions and 47 deletions

View file

@ -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 *mp1 = p1;
const alpm_mountpoint_t *mp2 = p2; 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) 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)); MALLOC(mp, sizeof(alpm_mountpoint_t), RET_ERR(PM_ERR_MEMORY, NULL));
mp->mount_dir = strdup(mnt->mnt_dir); mp->mount_dir = strdup(mnt->mnt_dir);
mp->mount_dir_len = strlen(mnt->mnt_dir);
memcpy(&(mp->fsp), &fsp, sizeof(FSSTATSTYPE)); memcpy(&(mp->fsp), &fsp, sizeof(FSSTATSTYPE));
mp->blocks_needed = 0l; mp->blocks_needed = 0l;
@ -105,6 +107,7 @@ static alpm_list_t *mount_point_list(void)
for(; entries-- > 0; fsp++) { for(; entries-- > 0; fsp++) {
MALLOC(mp, sizeof(alpm_mountpoint_t), RET_ERR(PM_ERR_MEMORY, NULL)); MALLOC(mp, sizeof(alpm_mountpoint_t), RET_ERR(PM_ERR_MEMORY, NULL));
mp->mount_dir = strdup(fsp->f_mntonname); mp->mount_dir = strdup(fsp->f_mntonname);
mp->mount_dir_len = strlen(mnt->mnt_dir);
memcpy(&(mp->fsp), fsp, sizeof(FSSTATSTYPE)); memcpy(&(mp->fsp), fsp, sizeof(FSSTATSTYPE));
mp->blocks_needed = 0l; mp->blocks_needed = 0l;
@ -120,22 +123,18 @@ static alpm_list_t *mount_point_list(void)
return(mount_points); return(mount_points);
} }
static alpm_list_t *match_mount_point(const alpm_list_t *mount_points, static alpm_mountpoint_t *match_mount_point(const alpm_list_t *mount_points,
const char *file) const char *real_path)
{ {
char real_path[PATH_MAX]; const alpm_list_t *mp;
snprintf(real_path, PATH_MAX, "%s%s", handle->root, file);
alpm_list_t *mp = alpm_list_last(mount_points); for(mp = mount_points; mp != NULL; mp = mp->next) {
do {
alpm_mountpoint_t *data = mp->data; alpm_mountpoint_t *data = mp->data;
if(strncmp(data->mount_dir, real_path, strlen(data->mount_dir)) == 0) { if(strncmp(data->mount_dir, real_path, data->mount_dir_len) == 0) {
return(mp); return(data);
} }
}
mp = mp->prev;
} while (mp != alpm_list_last(mount_points));
/* should not get here... */ /* should not get here... */
return(NULL); 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); alpm_list_t *files = alpm_pkg_get_files(pkg);
for(file = files; file; file = file->next) { for(file = files; file; file = file->next) {
alpm_list_t *mp; alpm_mountpoint_t *mp;
alpm_mountpoint_t *data;
struct stat st; struct stat st;
char path[PATH_MAX]; char path[PATH_MAX];
const char *filename = file->data; const char *filename = file->data;
/* skip directories to be consistent with libarchive that reports them snprintf(path, PATH_MAX, "%s%s", handle->root, filename);
* to be zero size and to prevent multiple counting across packages */ _alpm_lstat(path, &st);
if(*(filename + strlen(filename) - 1) == '/') {
/* 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; continue;
} }
mp = match_mount_point(mount_points, filename); mp = match_mount_point(mount_points, path);
if(mp == NULL) { if(mp == NULL) {
_alpm_log(PM_LOG_WARNING, _alpm_log(PM_LOG_WARNING,
_("could not determine mount point for file %s"), filename); _("could not determine mount point for file %s"), filename);
continue; 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 */ /* the addition of (divisor - 1) performs ceil() with integer division */
data->blocks_needed -= mp->blocks_needed -=
(st.st_size + data->fsp.f_bsize - 1l) / data->fsp.f_bsize; (st.st_size + mp->fsp.f_bsize - 1l) / mp->fsp.f_bsize;
} }
return(0); return(0);
@ -191,7 +182,6 @@ static int calculate_installed_size(const alpm_list_t *mount_points,
int ret=0; int ret=0;
struct archive *archive; struct archive *archive;
struct archive_entry *entry; struct archive_entry *entry;
const char *file;
if ((archive = archive_read_new()) == NULL) { if ((archive = archive_read_new()) == NULL) {
pm_errno = PM_ERR_LIBARCHIVE; 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) { while(archive_read_next_header(archive, &entry) == ARCHIVE_OK) {
alpm_list_t *mp; alpm_mountpoint_t *mp;
alpm_mountpoint_t *data; 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);
/* approximate space requirements for db entries */ /* libarchive reports these as zero size anyways */
if(file[0] == '.') { /* NOTE: if we do start accounting for directory size, a dir matching a
file = alpm_option_get_dbpath(); * mountpoint needs to be attributed to the parent, not the mountpoint. */
} if(S_ISDIR(mode) || S_ISLNK(mode)) {
continue;
mp = match_mount_point(mount_points, file); }
if(mp == NULL) {
_alpm_log(PM_LOG_WARNING, /* approximate space requirements for db entries */
_("could not determine mount point for file %s"), file); if(filename[0] == '.') {
filename = alpm_option_get_dbpath();
}
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"), filename);
continue; continue;
} }
data = mp->data;
/* the addition of (divisor - 1) performs ceil() with integer division */ /* the addition of (divisor - 1) performs ceil() with integer division */
data->blocks_needed += mp->blocks_needed +=
(archive_entry_size(entry) + data->fsp.f_bsize - 1l) / data->fsp.f_bsize; (archive_entry_size(entry) + mp->fsp.f_bsize - 1l) / mp->fsp.f_bsize;
data->used = 1; mp->used = 1;
if(archive_read_data_skip(archive)) { if(archive_read_data_skip(archive)) {
_alpm_log(PM_LOG_ERROR, _("error while reading package %s: %s\n"), _alpm_log(PM_LOG_ERROR, _("error while reading package %s: %s\n"),

View file

@ -32,6 +32,7 @@
typedef struct __alpm_mountpoint_t { typedef struct __alpm_mountpoint_t {
/* mount point information */ /* mount point information */
char *mount_dir; char *mount_dir;
size_t mount_dir_len;
/* storage for additional disk usage calculations */ /* storage for additional disk usage calculations */
long blocks_needed; long blocks_needed;
long max_blocks_needed; long max_blocks_needed;