du: support -b "apparent size"

function                                             old     new   delta
du                                                   434     470     +36
packed_usage                                       33542   33570     +28
print                                                 57      78     +21
du_main                                              286     302     +16
.rodata                                           103187  103188      +1
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 5/0 up/down: 102/0)             Total: 102 bytes

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
diff --git a/coreutils/du.c b/coreutils/du.c
index c8aedb6..832dd75 100644
--- a/coreutils/du.c
+++ b/coreutils/du.c
@@ -42,6 +42,7 @@
 //usage:#define du_full_usage "\n\n"
 //usage:       "Summarize disk space used for FILEs (or directories)\n"
 //usage:     "\n	-a	Show file sizes too"
+//usage:     "\n	-b	Apparent size (including holes)"
 //usage:     "\n	-L	Follow all symlinks"
 //usage:     "\n	-H	Follow symlinks on command line"
 //usage:     "\n	-d N	Limit output to directories (and files with -a) of depth < N"
@@ -84,8 +85,9 @@
 	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              = (1 << 9),
+	OPT_h_for_humans   = (1 << 10),
+	OPT_m_mbytes       = (1 << 11),
 };
 
 struct globals {
@@ -109,7 +111,7 @@
 	/* TODO - May not want to defer error checking here. */
 #if ENABLE_FEATURE_HUMAN_READABLE
 # if ENABLE_DESKTOP
-	/* ~30 bytes of code for extra comtat:
+	/* ~30 bytes of code for extra compat:
 	 * coreutils' du rounds sizes up:
 	 * for example,  1025k file is shown as "2" by du -m.
 	 * We round to nearest if human-readable [too hard to fix],
@@ -124,12 +126,16 @@
 			 * 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, (option_mask32 & OPT_b) ? 1 : 512, G.disp_unit),
 			filename);
 #else
 	if (G.disp_k) {
-		size++;
-		size >>= 1;
+		if (!(option_mask32 & OPT_b)) {
+			size++;
+			size >>= 1;
+		} else {
+			size >>= 10;
+		}
 	}
 	printf("%llu\t%s\n", size, filename);
 #endif
@@ -155,7 +161,7 @@
 		}
 	}
 
-	sum = statbuf.st_blocks;
+	sum = ((option_mask32 & OPT_b) ? statbuf.st_size : statbuf.st_blocks);
 
 	if (S_ISLNK(statbuf.st_mode)) {
 		if (G.slink_depth > G.du_depth) { /* -H or -L */
@@ -164,7 +170,7 @@
 				G.status = EXIT_FAILURE;
 				return 0;
 			}
-			sum = statbuf.st_blocks;
+			sum = ((option_mask32 & OPT_b) ? statbuf.st_size : statbuf.st_blocks);
 			if (G.slink_depth == 1) {
 				/* Convert -H to -L */
 				G.slink_depth = INT_MAX;
@@ -241,11 +247,14 @@
 	 */
 #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) {
+		G.disp_unit = 1;
+	}
 	if (opt & OPT_h_for_humans) {
 		G.disp_unit = 0;
 	}
@@ -257,16 +266,16 @@
 	}
 #else
 	opt = getopt32(argv, "^"
-			"aHkLsxd:+lc"
+			"aHkLsxd:+lcb"
 			"\0" "H-L:L-H:s-d:d-s",
 			&G.max_print_depth
 	);
 	argv += optind;
-#if !ENABLE_FEATURE_DU_DEFAULT_BLOCKSIZE_1K
+# if !ENABLE_FEATURE_DU_DEFAULT_BLOCKSIZE_1K
 	if (opt & OPT_k_kbytes) {
 		G.disp_k = 1;
 	}
-#endif
+# endif
 #endif
 	if (opt & OPT_H_follow_links) {
 		G.slink_depth = 1;