2010-11-16 00:57:39 -05:00
|
|
|
/*
|
|
|
|
* diskspace.c
|
|
|
|
*
|
2014-01-01 05:24:48 -05:00
|
|
|
* Copyright (c) 2010-2014 Pacman Development Team <pacman-dev@archlinux.org>
|
2010-11-16 00:57:39 -05:00
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
2012-01-19 17:21:06 -05:00
|
|
|
#include <stdio.h>
|
2011-02-08 22:19:00 -05:00
|
|
|
#include <errno.h>
|
2012-01-19 17:21:06 -05:00
|
|
|
|
2010-11-16 21:12:26 -05:00
|
|
|
#if defined(HAVE_MNTENT_H)
|
2010-11-16 01:15:21 -05:00
|
|
|
#include <mntent.h>
|
2010-11-16 21:12:26 -05:00
|
|
|
#endif
|
2012-01-23 13:15:53 -05:00
|
|
|
#if defined(HAVE_SYS_MNTTAB_H)
|
|
|
|
#include <sys/mnttab.h>
|
2012-01-19 17:21:06 -05:00
|
|
|
#endif
|
2010-11-16 21:12:26 -05:00
|
|
|
#if defined(HAVE_SYS_STATVFS_H)
|
2010-11-16 01:15:21 -05:00
|
|
|
#include <sys/statvfs.h>
|
2010-11-16 21:12:26 -05:00
|
|
|
#endif
|
|
|
|
#if defined(HAVE_SYS_PARAM_H)
|
2010-11-16 01:15:21 -05:00
|
|
|
#include <sys/param.h>
|
2010-11-16 21:12:26 -05:00
|
|
|
#endif
|
|
|
|
#if defined(HAVE_SYS_MOUNT_H)
|
2010-11-16 01:15:21 -05:00
|
|
|
#include <sys/mount.h>
|
2010-11-16 21:12:26 -05:00
|
|
|
#endif
|
|
|
|
#if defined(HAVE_SYS_UCRED_H)
|
2010-11-16 01:15:21 -05:00
|
|
|
#include <sys/ucred.h>
|
|
|
|
#endif
|
2010-11-16 21:12:26 -05:00
|
|
|
#if defined(HAVE_SYS_TYPES_H)
|
2010-11-16 01:15:21 -05:00
|
|
|
#include <sys/types.h>
|
|
|
|
#endif
|
|
|
|
|
2010-11-16 00:57:39 -05:00
|
|
|
/* libalpm */
|
|
|
|
#include "diskspace.h"
|
2010-11-16 01:15:21 -05:00
|
|
|
#include "alpm_list.h"
|
|
|
|
#include "util.h"
|
|
|
|
#include "log.h"
|
2010-11-16 02:07:43 -05:00
|
|
|
#include "trans.h"
|
2010-11-16 01:24:52 -05:00
|
|
|
#include "handle.h"
|
|
|
|
|
2010-11-16 21:12:27 -05:00
|
|
|
static int mount_point_cmp(const void *p1, const void *p2)
|
2010-11-16 01:24:52 -05:00
|
|
|
{
|
2010-11-16 21:12:27 -05:00
|
|
|
const alpm_mountpoint_t *mp1 = p1;
|
|
|
|
const alpm_mountpoint_t *mp2 = p2;
|
2011-02-07 22:33:30 -05:00
|
|
|
/* the negation will sort all mountpoints before their parent */
|
2011-03-20 20:45:57 -04:00
|
|
|
return -strcmp(mp1->mount_dir, mp2->mount_dir);
|
2010-11-16 01:24:52 -05:00
|
|
|
}
|
2010-11-16 01:15:21 -05:00
|
|
|
|
2011-10-16 16:00:35 -04:00
|
|
|
static void mount_point_list_free(alpm_list_t *mount_points)
|
|
|
|
{
|
|
|
|
alpm_list_t *i;
|
|
|
|
|
|
|
|
for(i = mount_points; i; i = i->next) {
|
|
|
|
alpm_mountpoint_t *data = i->data;
|
|
|
|
FREE(data->mount_dir);
|
|
|
|
}
|
|
|
|
FREELIST(mount_points);
|
|
|
|
}
|
|
|
|
|
2012-04-29 14:54:10 -04:00
|
|
|
static int mount_point_load_fsinfo(alpm_handle_t *handle, alpm_mountpoint_t *mountpoint)
|
|
|
|
{
|
2012-04-29 15:00:38 -04:00
|
|
|
#if defined(HAVE_GETMNTENT)
|
2012-04-29 14:54:10 -04:00
|
|
|
/* grab the filesystem usage */
|
|
|
|
if(statvfs(mountpoint->mount_dir, &(mountpoint->fsp)) != 0) {
|
|
|
|
_alpm_log(handle, ALPM_LOG_WARNING,
|
|
|
|
_("could not get filesystem information for %s: %s\n"),
|
|
|
|
mountpoint->mount_dir, strerror(errno));
|
2012-04-29 15:00:38 -04:00
|
|
|
mountpoint->fsinfo_loaded = MOUNT_FSINFO_FAIL;
|
2012-04-29 14:54:10 -04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2012-04-29 15:00:38 -04:00
|
|
|
_alpm_log(handle, ALPM_LOG_DEBUG, "loading fsinfo for %s\n", mountpoint->mount_dir);
|
2012-04-29 14:54:10 -04:00
|
|
|
mountpoint->read_only = mountpoint->fsp.f_flag & ST_RDONLY;
|
2012-04-29 15:00:38 -04:00
|
|
|
mountpoint->fsinfo_loaded = MOUNT_FSINFO_LOADED;
|
2014-01-02 13:37:07 -05:00
|
|
|
#else
|
|
|
|
(void)handle;
|
|
|
|
(void)mountpoint;
|
2012-04-29 15:00:38 -04:00
|
|
|
#endif
|
2012-04-29 14:54:10 -04:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-06-28 00:04:00 -04:00
|
|
|
static alpm_list_t *mount_point_list(alpm_handle_t *handle)
|
2010-11-16 01:15:21 -05:00
|
|
|
{
|
2011-03-17 06:14:06 -04:00
|
|
|
alpm_list_t *mount_points = NULL, *ptr;
|
2010-11-16 01:15:21 -05:00
|
|
|
alpm_mountpoint_t *mp;
|
|
|
|
|
2012-01-19 17:21:06 -05:00
|
|
|
#if defined(HAVE_GETMNTENT) && defined(HAVE_MNTENT_H)
|
|
|
|
/* Linux */
|
2010-11-16 01:15:21 -05:00
|
|
|
struct mntent *mnt;
|
|
|
|
FILE *fp;
|
|
|
|
|
|
|
|
fp = setmntent(MOUNTED, "r");
|
|
|
|
|
2011-04-20 20:45:16 -04:00
|
|
|
if(fp == NULL) {
|
2012-06-10 21:44:19 -04:00
|
|
|
_alpm_log(handle, ALPM_LOG_ERROR, _("could not open file: %s: %s\n"),
|
|
|
|
MOUNTED, strerror(errno));
|
2011-03-20 20:45:57 -04:00
|
|
|
return NULL;
|
2010-11-16 01:15:21 -05:00
|
|
|
}
|
|
|
|
|
2010-11-16 21:12:27 -05:00
|
|
|
while((mnt = getmntent(fp))) {
|
2011-07-01 12:01:39 -04:00
|
|
|
CALLOC(mp, 1, sizeof(alpm_mountpoint_t), RET_ERR(handle, ALPM_ERR_MEMORY, NULL));
|
2014-12-23 19:56:37 -05:00
|
|
|
STRDUP(mp->mount_dir, mnt->mnt_dir, free(mp); RET_ERR(handle, ALPM_ERR_MEMORY, NULL));
|
2011-02-11 11:34:34 -05:00
|
|
|
mp->mount_dir_len = strlen(mp->mount_dir);
|
2010-11-16 01:15:21 -05:00
|
|
|
|
|
|
|
mount_points = alpm_list_add(mount_points, mp);
|
|
|
|
}
|
|
|
|
|
|
|
|
endmntent(fp);
|
2012-01-19 17:21:06 -05:00
|
|
|
#elif defined(HAVE_GETMNTENT) && defined(HAVE_MNTTAB_H)
|
|
|
|
/* Solaris, Illumos */
|
|
|
|
struct mnttab mnt;
|
|
|
|
FILE *fp;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
fp = fopen("/etc/mnttab", "r");
|
|
|
|
|
|
|
|
if(fp == NULL) {
|
2012-06-10 21:44:19 -04:00
|
|
|
_alpm_log(handle, ALPM_LOG_ERROR, _("could not open file %s: %s\n"),
|
|
|
|
"/etc/mnttab", strerror(errno));
|
2012-01-19 17:21:06 -05:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
while((ret = getmntent(fp, &mnt)) == 0) {
|
|
|
|
CALLOC(mp, 1, sizeof(alpm_mountpoint_t), RET_ERR(handle, ALPM_ERR_MEMORY, NULL));
|
2014-12-23 19:56:37 -05:00
|
|
|
STRDUP(mp->mount_dir, mnt->mnt_mountp, free(mp); RET_ERR(handle, ALPM_ERR_MEMORY, NULL));
|
2012-01-19 17:21:06 -05:00
|
|
|
mp->mount_dir_len = strlen(mp->mount_dir);
|
|
|
|
|
|
|
|
mount_points = alpm_list_add(mount_points, mp);
|
|
|
|
}
|
|
|
|
/* -1 == EOF */
|
|
|
|
if(ret != -1) {
|
|
|
|
_alpm_log(handle, ALPM_LOG_WARNING,
|
|
|
|
_("could not get filesystem information\n"));
|
|
|
|
}
|
|
|
|
|
|
|
|
fclose(fp);
|
|
|
|
#elif defined(HAVE_GETMNTINFO)
|
|
|
|
/* FreeBSD (statfs), NetBSD (statvfs), OpenBSD (statfs), OS X (statfs) */
|
2010-11-16 01:15:21 -05:00
|
|
|
int entries;
|
2010-11-16 21:12:26 -05:00
|
|
|
FSSTATSTYPE *fsp;
|
2010-11-16 01:15:21 -05:00
|
|
|
|
|
|
|
entries = getmntinfo(&fsp, MNT_NOWAIT);
|
|
|
|
|
2011-04-20 20:45:16 -04:00
|
|
|
if(entries < 0) {
|
2012-06-10 21:44:19 -04:00
|
|
|
_alpm_log(handle, ALPM_LOG_ERROR,
|
|
|
|
_("could not get filesystem information\n"));
|
2011-03-20 20:45:57 -04:00
|
|
|
return NULL;
|
2010-11-16 01:15:21 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
for(; entries-- > 0; fsp++) {
|
2011-08-15 14:44:07 -04:00
|
|
|
CALLOC(mp, 1, sizeof(alpm_mountpoint_t), RET_ERR(handle, ALPM_ERR_MEMORY, NULL));
|
2014-12-23 19:56:37 -05:00
|
|
|
STRDUP(mp->mount_dir, fsp->f_mntonname, free(mp); RET_ERR(handle, ALPM_ERR_MEMORY, NULL));
|
2011-02-11 11:34:34 -05:00
|
|
|
mp->mount_dir_len = strlen(mp->mount_dir);
|
2010-11-16 21:12:27 -05:00
|
|
|
memcpy(&(mp->fsp), fsp, sizeof(FSSTATSTYPE));
|
2011-04-04 19:37:09 -04:00
|
|
|
#if defined(HAVE_GETMNTINFO_STATVFS) && defined(HAVE_STRUCT_STATVFS_F_FLAG)
|
2011-02-08 22:19:00 -05:00
|
|
|
mp->read_only = fsp->f_flag & ST_RDONLY;
|
2011-04-04 19:37:09 -04:00
|
|
|
#elif defined(HAVE_GETMNTINFO_STATFS) && defined(HAVE_STRUCT_STATFS_F_FLAGS)
|
2011-02-08 22:19:00 -05:00
|
|
|
mp->read_only = fsp->f_flags & MNT_RDONLY;
|
|
|
|
#endif
|
2010-11-16 01:15:21 -05:00
|
|
|
|
2012-04-29 15:00:38 -04:00
|
|
|
/* we don't support lazy loading on this platform */
|
|
|
|
mp->fsinfo_loaded = MOUNT_FSINFO_LOADED;
|
|
|
|
|
2010-11-16 01:15:21 -05:00
|
|
|
mount_points = alpm_list_add(mount_points, mp);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2010-11-16 01:24:52 -05:00
|
|
|
mount_points = alpm_list_msort(mount_points, alpm_list_count(mount_points),
|
2010-11-16 21:12:27 -05:00
|
|
|
mount_point_cmp);
|
2011-03-17 06:14:06 -04:00
|
|
|
for(ptr = mount_points; ptr != NULL; ptr = ptr->next) {
|
|
|
|
mp = ptr->data;
|
2012-04-29 15:00:38 -04:00
|
|
|
_alpm_log(handle, ALPM_LOG_DEBUG, "discovered mountpoint: %s\n", mp->mount_dir);
|
2011-03-17 06:14:06 -04:00
|
|
|
}
|
2011-03-20 20:45:57 -04:00
|
|
|
return mount_points;
|
2010-11-16 01:15:21 -05:00
|
|
|
}
|
2010-11-16 00:57:39 -05:00
|
|
|
|
2011-02-07 22:33:30 -05:00
|
|
|
static alpm_mountpoint_t *match_mount_point(const alpm_list_t *mount_points,
|
|
|
|
const char *real_path)
|
2010-11-16 01:24:52 -05:00
|
|
|
{
|
2011-02-07 22:33:30 -05:00
|
|
|
const alpm_list_t *mp;
|
2010-11-16 01:24:52 -05:00
|
|
|
|
2011-02-07 22:33:30 -05:00
|
|
|
for(mp = mount_points; mp != NULL; mp = mp->next) {
|
2010-11-16 01:24:52 -05:00
|
|
|
alpm_mountpoint_t *data = mp->data;
|
|
|
|
|
2012-02-20 00:04:12 -05:00
|
|
|
/* first, check if the prefix matches */
|
2011-02-07 22:33:30 -05:00
|
|
|
if(strncmp(data->mount_dir, real_path, data->mount_dir_len) == 0) {
|
2012-02-20 00:04:12 -05:00
|
|
|
/* now, the hard work- a file like '/etc/myconfig' shouldn't map to a
|
|
|
|
* mountpoint '/e', but only '/etc'. If the mountpoint ends in a trailing
|
|
|
|
* slash, we know we didn't have a mismatch, otherwise we have to do some
|
|
|
|
* more sanity checks. */
|
|
|
|
if(data->mount_dir[data->mount_dir_len - 1] == '/') {
|
|
|
|
return data;
|
|
|
|
} else if(strlen(real_path) >= data->mount_dir_len) {
|
|
|
|
const char next = real_path[data->mount_dir_len];
|
|
|
|
if(next == '/' || next == '\0') {
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
}
|
2010-11-16 01:24:52 -05:00
|
|
|
}
|
2011-02-07 22:33:30 -05:00
|
|
|
}
|
2010-11-16 01:24:52 -05:00
|
|
|
|
|
|
|
/* should not get here... */
|
2011-03-20 20:45:57 -04:00
|
|
|
return NULL;
|
2010-11-16 01:24:52 -05:00
|
|
|
}
|
|
|
|
|
2011-06-28 00:04:00 -04:00
|
|
|
static int calculate_removed_size(alpm_handle_t *handle,
|
2011-06-28 09:26:39 -04:00
|
|
|
const alpm_list_t *mount_points, alpm_pkg_t *pkg)
|
2010-11-16 01:30:33 -05:00
|
|
|
{
|
Convert package filelists to an array instead of linked list
This accomplishes quite a few things with one rather invasive change.
1. Iteration is much more performant, due to a reduction in pointer
chasing and linear item access.
2. Data structures are smaller- we no longer have the overhead of the
linked list as the file struts are now laid out consecutively in
memory.
3. Memory allocation has been massively reworked. Before, we would
allocate three different pieces of memory per file item- the list
struct, the file struct, and the copied filename. What this resulted
in was massive fragmentation of memory when loading filelists since
the memory allocator had to leave holes all over the place. The new
situation here now removes the need for any list item allocation;
allocates the file structs in contiguous memory (and reallocs as
necessary), leaving only the strings as individually allocated. Tests
using valgrind (massif) show some pretty significant memory
reductions on the worst case `pacman -Ql > /dev/null` (366387 files
on my machine):
Before:
Peak heap: 54,416,024 B
Useful heap: 36,840,692 B
Extra heap: 17,575,332 B
After:
Peak heap: 38,004,352 B
Useful heap: 28,101,347 B
Extra heap: 9,903,005 B
Several small helper methods have been introduced, including a list to
array conversion helper as well as a filelist merge sort that works
directly on arrays.
Signed-off-by: Dan McGee <dan@archlinux.org>
2011-07-19 05:47:29 -04:00
|
|
|
size_t i;
|
|
|
|
alpm_filelist_t *filelist = alpm_pkg_get_files(pkg);
|
2010-11-16 01:30:33 -05:00
|
|
|
|
Convert package filelists to an array instead of linked list
This accomplishes quite a few things with one rather invasive change.
1. Iteration is much more performant, due to a reduction in pointer
chasing and linear item access.
2. Data structures are smaller- we no longer have the overhead of the
linked list as the file struts are now laid out consecutively in
memory.
3. Memory allocation has been massively reworked. Before, we would
allocate three different pieces of memory per file item- the list
struct, the file struct, and the copied filename. What this resulted
in was massive fragmentation of memory when loading filelists since
the memory allocator had to leave holes all over the place. The new
situation here now removes the need for any list item allocation;
allocates the file structs in contiguous memory (and reallocs as
necessary), leaving only the strings as individually allocated. Tests
using valgrind (massif) show some pretty significant memory
reductions on the worst case `pacman -Ql > /dev/null` (366387 files
on my machine):
Before:
Peak heap: 54,416,024 B
Useful heap: 36,840,692 B
Extra heap: 17,575,332 B
After:
Peak heap: 38,004,352 B
Useful heap: 28,101,347 B
Extra heap: 9,903,005 B
Several small helper methods have been introduced, including a list to
array conversion helper as well as a filelist merge sort that works
directly on arrays.
Signed-off-by: Dan McGee <dan@archlinux.org>
2011-07-19 05:47:29 -04:00
|
|
|
if(!filelist->count) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
for(i = 0; i < filelist->count; i++) {
|
|
|
|
const alpm_file_t *file = filelist->files + i;
|
2011-02-07 22:33:30 -05:00
|
|
|
alpm_mountpoint_t *mp;
|
2010-11-16 01:30:33 -05:00
|
|
|
struct stat st;
|
|
|
|
char path[PATH_MAX];
|
2012-04-08 23:32:49 -04:00
|
|
|
blkcnt_t remove_size;
|
2011-06-16 14:16:49 -04:00
|
|
|
const char *filename = file->name;
|
2010-11-16 01:30:33 -05:00
|
|
|
|
2011-02-07 22:33:30 -05:00
|
|
|
snprintf(path, PATH_MAX, "%s%s", handle->root, filename);
|
2014-06-26 11:50:34 -04:00
|
|
|
llstat(path, &st);
|
2011-02-07 22:33:30 -05:00
|
|
|
|
|
|
|
/* 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)) {
|
2010-11-16 01:30:33 -05:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2011-02-07 22:33:30 -05:00
|
|
|
mp = match_mount_point(mount_points, path);
|
2010-11-16 01:30:33 -05:00
|
|
|
if(mp == NULL) {
|
2011-07-01 12:01:38 -04:00
|
|
|
_alpm_log(handle, ALPM_LOG_WARNING,
|
2011-03-11 19:32:20 -05:00
|
|
|
_("could not determine mount point for file %s\n"), filename);
|
2010-11-16 01:30:33 -05:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2012-04-29 15:00:38 -04:00
|
|
|
/* don't check a mount that we know we can't stat */
|
|
|
|
if(mp && mp->fsinfo_loaded == MOUNT_FSINFO_FAIL) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* lazy load filesystem info */
|
|
|
|
if(mp->fsinfo_loaded == MOUNT_FSINFO_UNLOADED) {
|
|
|
|
if(mount_point_load_fsinfo(handle, mp) < 0) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-01-09 21:36:42 -05:00
|
|
|
/* the addition of (divisor - 1) performs ceil() with integer division */
|
2012-04-08 23:32:49 -04:00
|
|
|
remove_size = (st.st_size + mp->fsp.f_bsize - 1) / mp->fsp.f_bsize;
|
|
|
|
mp->blocks_needed -= remove_size;
|
2011-02-11 11:49:30 -05:00
|
|
|
mp->used |= USED_REMOVE;
|
2010-11-16 01:30:33 -05:00
|
|
|
}
|
|
|
|
|
2011-03-20 20:45:57 -04:00
|
|
|
return 0;
|
2010-11-16 01:30:33 -05:00
|
|
|
}
|
|
|
|
|
2011-06-28 00:04:00 -04:00
|
|
|
static int calculate_installed_size(alpm_handle_t *handle,
|
2011-06-28 09:26:39 -04:00
|
|
|
const alpm_list_t *mount_points, alpm_pkg_t *pkg)
|
2010-11-16 01:30:33 -05:00
|
|
|
{
|
Convert package filelists to an array instead of linked list
This accomplishes quite a few things with one rather invasive change.
1. Iteration is much more performant, due to a reduction in pointer
chasing and linear item access.
2. Data structures are smaller- we no longer have the overhead of the
linked list as the file struts are now laid out consecutively in
memory.
3. Memory allocation has been massively reworked. Before, we would
allocate three different pieces of memory per file item- the list
struct, the file struct, and the copied filename. What this resulted
in was massive fragmentation of memory when loading filelists since
the memory allocator had to leave holes all over the place. The new
situation here now removes the need for any list item allocation;
allocates the file structs in contiguous memory (and reallocs as
necessary), leaving only the strings as individually allocated. Tests
using valgrind (massif) show some pretty significant memory
reductions on the worst case `pacman -Ql > /dev/null` (366387 files
on my machine):
Before:
Peak heap: 54,416,024 B
Useful heap: 36,840,692 B
Extra heap: 17,575,332 B
After:
Peak heap: 38,004,352 B
Useful heap: 28,101,347 B
Extra heap: 9,903,005 B
Several small helper methods have been introduced, including a list to
array conversion helper as well as a filelist merge sort that works
directly on arrays.
Signed-off-by: Dan McGee <dan@archlinux.org>
2011-07-19 05:47:29 -04:00
|
|
|
size_t i;
|
|
|
|
alpm_filelist_t *filelist = alpm_pkg_get_files(pkg);
|
2010-11-16 01:30:33 -05:00
|
|
|
|
Convert package filelists to an array instead of linked list
This accomplishes quite a few things with one rather invasive change.
1. Iteration is much more performant, due to a reduction in pointer
chasing and linear item access.
2. Data structures are smaller- we no longer have the overhead of the
linked list as the file struts are now laid out consecutively in
memory.
3. Memory allocation has been massively reworked. Before, we would
allocate three different pieces of memory per file item- the list
struct, the file struct, and the copied filename. What this resulted
in was massive fragmentation of memory when loading filelists since
the memory allocator had to leave holes all over the place. The new
situation here now removes the need for any list item allocation;
allocates the file structs in contiguous memory (and reallocs as
necessary), leaving only the strings as individually allocated. Tests
using valgrind (massif) show some pretty significant memory
reductions on the worst case `pacman -Ql > /dev/null` (366387 files
on my machine):
Before:
Peak heap: 54,416,024 B
Useful heap: 36,840,692 B
Extra heap: 17,575,332 B
After:
Peak heap: 38,004,352 B
Useful heap: 28,101,347 B
Extra heap: 9,903,005 B
Several small helper methods have been introduced, including a list to
array conversion helper as well as a filelist merge sort that works
directly on arrays.
Signed-off-by: Dan McGee <dan@archlinux.org>
2011-07-19 05:47:29 -04:00
|
|
|
if(!filelist->count) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
for(i = 0; i < filelist->count; i++) {
|
|
|
|
const alpm_file_t *file = filelist->files + i;
|
2011-02-07 22:33:30 -05:00
|
|
|
alpm_mountpoint_t *mp;
|
|
|
|
char path[PATH_MAX];
|
2012-04-08 23:32:49 -04:00
|
|
|
blkcnt_t install_size;
|
2011-06-16 15:51:04 -04:00
|
|
|
const char *filename = file->name;
|
2011-02-07 22:33:30 -05:00
|
|
|
|
|
|
|
/* 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. */
|
2011-06-16 15:51:04 -04:00
|
|
|
if(S_ISDIR(file->mode) || S_ISLNK(file->mode)) {
|
2011-02-07 22:33:30 -05:00
|
|
|
continue;
|
|
|
|
}
|
2010-11-16 01:30:33 -05:00
|
|
|
|
|
|
|
/* approximate space requirements for db entries */
|
2011-02-07 22:33:30 -05:00
|
|
|
if(filename[0] == '.') {
|
2011-08-19 20:12:21 -04:00
|
|
|
filename = handle->dbpath;
|
2010-11-16 01:30:33 -05:00
|
|
|
}
|
|
|
|
|
2011-02-07 22:33:30 -05:00
|
|
|
snprintf(path, PATH_MAX, "%s%s", handle->root, filename);
|
|
|
|
|
|
|
|
mp = match_mount_point(mount_points, path);
|
2010-11-16 01:30:33 -05:00
|
|
|
if(mp == NULL) {
|
2011-07-01 12:01:38 -04:00
|
|
|
_alpm_log(handle, ALPM_LOG_WARNING,
|
2011-03-11 19:32:20 -05:00
|
|
|
_("could not determine mount point for file %s\n"), filename);
|
2010-11-16 01:30:33 -05:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2012-04-29 15:00:38 -04:00
|
|
|
/* don't check a mount that we know we can't stat */
|
|
|
|
if(mp && mp->fsinfo_loaded == MOUNT_FSINFO_FAIL) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* lazy load filesystem info */
|
|
|
|
if(mp->fsinfo_loaded == MOUNT_FSINFO_UNLOADED) {
|
|
|
|
if(mount_point_load_fsinfo(handle, mp) < 0) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-01-09 21:36:42 -05:00
|
|
|
/* the addition of (divisor - 1) performs ceil() with integer division */
|
2012-04-08 23:32:49 -04:00
|
|
|
install_size = (file->size + mp->fsp.f_bsize - 1) / mp->fsp.f_bsize;
|
|
|
|
mp->blocks_needed += install_size;
|
2011-02-11 11:49:30 -05:00
|
|
|
mp->used |= USED_INSTALL;
|
2010-11-16 01:30:33 -05:00
|
|
|
}
|
|
|
|
|
2011-06-16 15:51:04 -04:00
|
|
|
return 0;
|
2010-11-16 01:30:33 -05:00
|
|
|
}
|
|
|
|
|
2011-09-20 18:34:36 -04:00
|
|
|
static int check_mountpoint(alpm_handle_t *handle, alpm_mountpoint_t *mp)
|
|
|
|
{
|
|
|
|
/* cushion is roughly min(5% capacity, 20MiB) */
|
|
|
|
fsblkcnt_t fivepc = (mp->fsp.f_blocks / 20) + 1;
|
|
|
|
fsblkcnt_t twentymb = (20 * 1024 * 1024 / mp->fsp.f_bsize) + 1;
|
|
|
|
fsblkcnt_t cushion = fivepc < twentymb ? fivepc : twentymb;
|
|
|
|
blkcnt_t needed = mp->max_blocks_needed + cushion;
|
|
|
|
|
|
|
|
_alpm_log(handle, ALPM_LOG_DEBUG,
|
|
|
|
"partition %s, needed %jd, cushion %ju, free %ju\n",
|
|
|
|
mp->mount_dir, (intmax_t)mp->max_blocks_needed,
|
|
|
|
(uintmax_t)cushion, (uintmax_t)mp->fsp.f_bfree);
|
|
|
|
if(needed >= 0 && (fsblkcnt_t)needed > mp->fsp.f_bfree) {
|
|
|
|
_alpm_log(handle, ALPM_LOG_ERROR,
|
|
|
|
_("Partition %s too full: %jd blocks needed, %jd blocks free\n"),
|
|
|
|
mp->mount_dir, (intmax_t)needed, (uintmax_t)mp->fsp.f_bfree);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-09-07 22:48:00 -04:00
|
|
|
int _alpm_check_downloadspace(alpm_handle_t *handle, const char *cachedir,
|
|
|
|
size_t num_files, off_t *file_sizes)
|
|
|
|
{
|
2011-10-16 16:00:35 -04:00
|
|
|
alpm_list_t *mount_points;
|
2011-09-07 22:48:00 -04:00
|
|
|
alpm_mountpoint_t *cachedir_mp;
|
2012-04-29 18:26:13 -04:00
|
|
|
char resolved_cachedir[PATH_MAX];
|
2011-09-07 22:48:00 -04:00
|
|
|
size_t j;
|
|
|
|
int error = 0;
|
|
|
|
|
2013-11-08 00:44:40 -05:00
|
|
|
/* resolve the cachedir path to ensure we check the right mountpoint. We
|
2012-04-29 18:26:13 -04:00
|
|
|
* handle failures silently, and continue to use the possibly unresolved
|
|
|
|
* path. */
|
|
|
|
if(realpath(cachedir, resolved_cachedir) != NULL) {
|
|
|
|
cachedir = resolved_cachedir;
|
|
|
|
}
|
|
|
|
|
2011-09-07 22:48:00 -04:00
|
|
|
mount_points = mount_point_list(handle);
|
|
|
|
if(mount_points == NULL) {
|
|
|
|
_alpm_log(handle, ALPM_LOG_ERROR, _("could not determine filesystem mount points\n"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
cachedir_mp = match_mount_point(mount_points, cachedir);
|
2012-06-05 19:15:59 -04:00
|
|
|
if(cachedir_mp == NULL) {
|
2011-09-07 22:48:00 -04:00
|
|
|
_alpm_log(handle, ALPM_LOG_ERROR, _("could not determine cachedir mount point %s\n"),
|
|
|
|
cachedir);
|
|
|
|
error = 1;
|
|
|
|
goto finish;
|
|
|
|
}
|
|
|
|
|
2012-04-29 15:00:38 -04:00
|
|
|
if(cachedir_mp->fsinfo_loaded == MOUNT_FSINFO_UNLOADED) {
|
|
|
|
if(mount_point_load_fsinfo(handle, cachedir_mp)) {
|
|
|
|
error = 1;
|
|
|
|
goto finish;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-09-07 22:48:00 -04:00
|
|
|
/* there's no need to check for a R/O mounted filesystem here, as
|
|
|
|
* _alpm_filecache_setup will never give us a non-writable directory */
|
|
|
|
|
|
|
|
/* round up the size of each file to the nearest block and accumulate */
|
|
|
|
for(j = 0; j < num_files; j++) {
|
|
|
|
cachedir_mp->max_blocks_needed += (file_sizes[j] + cachedir_mp->fsp.f_bsize + 1) /
|
|
|
|
cachedir_mp->fsp.f_bsize;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(check_mountpoint(handle, cachedir_mp)) {
|
|
|
|
error = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
finish:
|
2011-10-16 16:00:35 -04:00
|
|
|
mount_point_list_free(mount_points);
|
2011-09-07 22:48:00 -04:00
|
|
|
|
|
|
|
if(error) {
|
|
|
|
RET_ERR(handle, ALPM_ERR_DISK_SPACE, -1);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-06-28 00:04:00 -04:00
|
|
|
int _alpm_check_diskspace(alpm_handle_t *handle)
|
2010-11-16 00:57:39 -05:00
|
|
|
{
|
2010-11-16 01:43:45 -05:00
|
|
|
alpm_list_t *mount_points, *i;
|
2011-03-17 06:14:06 -04:00
|
|
|
alpm_mountpoint_t *root_mp;
|
2011-01-07 22:06:06 -05:00
|
|
|
size_t replaces = 0, current = 0, numtargs;
|
2011-06-27 11:10:08 -04:00
|
|
|
int error = 0;
|
2010-11-16 01:43:45 -05:00
|
|
|
alpm_list_t *targ;
|
2011-06-28 09:27:16 -04:00
|
|
|
alpm_trans_t *trans = handle->trans;
|
2010-11-16 01:15:21 -05:00
|
|
|
|
2011-01-07 22:06:06 -05:00
|
|
|
numtargs = alpm_list_count(trans->add);
|
2011-06-07 17:06:16 -04:00
|
|
|
mount_points = mount_point_list(handle);
|
2010-11-16 01:15:21 -05:00
|
|
|
if(mount_points == NULL) {
|
2011-07-01 12:01:38 -04:00
|
|
|
_alpm_log(handle, ALPM_LOG_ERROR, _("could not determine filesystem mount points\n"));
|
2011-03-20 20:45:57 -04:00
|
|
|
return -1;
|
2011-03-17 06:14:06 -04:00
|
|
|
}
|
|
|
|
root_mp = match_mount_point(mount_points, handle->root);
|
|
|
|
if(root_mp == NULL) {
|
2011-07-01 12:01:38 -04:00
|
|
|
_alpm_log(handle, ALPM_LOG_ERROR, _("could not determine root mount point %s\n"),
|
2011-03-17 06:14:06 -04:00
|
|
|
handle->root);
|
2011-09-07 22:22:25 -04:00
|
|
|
error = 1;
|
|
|
|
goto finish;
|
2010-11-16 01:15:21 -05:00
|
|
|
}
|
|
|
|
|
2010-11-16 01:43:45 -05:00
|
|
|
replaces = alpm_list_count(trans->remove);
|
|
|
|
if(replaces) {
|
2010-11-16 02:07:43 -05:00
|
|
|
numtargs += replaces;
|
|
|
|
for(targ = trans->remove; targ; targ = targ->next, current++) {
|
2011-06-28 09:26:39 -04:00
|
|
|
alpm_pkg_t *local_pkg;
|
2011-01-09 21:36:42 -05:00
|
|
|
int percent = (current * 100) / numtargs;
|
2011-09-01 18:35:50 -04:00
|
|
|
PROGRESS(handle, ALPM_PROGRESS_DISKSPACE_START, "", percent,
|
2010-11-16 21:12:27 -05:00
|
|
|
numtargs, current);
|
2010-11-16 02:07:43 -05:00
|
|
|
|
2011-01-09 21:47:47 -05:00
|
|
|
local_pkg = targ->data;
|
2011-06-03 13:36:13 -04:00
|
|
|
calculate_removed_size(handle, mount_points, local_pkg);
|
2010-11-16 01:43:45 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-11-16 02:07:43 -05:00
|
|
|
for(targ = trans->add; targ; targ = targ->next, current++) {
|
2011-06-28 09:26:39 -04:00
|
|
|
alpm_pkg_t *pkg, *local_pkg;
|
2011-01-09 21:36:42 -05:00
|
|
|
int percent = (current * 100) / numtargs;
|
2011-09-01 18:35:50 -04:00
|
|
|
PROGRESS(handle, ALPM_PROGRESS_DISKSPACE_START, "", percent,
|
2010-11-16 21:12:27 -05:00
|
|
|
numtargs, current);
|
2010-11-16 02:07:43 -05:00
|
|
|
|
2010-11-16 21:12:27 -05:00
|
|
|
pkg = targ->data;
|
|
|
|
/* is this package already installed? */
|
2011-06-03 13:36:13 -04:00
|
|
|
local_pkg = _alpm_db_get_pkgfromcache(handle->db_local, pkg->name);
|
2011-01-09 21:47:47 -05:00
|
|
|
if(local_pkg) {
|
2011-06-03 13:36:13 -04:00
|
|
|
calculate_removed_size(handle, mount_points, local_pkg);
|
2010-11-16 01:43:45 -05:00
|
|
|
}
|
2011-06-03 13:36:13 -04:00
|
|
|
calculate_installed_size(handle, mount_points, pkg);
|
2010-11-16 01:43:45 -05:00
|
|
|
|
2011-08-18 01:28:53 -04:00
|
|
|
for(i = mount_points; i; i = i->next) {
|
2010-11-16 01:43:45 -05:00
|
|
|
alpm_mountpoint_t *data = i->data;
|
|
|
|
if(data->blocks_needed > data->max_blocks_needed) {
|
|
|
|
data->max_blocks_needed = data->blocks_needed;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-09-01 18:35:50 -04:00
|
|
|
PROGRESS(handle, ALPM_PROGRESS_DISKSPACE_START, "", 100,
|
2010-11-16 21:12:27 -05:00
|
|
|
numtargs, current);
|
2010-11-16 02:07:43 -05:00
|
|
|
|
2011-08-18 01:28:53 -04:00
|
|
|
for(i = mount_points; i; i = i->next) {
|
2010-11-16 01:43:45 -05:00
|
|
|
alpm_mountpoint_t *data = i->data;
|
2011-02-08 22:19:00 -05:00
|
|
|
if(data->used && data->read_only) {
|
2011-07-01 12:01:38 -04:00
|
|
|
_alpm_log(handle, ALPM_LOG_ERROR, _("Partition %s is mounted read only\n"),
|
2011-02-08 22:19:00 -05:00
|
|
|
data->mount_dir);
|
2011-06-27 11:10:08 -04:00
|
|
|
error = 1;
|
2011-09-20 18:34:36 -04:00
|
|
|
} else if(data->used & USED_INSTALL && check_mountpoint(handle, data)) {
|
|
|
|
error = 1;
|
2010-11-16 01:43:45 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-09-07 22:22:25 -04:00
|
|
|
finish:
|
2011-10-16 16:00:35 -04:00
|
|
|
mount_point_list_free(mount_points);
|
2010-11-16 01:15:21 -05:00
|
|
|
|
2011-06-27 11:10:08 -04:00
|
|
|
if(error) {
|
2011-07-01 12:01:39 -04:00
|
|
|
RET_ERR(handle, ALPM_ERR_DISK_SPACE, -1);
|
2010-11-16 01:43:45 -05:00
|
|
|
}
|
|
|
|
|
2011-03-20 20:45:57 -04:00
|
|
|
return 0;
|
2010-11-16 00:57:39 -05:00
|
|
|
}
|
|
|
|
|
2014-01-22 18:06:11 -05:00
|
|
|
/* vim: set noet: */
|