|
|
9ab6cd |
From 0214512479e04a3e118cbef8703aa1aec5240f3f Mon Sep 17 00:00:00 2001
|
|
|
9ab6cd |
From: Jan Kara <jack@suse.cz>
|
|
|
9ab6cd |
Date: Thu, 1 May 2014 18:08:09 +0200
|
|
|
9ab6cd |
Subject: [PATCH] Properly handle signed space and inode values
|
|
|
9ab6cd |
MIME-Version: 1.0
|
|
|
9ab6cd |
Content-Type: text/plain; charset=UTF-8
|
|
|
9ab6cd |
Content-Transfer-Encoding: 8bit
|
|
|
9ab6cd |
|
|
|
9ab6cd |
For cluster filesystems, kernel can sometimes return negative values of
|
|
|
9ab6cd |
used space or inodes (because counters are not completely synchronized
|
|
|
9ab6cd |
across the cluster). Make quota tools properly print these.
|
|
|
9ab6cd |
|
|
|
9ab6cd |
Signed-off-by: Jan Kara <jack@suse.cz>
|
|
|
9ab6cd |
Signed-off-by: Petr Písař <ppisar@redhat.com>
|
|
|
9ab6cd |
---
|
|
|
9ab6cd |
quotasys.c | 47 +++++++++++++++++++++++++++++++----------------
|
|
|
9ab6cd |
quotasys.h | 2 +-
|
|
|
9ab6cd |
2 files changed, 32 insertions(+), 17 deletions(-)
|
|
|
9ab6cd |
|
|
|
9ab6cd |
diff --git a/quotasys.c b/quotasys.c
|
|
|
9ab6cd |
index dee5118..120125a 100644
|
|
|
9ab6cd |
--- a/quotasys.c
|
|
|
9ab6cd |
+++ b/quotasys.c
|
|
|
9ab6cd |
@@ -376,6 +376,7 @@ int str2timeunits(time_t num, char *unit, time_t *res)
|
|
|
9ab6cd |
return 0;
|
|
|
9ab6cd |
}
|
|
|
9ab6cd |
|
|
|
9ab6cd |
+#define DIV_ROUND_UP(x, d) (((x) + d - 1) / d)
|
|
|
9ab6cd |
/*
|
|
|
9ab6cd |
* Convert number in quota blocks to some nice short form for printing
|
|
|
9ab6cd |
*/
|
|
|
9ab6cd |
@@ -383,18 +384,26 @@ void space2str(qsize_t space, char *buf, int format)
|
|
|
9ab6cd |
{
|
|
|
9ab6cd |
int i;
|
|
|
9ab6cd |
char suffix[8] = " MGT";
|
|
|
9ab6cd |
+ qsize_t aspace = space >= 0 ? space : -space;
|
|
|
9ab6cd |
|
|
|
9ab6cd |
space = qb2kb(space);
|
|
|
9ab6cd |
if (format) {
|
|
|
9ab6cd |
- for (i = 3; i > 0; i--)
|
|
|
9ab6cd |
- if (space >= (1LL << (QUOTABLOCK_BITS*i))*100) {
|
|
|
9ab6cd |
- sprintf(buf, "%llu%c", (unsigned long long)(space+(1 << (QUOTABLOCK_BITS*i))-1) >> (QUOTABLOCK_BITS*i), suffix[i]);
|
|
|
9ab6cd |
+ for (i = 3; i > 0; i--) {
|
|
|
9ab6cd |
+ long long unit = 1LL << (QUOTABLOCK_BITS*i);
|
|
|
9ab6cd |
+
|
|
|
9ab6cd |
+ if (aspace >= unit * 100) {
|
|
|
9ab6cd |
+ int sign = aspace != space ? -1 : 1;
|
|
|
9ab6cd |
+
|
|
|
9ab6cd |
+ sprintf(buf, "%lld%c", (long long)
|
|
|
9ab6cd |
+ DIV_ROUND_UP(aspace, unit) * sign,
|
|
|
9ab6cd |
+ suffix[i]);
|
|
|
9ab6cd |
return;
|
|
|
9ab6cd |
}
|
|
|
9ab6cd |
- sprintf(buf, "%lluK", (unsigned long long)space);
|
|
|
9ab6cd |
+ }
|
|
|
9ab6cd |
+ sprintf(buf, "%lldK", (long long)space);
|
|
|
9ab6cd |
return;
|
|
|
9ab6cd |
}
|
|
|
9ab6cd |
- sprintf(buf, "%llu", (unsigned long long)space);
|
|
|
9ab6cd |
+ sprintf(buf, "%lld", (long long)space);
|
|
|
9ab6cd |
}
|
|
|
9ab6cd |
|
|
|
9ab6cd |
/*
|
|
|
9ab6cd |
@@ -404,11 +413,11 @@ void space2str(qsize_t space, char *buf, int format)
|
|
|
9ab6cd |
const char *str2space(const char *string, qsize_t *space)
|
|
|
9ab6cd |
{
|
|
|
9ab6cd |
char *unit;
|
|
|
9ab6cd |
- unsigned long long int number;
|
|
|
9ab6cd |
+ long long int number;
|
|
|
9ab6cd |
int unit_shift;
|
|
|
9ab6cd |
|
|
|
9ab6cd |
- number = strtoull(string, &unit, 0);
|
|
|
9ab6cd |
- if (ULLONG_MAX == number)
|
|
|
9ab6cd |
+ number = strtoll(string, &unit, 0);
|
|
|
9ab6cd |
+ if (number == LLONG_MAX || number == LLONG_MIN)
|
|
|
9ab6cd |
return _("Integer overflow while parsing space number.");
|
|
|
9ab6cd |
|
|
|
9ab6cd |
if (!unit || unit[0] == '\0' || !strcmp(unit, _("K")))
|
|
|
9ab6cd |
@@ -422,7 +431,8 @@ const char *str2space(const char *string, qsize_t *space)
|
|
|
9ab6cd |
else
|
|
|
9ab6cd |
return _("Unknown space binary unit. "
|
|
|
9ab6cd |
"Valid units are K, M, G, T.");
|
|
|
9ab6cd |
- if (number > (QSIZE_MAX >> unit_shift))
|
|
|
9ab6cd |
+ if (number > (QSIZE_MAX >> unit_shift) ||
|
|
|
9ab6cd |
+ number < -(QSIZE_MAX >> unit_shift))
|
|
|
9ab6cd |
return _("Integer overflow while interpreting space unit.");
|
|
|
9ab6cd |
*space = number << unit_shift;
|
|
|
9ab6cd |
return NULL;
|
|
|
9ab6cd |
@@ -431,19 +441,23 @@ const char *str2space(const char *string, qsize_t *space)
|
|
|
9ab6cd |
/*
|
|
|
9ab6cd |
* Convert number to some nice short form for printing
|
|
|
9ab6cd |
*/
|
|
|
9ab6cd |
-void number2str(unsigned long long num, char *buf, int format)
|
|
|
9ab6cd |
+void number2str(long long num, char *buf, int format)
|
|
|
9ab6cd |
{
|
|
|
9ab6cd |
int i;
|
|
|
9ab6cd |
unsigned long long div;
|
|
|
9ab6cd |
char suffix[8] = " kmgt";
|
|
|
9ab6cd |
+ long long anum = num >= 0 ? num : -num;
|
|
|
9ab6cd |
|
|
|
9ab6cd |
if (format)
|
|
|
9ab6cd |
for (i = 4, div = 1000000000000LL; i > 0; i--, div /= 1000)
|
|
|
9ab6cd |
if (num >= 100*div) {
|
|
|
9ab6cd |
- sprintf(buf, "%llu%c", (num+div-1) / div, suffix[i]);
|
|
|
9ab6cd |
+ int sign = num != anum ? -1 : 1;
|
|
|
9ab6cd |
+
|
|
|
9ab6cd |
+ sprintf(buf, "%lld%c", (num+div-1) / div * sign,
|
|
|
9ab6cd |
+ suffix[i]);
|
|
|
9ab6cd |
return;
|
|
|
9ab6cd |
}
|
|
|
9ab6cd |
- sprintf(buf, "%llu", num);
|
|
|
9ab6cd |
+ sprintf(buf, "%lld", num);
|
|
|
9ab6cd |
}
|
|
|
9ab6cd |
|
|
|
9ab6cd |
/*
|
|
|
9ab6cd |
@@ -453,10 +467,10 @@ void number2str(unsigned long long num, char *buf, int format)
|
|
|
9ab6cd |
const char *str2number(const char *string, qsize_t *inodes)
|
|
|
9ab6cd |
{
|
|
|
9ab6cd |
char *unit;
|
|
|
9ab6cd |
- unsigned long long int number, multiple;
|
|
|
9ab6cd |
+ long long int number, multiple;
|
|
|
9ab6cd |
|
|
|
9ab6cd |
- number = strtoull(string, &unit, 0);
|
|
|
9ab6cd |
- if (ULLONG_MAX == number)
|
|
|
9ab6cd |
+ number = strtoll(string, &unit, 0);
|
|
|
9ab6cd |
+ if (number == LLONG_MAX || number == LLONG_MIN)
|
|
|
9ab6cd |
return _("Integer overflow while parsing number.");
|
|
|
9ab6cd |
|
|
|
9ab6cd |
if (!unit || unit[0] == '\0')
|
|
|
9ab6cd |
@@ -472,7 +486,8 @@ const char *str2number(const char *string, qsize_t *inodes)
|
|
|
9ab6cd |
else
|
|
|
9ab6cd |
return _("Unknown decimal unit. "
|
|
|
9ab6cd |
"Valid units are k, m, g, t.");
|
|
|
9ab6cd |
- if (number > QSIZE_MAX / multiple)
|
|
|
9ab6cd |
+ if (number > QSIZE_MAX / multiple ||
|
|
|
9ab6cd |
+ -number < QSIZE_MAX / multiple)
|
|
|
9ab6cd |
return _("Integer overflow while interpreting decimal unit.");
|
|
|
9ab6cd |
*inodes = number * multiple;
|
|
|
9ab6cd |
return NULL;
|
|
|
9ab6cd |
diff --git a/quotasys.h b/quotasys.h
|
|
|
9ab6cd |
index 5ca26e6..e79f8cd 100644
|
|
|
9ab6cd |
--- a/quotasys.h
|
|
|
9ab6cd |
+++ b/quotasys.h
|
|
|
9ab6cd |
@@ -113,7 +113,7 @@ void space2str(qsize_t, char *, int);
|
|
|
9ab6cd |
const char *str2space(const char *string, qsize_t *space);
|
|
|
9ab6cd |
|
|
|
9ab6cd |
/* Convert number to short printable form */
|
|
|
9ab6cd |
-void number2str(unsigned long long, char *, int);
|
|
|
9ab6cd |
+void number2str(long long, char *, int);
|
|
|
9ab6cd |
|
|
|
9ab6cd |
/* Convert inode number with unit from string to quota inodes. */
|
|
|
9ab6cd |
const char *str2number(const char *string, qsize_t *inodes);
|
|
|
9ab6cd |
--
|
|
|
9ab6cd |
2.13.6
|
|
|
9ab6cd |
|