[PATCH 1/1] du: add -b option (print apparent size in bytes, rather than disk usage)

Alexander Mikhalitsyn alexander at mihalicyn.com
Sat Feb 15 13:31:53 UTC 2020


Signed-off-by: Alexander Mikhalitsyn <alexander at mihalicyn.com>
---
 coreutils/du.c | 70 ++++++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 60 insertions(+), 10 deletions(-)

diff --git a/coreutils/du.c b/coreutils/du.c
index d14d9e4ea..abf9d2ef0 100644
--- a/coreutils/du.c
+++ b/coreutils/du.c
@@ -57,6 +57,7 @@
 //usage:	IF_NOT_FEATURE_DU_DEFAULT_BLOCKSIZE_1K(
 //usage:     "\n		Default unit is 512 bytes"
 //usage:	)
+//usage:     "\n	-b	Print apparent sizes in bytes, rather than disk blocks usage"
 //usage:
 //usage:#define du_example_usage
 //usage:       "$ du\n"
@@ -84,8 +85,9 @@ enum {
 	OPT_d_maxdepth     = (1 << 6),
 	OPT_l_hardlinks    = (1 << 7),
 	OPT_c_total        = (1 << 8),
-	OPT_h_for_humans   = (1 << 9),
-	OPT_m_mbytes       = (1 << 10),
+	OPT_b_apparent_size = (1 << 9),
+	OPT_h_for_humans   = (1 << 10),
+	OPT_m_mbytes       = (1 << 11),
 };
 
 struct globals {
@@ -94,6 +96,7 @@ struct globals {
 #else
 	unsigned disp_k;
 #endif
+	unsigned int size_unit;
 	int max_print_depth;
 	bool status;
 	int slink_depth;
@@ -120,21 +123,43 @@ static void print(unsigned long long size, const char *filename)
 		size += (G.disp_unit-1) / (unsigned)(512 * 2);
 # endif
 	printf("%s\t%s\n",
-			/* size x 512 / G.disp_unit.
+			/* size x G.size_unit / G.disp_unit.
 			 * If G.disp_unit == 0, show one fractional
 			 * and use suffixes
 			 */
-			make_human_readable_str(size, 512, G.disp_unit),
+			make_human_readable_str(size, G.size_unit, G.disp_unit),
 			filename);
 #else
 	if (G.disp_k) {
-		size++;
-		size >>= 1;
+		if (option_mask32 & OPT_b_apparent_size) {
+			size += 1023;
+			size >>= 10;
+		} else {
+			size++;
+			size >>= 1;
+		}
 	}
+
 	printf("%llu\t%s\n", size, filename);
 #endif
 }
 
+static ALWAYS_INLINE unsigned long long file_size(struct stat *statbufp)
+{
+	if (option_mask32 & OPT_b_apparent_size) {
+		/*
+		 * Yes, we need to return MAX(0, statbufp->st_size)
+		 * this is weird but, please, refer to
+		 * 9d308df13271a852aee7d46c65432fa84145ea31 commit
+		 * (maint: handle file sizes more reliably)
+		 * in GNU coreutils
+		 */
+		return MAX(0, statbufp->st_size);
+	} else {
+		return statbufp->st_blocks;
+	}
+}
+
 /* tiny recursive du */
 static unsigned long long du(const char *filename)
 {
@@ -155,7 +180,7 @@ static unsigned long long du(const char *filename)
 		}
 	}
 
-	sum = statbuf.st_blocks;
+	sum = file_size(&statbuf);
 
 	if (S_ISLNK(statbuf.st_mode)) {
 		if (G.slink_depth > G.du_depth) { /* -H or -L */
@@ -164,7 +189,7 @@ static unsigned long long du(const char *filename)
 				G.status = EXIT_FAILURE;
 				return 0;
 			}
-			sum = statbuf.st_blocks;
+			sum = file_size(&statbuf);
 			if (G.slink_depth == 1) {
 				/* Convert -H to -L */
 				G.slink_depth = INT_MAX;
@@ -241,11 +266,14 @@ int du_main(int argc UNUSED_PARAM, char **argv)
 	 */
 #if ENABLE_FEATURE_HUMAN_READABLE
 	opt = getopt32(argv, "^"
-			"aHkLsxd:+lchm"
+			"aHkLsxd:+lcbhm"
 			"\0" "h-km:k-hm:m-hk:H-L:L-H:s-d:d-s",
 			&G.max_print_depth
 	);
 	argv += optind;
+	if (opt & OPT_b_apparent_size) {
+		G.disp_unit = 1;
+	}
 	if (opt & OPT_h_for_humans) {
 		G.disp_unit = 0;
 	}
@@ -257,7 +285,7 @@ int du_main(int argc UNUSED_PARAM, char **argv)
 	}
 #else
 	opt = getopt32(argv, "^"
-			"aHkLsxd:+lc"
+			"aHkLsxd:+lcb"
 			"\0" "H-L:L-H:s-d:d-s",
 			&G.max_print_depth
 	);
@@ -266,8 +294,30 @@ int du_main(int argc UNUSED_PARAM, char **argv)
 	if (opt & OPT_k_kbytes) {
 		G.disp_k = 1;
 	}
+#else
+	/*
+	 * If FEATURE_DU_DEFAULT_BLOCKSIZE_1K is enabled
+	 * we have already set G.disp_k = 1 but this is incorrect.
+	 * For example, if we called du -b we need to
+	 * print size in bytes not in KBytes.
+	 */
+	if (!(opt & OPT_k_kbytes) && (opt & OPT_b_apparent_size)) {
+		G.disp_k = 0;
+	}
 #endif
 #endif
+
+	/*
+	 * When OPT_b_apparent_size is enabled file_size()
+	 * function will return sb->st_size instead of
+	 * sb->st_blocks therefore we need to assume
+	 * that "block" size is 1.
+	 */
+	G.size_unit = 512;
+	if (opt & OPT_b_apparent_size) {
+		G.size_unit = 1;
+	}
+
 	if (opt & OPT_H_follow_links) {
 		G.slink_depth = 1;
 	}
-- 
2.19.1



More information about the busybox mailing list