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

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