Blame SOURCES/quota-4.01-Properly-handle-signed-space-and-inode-values.patch

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