4 * Copyright (c) 2010 Pacman Development Team <pacman-dev@archlinux.org>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #if defined HAVE_GETMNTENT
24 #include <sys/statvfs.h>
25 #elif defined HAVE_GETMNTINFO_STATFS
26 #include <sys/param.h>
27 #include <sys/mount.h>
29 #include <sys/ucred.h>
31 #elif defined HAVE_GETMNTINFO_STATVFS
32 #include <sys/types.h>
33 #include <sys/statvfs.h>
40 #include <archive_entry.h>
43 #include "diskspace.h"
44 #include "alpm_list.h"
49 static int mount_point_cmp(const alpm_mountpoint_t
*mp1
, const alpm_mountpoint_t
*mp2
)
51 return(strcmp(mp1
->mount_dir
, mp2
->mount_dir
));
54 static alpm_list_t
*mount_point_list()
56 alpm_list_t
*mount_points
= NULL
;
57 alpm_mountpoint_t
*mp
;
59 #if defined HAVE_GETMNTENT
64 fp
= setmntent(MOUNTED
, "r");
70 while((mnt
= getmntent (fp
))) {
71 if(statvfs(mnt
->mnt_dir
, &fsp
) != 0) {
72 _alpm_log(PM_LOG_WARNING
, "could not get filesystem information for %s\n", mnt
->mnt_dir
);
76 MALLOC(mp
, sizeof(alpm_mountpoint_t
), RET_ERR(PM_ERR_MEMORY
, NULL
));
77 mp
->mount_dir
= strdup(mnt
->mnt_dir
);
79 MALLOC(mp
->fsp
, sizeof(struct statvfs
), RET_ERR(PM_ERR_MEMORY
, NULL
));
80 memcpy((void *)(mp
->fsp
), (void *)(&fsp
), sizeof(struct statvfs
));
82 mp
->blocks_needed
= 0;
83 mp
->max_blocks_needed
= 0;
86 mount_points
= alpm_list_add(mount_points
, mp
);
90 #elif defined HAVE_GETMNTINFO_STATFS
94 entries
= getmntinfo(&fsp
, MNT_NOWAIT
);
100 for(; entries
-- > 0; fsp
++) {
101 MALLOC(mp
, sizeof(alpm_mountpoint_t
), RET_ERR(PM_ERR_MEMORY
, NULL
));
102 mp
->mount_dir
= strdup(fsp
->f_mntonname
);
104 MALLOC(mp
->fsp
, sizeof(struct statfs
), RET_ERR(PM_ERR_MEMORY
, NULL
));
105 memcpy((void *)(mp
->fsp
), (void *)fsp
, sizeof(struct statfs
));
107 mp
->blocks_needed
= 0;
108 mp
->max_blocks_needed
= 0;
110 mount_points
= alpm_list_add(mount_points
, mp
);
112 #elif defined HAVE_GETMNTINFO_STATVFS
116 entries
= getmntinfo(&fsp
, MNT_NOWAIT
);
122 for (; entries
-- > 0; fsp
++) {
123 MALLOC(mp
, sizeof(alpm_mountpoint_t
), RET_ERR(PM_ERR_MEMORY
, NULL
));
124 mp
->mount_dir
= strdup(fsp
->f_mntonname
);
126 MALLOC(mp
->fsp
, sizeof(struct statvfs
), RET_ERR(PM_ERR_MEMORY
, NULL
));
127 memcpy((void *)(mp
->fsp
), (void *)fsp
, sizeof(struct statvfs
));
129 mp
->blocks_needed
= 0;
130 mp
->max_blocks_needed
= 0;
132 mount_points
= alpm_list_add(mount_points
, mp
);
136 mount_points
= alpm_list_msort(mount_points
, alpm_list_count(mount_points
),
137 (alpm_list_fn_cmp
)mount_point_cmp
);
138 return(mount_points
);
141 static alpm_list_t
*match_mount_point(const alpm_list_t
*mount_points
, const char *file
)
143 char real_path
[PATH_MAX
];
144 snprintf(real_path
, PATH_MAX
, "%s%s", handle
->root
, file
);
146 alpm_list_t
*mp
= alpm_list_last(mount_points
);
148 alpm_mountpoint_t
*data
= mp
->data
;
150 if(strncmp(data
->mount_dir
, real_path
, strlen(data
->mount_dir
)) == 0) {
155 } while (mp
!= alpm_list_last(mount_points
));
157 /* should not get here... */
161 static int calculate_removed_size(pmpkg_t
*pkg
, const alpm_list_t
*mount_points
)
165 alpm_list_t
*files
= alpm_pkg_get_files(pkg
);
166 for(file
= files
; file
; file
= file
->next
) {
168 alpm_mountpoint_t
*data
;
172 /* skip directories to be consistent with libarchive that reports them to be zero size
173 and to prevent multiple counting across packages */
174 if(*((char *)(file
->data
) + strlen(file
->data
) - 1) == '/') {
178 mp
= match_mount_point(mount_points
, file
->data
);
180 _alpm_log(PM_LOG_WARNING
, _("could not determine mount point for file %s"), (char *)(file
->data
));
184 snprintf(path
, PATH_MAX
, "%s%s", handle
->root
, (char *)file
->data
);
185 _alpm_lstat(path
, &st
);
187 /* skip symlinks to be consistent with libarchive that reports them to be zero size */
188 if(S_ISLNK(st
.st_mode
)) {
193 data
->blocks_needed
-= ceil((double)(st
.st_size
) /
194 (double)(data
->fsp
->f_bsize
));
201 static int calculate_installed_size(pmpkg_t
*pkg
, const alpm_list_t
*mount_points
)
204 struct archive
*archive
;
205 struct archive_entry
*entry
;
208 if ((archive
= archive_read_new()) == NULL
) {
209 pm_errno
= PM_ERR_LIBARCHIVE
;
214 archive_read_support_compression_all(archive
);
215 archive_read_support_format_all(archive
);
217 if(archive_read_open_filename(archive
, pkg
->origin_data
.file
,
218 ARCHIVE_DEFAULT_BYTES_PER_BLOCK
) != ARCHIVE_OK
) {
219 pm_errno
= PM_ERR_PKG_OPEN
;
224 while(archive_read_next_header(archive
, &entry
) == ARCHIVE_OK
) {
226 alpm_mountpoint_t
*data
;
228 file
= archive_entry_pathname(entry
);
230 /* approximate space requirements for db entries */
231 if(strcmp(file
, ".PKGINFO") == 0 ||
232 strcmp(file
, ".INSTALL") == 0 ||
233 strcmp(file
, ".CHANGELOG") == 0) {
234 file
= alpm_option_get_dbpath();
237 mp
= match_mount_point(mount_points
, file
);
239 _alpm_log(PM_LOG_WARNING
, _("could not determine mount point for file %s"), archive_entry_pathname(entry
));
244 data
->blocks_needed
+= ceil((double)(archive_entry_size(entry
)) /
245 (double)(data
->fsp
->f_bsize
));
249 archive_read_finish(archive
);
255 int _alpm_check_diskspace(pmtrans_t
*trans
, pmdb_t
*db
)
257 alpm_list_t
*mount_points
;
259 mount_points
= mount_point_list();
260 if(mount_points
== NULL
) {
261 _alpm_log(PM_LOG_ERROR
, _("count not determine filesystem mount points"));
265 for(i
= mount_points
; i
; i
= alpm_list_next(i
)) {
266 alpm_mountpoint_t
*data
= i
->data
;
267 FREE(data
->mount_dir
);
270 FREELIST(mount_points
);
275 /* vim: set ts=2 sw=2 noet: */