Abort transaction if there's not enough free space on disk.

Close #7.
This commit is contained in:
Juan RP 2014-07-13 11:45:04 +02:00
parent 79fe312302
commit 4356b6fd65
4 changed files with 40 additions and 5 deletions

5
NEWS
View File

@ -1,5 +1,10 @@
xbps-0.38 (???):
* Before accepting a transaction, xbps now checks if there's enough free space
on the target rootdir (on disk) to proceed with the operation. In code terms,
xbps_transaction_prepare() now returns ENOSPC if the size of the transaction
exceeds the size of the free space. Close issue #7.
* When installing or updating packages, now proper statistics are generated
when a binary package from a repository repository exists in the cachedir,
and when a package has the "preserve" property.

View File

@ -1,5 +1,5 @@
/*-
* Copyright (c) 2009-2013 Juan Romero Pardines.
* Copyright (c) 2009-2014 Juan Romero Pardines.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -97,7 +97,7 @@ show_package_list(xbps_object_iterator_t iter, const char *match, int cols)
static int
show_transaction_sizes(struct transaction *trans, int cols)
{
uint64_t dlsize = 0, instsize = 0, rmsize = 0;
uint64_t dlsize = 0, instsize = 0, rmsize = 0, disk_free_size = 0;
char size[8];
/*
@ -139,10 +139,10 @@ show_transaction_sizes(struct transaction *trans, int cols)
* Show total download/installed/removed size for all required packages.
*/
xbps_dictionary_get_uint64(trans->d, "total-download-size", &dlsize);
xbps_dictionary_get_uint64(trans->d, "total-installed-size",
&instsize);
xbps_dictionary_get_uint64(trans->d, "total-installed-size", &instsize);
xbps_dictionary_get_uint64(trans->d, "total-removed-size", &rmsize);
if (dlsize || instsize || rmsize)
xbps_dictionary_get_uint64(trans->d, "disk-free-size", &disk_free_size);
if (dlsize || instsize || rmsize || disk_free_size)
printf("\n");
if (dlsize) {
@ -169,6 +169,14 @@ show_transaction_sizes(struct transaction *trans, int cols)
}
printf("Size freed on disk: %6s\n", size);
}
if (disk_free_size) {
if (xbps_humanize_number(size, (int64_t)disk_free_size) == -1) {
xbps_error_printf("humanize_number3 returns "
"%s\n", strerror(errno));
return -1;
}
printf("Free space on disk: %6s\n", size);
}
printf("\n");
return 0;

View File

@ -1121,6 +1121,8 @@ int xbps_transaction_autoremove_pkgs(struct xbps_handle *xhp);
* array of strings object in xhp->transd dictionary).
* @retval EAGAIN if there are package conflicts in transaction ("conflicts"
* array of strings object in xhp->transd dictionary).
* @retval ENOSPC Not enough free space on target rootdir to continue with the
* transaction.
* @retval EINVAL There was an error sorting packages or computing the transaction
* sizes.
*/

View File

@ -28,6 +28,7 @@
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/statvfs.h>
#include "xbps_api_impl.h"
@ -58,6 +59,8 @@ compute_transaction_stats(struct xbps_handle *xhp)
xbps_dictionary_t pkg_metad;
xbps_object_iterator_t iter;
xbps_object_t obj;
struct statvfs svfs;
unsigned long rootdir_free_size;
uint64_t tsize, dlsize, instsize, rmsize;
uint32_t inst_pkgcnt, up_pkgcnt, cf_pkgcnt, rm_pkgcnt;
const char *tract, *pkgver, *repo;
@ -101,6 +104,8 @@ compute_transaction_stats(struct xbps_handle *xhp)
!xbps_binpkg_exists(xhp, obj)) {
xbps_dictionary_get_uint64(obj,
"filename-size", &tsize);
/* signature file: 512 bytes */
tsize += 512;
dlsize += tsize;
instsize += tsize;
}
@ -159,6 +164,21 @@ compute_transaction_stats(struct xbps_handle *xhp)
"total-removed-size", rmsize))
return EINVAL;
/* Get free space from target rootdir: return ENOSPC if there's not enough space */
if (statvfs(xhp->rootdir, &svfs) == -1) {
xbps_dbg_printf(xhp, "%s: statvfs failed: %s\n", __func__, strerror(errno));
return EINVAL;
}
/* compute free space on disk */
rootdir_free_size = svfs.f_bfree * svfs.f_bsize - instsize;
if (!xbps_dictionary_set_uint64(xhp->transd,
"disk-free-size", rootdir_free_size))
return EINVAL;
if (instsize > rootdir_free_size)
return ENOSPC;
return 0;
}