Add the ability to specify a reserved space size when making filesystems.

If you specify a negative length when making a filesystem, then the
filesystem size is the size of the partiton (or image file) minus
the absolute value of the negative length specified.

Change-Id: I53e3b6de2ea692f4678682c3f49ff36429d9ad31
diff --git a/ext4_utils/ext4_utils.c b/ext4_utils/ext4_utils.c
index 1804e4b..bdf2a74 100644
--- a/ext4_utils/ext4_utils.c
+++ b/ext4_utils/ext4_utils.c
@@ -103,7 +103,7 @@
 
 	for_each_data_block(count_data_block, count_file_block, &count_chunks);
 
-	if (count_chunks.cur_ptr != info.len)
+	if (count_chunks.cur_ptr != (u64) info.len)
 		count_chunks.chunks++;
 
 	return count_chunks.chunks;
@@ -442,17 +442,29 @@
 {
 	struct stat buf;
 	int ret;
+	u64 reserve_len = 0;
+	s64 computed_size;
 
 	ret = stat(filename, &buf);
 	if (ret)
 		return 0;
 
+	if (info.len < 0)
+		reserve_len = -info.len;
+
 	if (S_ISREG(buf.st_mode))
-		return buf.st_size;
+		computed_size = buf.st_size - reserve_len;
 	else if (S_ISBLK(buf.st_mode))
-		return get_block_device_size(filename);
+		computed_size = get_block_device_size(filename) - reserve_len;
 	else
-		return 0;
+		computed_size = 0;
+
+	if (computed_size < 0) {
+		warn("Computed filesystem size less than 0");
+		computed_size = 0;
+	}
+
+	return computed_size;
 }
 
 u64 parse_num(const char *arg)
diff --git a/ext4_utils/ext4_utils.h b/ext4_utils/ext4_utils.h
index 8f3a64d..b770294 100644
--- a/ext4_utils/ext4_utils.h
+++ b/ext4_utils/ext4_utils.h
@@ -76,6 +76,7 @@
 #define __u8 u8
 
 typedef unsigned long long u64;
+typedef signed long long s64;
 typedef unsigned int u32;
 typedef unsigned short int u16;
 typedef unsigned char u8;
@@ -94,7 +95,9 @@
 };
 
 struct fs_info {
-	u64 len;
+	s64 len;	/* If set to 0, ask the block device for the size,
+			 * if less than 0, reserve that much space at the
+			 * end of the partition, else use the size given. */
 	u32 block_size;
 	u32 blocks_per_group;
 	u32 inodes_per_group;
diff --git a/ext4_utils/make_ext4fs.c b/ext4_utils/make_ext4fs.c
index 3fee133..a366a37 100644
--- a/ext4_utils/make_ext4fs.c
+++ b/ext4_utils/make_ext4fs.c
@@ -249,7 +249,7 @@
         u32 root_inode_num;
         u16 root_mode;
 
-	if (info.len == 0)
+	if (info.len <= 0)
 		info.len = get_file_size(filename);
 
 	if (info.len <= 0) {
diff --git a/ext4_utils/output_file.c b/ext4_utils/output_file.c
index 66550d5..c1997b6 100644
--- a/ext4_utils/output_file.c
+++ b/ext4_utils/output_file.c
@@ -333,7 +333,7 @@
 {
 	int ret;
 
-	if (len > info.len) {
+	if (len > (u64) info.len) {
 		error("attempted to pad file %llu bytes past end of filesystem",
 				len - info.len);
 		return;
@@ -370,7 +370,7 @@
 {
 	int ret;
 	
-	if (off + len > info.len) {
+	if (off + len > (u64) info.len) {
 		error("attempted to write block %llu past end of filesystem",
 				off + len - info.len);
 		return;
@@ -397,7 +397,7 @@
 	off64_t aligned_offset;
 	int aligned_diff;
 
-	if (off + len >= info.len) {
+	if (off + len >= (u64) info.len) {
 		error("attempted to write block %llu past end of filesystem",
 				off + len - info.len);
 		return;