ext4_utils: Add support for wipe option, and wipe by default in recovery

Adds a -w option to make_ext4fs, which will attempt to use the
BLKSECDISCARD ioctl to erase the partition in order to avoid
leaving old data where it could be recovered, and to improve
wear levelling after a reformat.

Also causes factory reset through recovery to do a wipe.

Change-Id: Ibe34bbd84552e526be6bd041024a950806aca6b4
diff --git a/ext4_utils/Android.mk b/ext4_utils/Android.mk
index 59b7bdf..57d0996 100644
--- a/ext4_utils/Android.mk
+++ b/ext4_utils/Android.mk
@@ -14,7 +14,8 @@
         indirect.c \
         uuid.c \
         sha1.c \
-	sparse_crc32.c
+	sparse_crc32.c \
+	wipe.c
 
 LOCAL_SRC_FILES := $(libext4_utils_src_files)
 LOCAL_MODULE := libext4_utils
diff --git a/ext4_utils/ext2simg.c b/ext4_utils/ext2simg.c
index a18a06e..9332bad 100644
--- a/ext4_utils/ext2simg.c
+++ b/ext4_utils/ext2simg.c
@@ -222,7 +222,7 @@
 
 	close(fd);
 
-	write_ext4_image(out, gzip, sparse, crc);
+	write_ext4_image(out, gzip, sparse, crc, 0);
 
 	return 0;
 }
diff --git a/ext4_utils/ext4_utils.c b/ext4_utils/ext4_utils.c
index bdf2a74..211448c 100644
--- a/ext4_utils/ext4_utils.c
+++ b/ext4_utils/ext4_utils.c
@@ -120,11 +120,12 @@
 }
 
 /* Write the filesystem image to a file */
-void write_ext4_image(const char *filename, int gz, int sparse, int crc)
+void write_ext4_image(const char *filename, int gz, int sparse, int crc,
+		int wipe)
 {
 	int ret = 0;
 	struct output_file *out = open_output_file(filename, gz, sparse,
-	        count_sparse_chunks(), crc);
+	        count_sparse_chunks(), crc, wipe);
 
 	if (!out)
 		return;
diff --git a/ext4_utils/ext4_utils.h b/ext4_utils/ext4_utils.h
index b770294..bed9933 100644
--- a/ext4_utils/ext4_utils.h
+++ b/ext4_utils/ext4_utils.h
@@ -141,7 +141,8 @@
 }
 
 int ext4_bg_has_super_block(int bg);
-void write_ext4_image(const char *filename, int gz, int sparse, int crc);
+void write_ext4_image(const char *filename, int gz, int sparse, int crc,
+		int wipe);
 void ext4_create_fs_aux_info(void);
 void ext4_free_fs_aux_info(void);
 void ext4_fill_in_sb(void);
diff --git a/ext4_utils/make_ext4fs.c b/ext4_utils/make_ext4fs.c
index 5742261..a87529d 100644
--- a/ext4_utils/make_ext4fs.c
+++ b/ext4_utils/make_ext4fs.c
@@ -246,12 +246,12 @@
 {
     reset_ext4fs_info();
     info.len = len;
-    return make_ext4fs_internal(filename, NULL, NULL, 0, 0, 0, 0);
+    return make_ext4fs_internal(filename, NULL, NULL, 0, 0, 0, 0, 1);
 }
 
 int make_ext4fs_internal(const char *filename, const char *directory,
                          char *mountpoint, int android, int gzip, int sparse,
-                         int crc)
+                         int crc, int wipe)
 {
         u32 root_inode_num;
         u16 root_mode;
@@ -349,7 +349,7 @@
 			aux_info.sb->s_blocks_count_lo - aux_info.sb->s_free_blocks_count_lo,
 			aux_info.sb->s_blocks_count_lo);
 
-	write_ext4_image(filename, gzip, sparse, crc);
+	write_ext4_image(filename, gzip, sparse, crc, wipe);
 
 	return 0;
 }
diff --git a/ext4_utils/make_ext4fs.h b/ext4_utils/make_ext4fs.h
index 1e82fa6..3a26c3f 100644
--- a/ext4_utils/make_ext4fs.h
+++ b/ext4_utils/make_ext4fs.h
@@ -24,6 +24,6 @@
 int make_ext4fs(const char *filename, s64 len);
 int make_ext4fs_internal(const char *filename, const char *directory,
                          char *mountpoint, int android, int gzip, int sparse,
-                         int crc);
+                         int crc, int wipe);
 
 #endif
diff --git a/ext4_utils/make_ext4fs_main.c b/ext4_utils/make_ext4fs_main.c
index bd7442e..8742e61 100644
--- a/ext4_utils/make_ext4fs_main.c
+++ b/ext4_utils/make_ext4fs_main.c
@@ -47,8 +47,9 @@
         int gzip = 0;
         int sparse = 0;
         int crc = 0;
+        int wipe = 0;
 
-        while ((opt = getopt(argc, argv, "l:j:b:g:i:I:L:a:fzJsc")) != -1) {
+        while ((opt = getopt(argc, argv, "l:j:b:g:i:I:L:a:fwzJsc")) != -1) {
                 switch (opt) {
                 case 'l':
                         info.len = parse_num(optarg);
@@ -78,6 +79,9 @@
                         android = 1;
                         mountpoint = optarg;
                         break;
+                case 'w':
+                        wipe = 1;
+                        break;
                 case 'z':
                         gzip = 1;
                         break;
@@ -102,6 +106,18 @@
                 exit(EXIT_FAILURE);
 	}
 
+        if (wipe && sparse) {
+                fprintf(stderr, "Cannot specifiy both wipe and sparse\n");
+                usage(argv[0]);
+                exit(EXIT_FAILURE);
+        }
+
+        if (wipe && gzip) {
+                fprintf(stderr, "Cannot specifiy both wipe and gzip\n");
+                usage(argv[0]);
+                exit(EXIT_FAILURE);
+        }
+
         if (optind >= argc) {
                 fprintf(stderr, "Expected filename after options\n");
                 usage(argv[0]);
@@ -120,5 +136,5 @@
         }
 
         return make_ext4fs_internal(filename, directory, mountpoint, android, gzip,
-        		sparse, crc);
+        		sparse, crc, wipe);
 }
diff --git a/ext4_utils/output_file.c b/ext4_utils/output_file.c
index c1997b6..abe8414 100644
--- a/ext4_utils/output_file.c
+++ b/ext4_utils/output_file.c
@@ -18,6 +18,7 @@
 #include "output_file.h"
 #include "sparse_format.h"
 #include "sparse_crc32.h"
+#include "wipe.h"
 
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -270,7 +271,7 @@
 }
 
 struct output_file *open_output_file(const char *filename, int gz, int sparse,
-        int chunks, int crc)
+        int chunks, int crc, int wipe)
 {
 	int ret;
 	struct output_file *out = malloc(sizeof(struct output_file));
@@ -314,6 +315,9 @@
 	out->crc32 = 0;
 	out->use_crc = crc;
 
+	if (wipe)
+		wipe_block_device(out->fd, info.len);
+
 	if (out->sparse) {
 		sparse_header.blk_sz = info.block_size,
 		sparse_header.total_blks = info.len / info.block_size,
diff --git a/ext4_utils/output_file.h b/ext4_utils/output_file.h
index c174cc3..7866c6a 100644
--- a/ext4_utils/output_file.h
+++ b/ext4_utils/output_file.h
@@ -20,7 +20,7 @@
 struct output_file;
 
 struct output_file *open_output_file(const char *filename, int gz, int sparse,
-        int chunks, int crc);
+        int chunks, int crc, int wipe);
 void write_data_block(struct output_file *out, u64 off, u8 *data, int len);
 void write_data_file(struct output_file *out, u64 off, const char *file,
 		     off64_t offset, int len);
diff --git a/ext4_utils/wipe.c b/ext4_utils/wipe.c
new file mode 100644
index 0000000..c7ba6db
--- /dev/null
+++ b/ext4_utils/wipe.c
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ext4_utils.h"
+#include "wipe.h"
+
+#if defined(__linux__)
+
+#include <linux/fs.h>
+#include <sys/ioctl.h>
+
+#ifndef BLKDISCARD
+#define BLKDISCARD _IO(0x12,119)
+#endif
+
+#ifndef BLKSECDISCARD
+#define BLKSECDISCARD _IO(0x12,125)
+#endif
+
+int wipe_block_device(int fd, int len)
+{
+	u64 range[2];
+	int ret;
+
+	range[0] = 0;
+	range[1] = len;
+	ret = ioctl(fd, BLKSECDISCARD, &range);
+	if (ret < 0) {
+		range[0] = 0;
+		range[1] = len;
+		ret = ioctl(fd, BLKDISCARD, &range);
+		if (ret < 0) {
+			error("Discard failed\n");
+			return 1;
+		} else {
+			warn("Wipe via secure discard failed, used discard instead\n");
+			return 0;
+		}
+	}
+
+	return 0;
+}
+#else
+int wipe_block_device(int fd)
+{
+	error("wipe not supported on non-linux platforms");
+	return 1;
+}
+#endif
+
diff --git a/ext4_utils/wipe.h b/ext4_utils/wipe.h
new file mode 100644
index 0000000..0b54b46
--- /dev/null
+++ b/ext4_utils/wipe.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _WIPE_H_
+#define _WIPE_H_
+
+int wipe_block_device(int fd, int len);
+
+#endif