allow fixing timestamps when building ext4 filesystem

When building an image, make_ext4fs currently sets the timestamps in
the image to the timestamps of the source files.  Allow this time to
be overridden with a fixed value provided on the command line, to make
it easier to reproduce bit-identical images from a target_files zip.

Change-Id: I52ddab4575a334ee52404f4d5d1c61b55513c618
diff --git a/ext4_utils/ext4_utils.h b/ext4_utils/ext4_utils.h
index 083aff5..1e13a90 100644
--- a/ext4_utils/ext4_utils.h
+++ b/ext4_utils/ext4_utils.h
@@ -172,14 +172,14 @@
 u16 ext4_crc16(u16 crc_in, const void *buf, int size);
 
 typedef void (*fs_config_func_t)(const char *path, int dir, unsigned *uid, unsigned *gid,
-        unsigned *mode, uint64_t *capabilities);
+		unsigned *mode, uint64_t *capabilities);
 
 struct selabel_handle;
 
 int make_ext4fs_internal(int fd, const char *directory,
-                         const char *mountpoint, fs_config_func_t fs_config_func, int gzip,
-                         int sparse, int crc, int wipe,
-                         struct selabel_handle *sehnd, int verbose);
+						 const char *mountpoint, fs_config_func_t fs_config_func, int gzip,
+						 int sparse, int crc, int wipe,
+						 struct selabel_handle *sehnd, int verbose, time_t fixed_time);
 
 #ifdef __cplusplus
 }
diff --git a/ext4_utils/make_ext4fs.c b/ext4_utils/make_ext4fs.c
index c2a2665..d672378 100644
--- a/ext4_utils/make_ext4fs.c
+++ b/ext4_utils/make_ext4fs.c
@@ -109,7 +109,7 @@
    if the image were mounted at the specified mount point */
 static u32 build_directory_structure(const char *full_path, const char *dir_path,
 		u32 dir_inode, fs_config_func_t fs_config_func,
-		struct selabel_handle *sehnd, int verbose)
+		struct selabel_handle *sehnd, int verbose, time_t fixed_time)
 {
 	int entries = 0;
 	struct dentry *dentries;
@@ -163,7 +163,11 @@
 
 		dentries[i].size = stat.st_size;
 		dentries[i].mode = stat.st_mode & (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO);
-		dentries[i].mtime = stat.st_mtime;
+		if (fixed_time == -1) {
+			dentries[i].mtime = stat.st_mtime;
+		} else {
+			dentries[i].mtime = fixed_time;
+		}
 		uint64_t capabilities;
 		if (fs_config_func != NULL) {
 #ifdef ANDROID
@@ -256,7 +260,7 @@
 			if (ret < 0)
 				critical_error_errno("asprintf");
 			entry_inode = build_directory_structure(subdir_full_path,
-					subdir_dir_path, inode, fs_config_func, sehnd, verbose);
+					subdir_dir_path, inode, fs_config_func, sehnd, verbose, fixed_time);
 			free(subdir_full_path);
 			free(subdir_dir_path);
 		} else if (dentries[i].file_type == EXT4_FT_SYMLINK) {
@@ -357,28 +361,28 @@
 }
 
 void reset_ext4fs_info() {
-    // Reset all the global data structures used by make_ext4fs so it
-    // can be called again.
-    memset(&info, 0, sizeof(info));
-    memset(&aux_info, 0, sizeof(aux_info));
+	// Reset all the global data structures used by make_ext4fs so it
+	// can be called again.
+	memset(&info, 0, sizeof(info));
+	memset(&aux_info, 0, sizeof(aux_info));
 
-    if (info.sparse_file) {
-        sparse_file_destroy(info.sparse_file);
-        info.sparse_file = NULL;
-    }
+	if (info.sparse_file) {
+		sparse_file_destroy(info.sparse_file);
+		info.sparse_file = NULL;
+	}
 }
 
 int make_ext4fs_sparse_fd(int fd, long long len,
-                const char *mountpoint, struct selabel_handle *sehnd)
+				const char *mountpoint, struct selabel_handle *sehnd)
 {
 	reset_ext4fs_info();
 	info.len = len;
 
-	return make_ext4fs_internal(fd, NULL, mountpoint, NULL, 0, 1, 0, 0, sehnd, 0);
+	return make_ext4fs_internal(fd, NULL, mountpoint, NULL, 0, 1, 0, 0, sehnd, 0, -1);
 }
 
 int make_ext4fs(const char *filename, long long len,
-                const char *mountpoint, struct selabel_handle *sehnd)
+				const char *mountpoint, struct selabel_handle *sehnd)
 {
 	int fd;
 	int status;
@@ -392,7 +396,7 @@
 		return EXIT_FAILURE;
 	}
 
-	status = make_ext4fs_internal(fd, NULL, mountpoint, NULL, 0, 0, 0, 1, sehnd, 0);
+	status = make_ext4fs_internal(fd, NULL, mountpoint, NULL, 0, 0, 0, 1, sehnd, 0, -1);
 	close(fd);
 
 	return status;
@@ -456,9 +460,9 @@
 }
 
 int make_ext4fs_internal(int fd, const char *_directory,
-                         const char *_mountpoint, fs_config_func_t fs_config_func, int gzip,
-                         int sparse, int crc, int wipe,
-                         struct selabel_handle *sehnd, int verbose)
+						 const char *_mountpoint, fs_config_func_t fs_config_func, int gzip,
+						 int sparse, int crc, int wipe,
+						 struct selabel_handle *sehnd, int verbose, time_t fixed_time)
 {
 	u32 root_inode_num;
 	u16 root_mode;
@@ -567,7 +571,7 @@
 #else
 	if (directory)
 		root_inode_num = build_directory_structure(directory, mountpoint, 0,
-                        fs_config_func, sehnd, verbose);
+				fs_config_func, sehnd, verbose, fixed_time);
 	else
 		root_inode_num = build_default_directory_structure();
 #endif
diff --git a/ext4_utils/make_ext4fs_main.c b/ext4_utils/make_ext4fs_main.c
index b6c740d..7e59417 100644
--- a/ext4_utils/make_ext4fs_main.c
+++ b/ext4_utils/make_ext4fs_main.c
@@ -52,7 +52,7 @@
 	fprintf(stderr, "%s [ -l <len> ] [ -j <journal size> ] [ -b <block_size> ]\n", basename(path));
 	fprintf(stderr, "    [ -g <blocks per group> ] [ -i <inodes> ] [ -I <inode size> ]\n");
 	fprintf(stderr, "    [ -L <label> ] [ -f ] [ -a <android mountpoint> ]\n");
-	fprintf(stderr, "    [ -S file_contexts ]\n");
+	fprintf(stderr, "    [ -S file_contexts ] [ -T timestamp ]\n");
 	fprintf(stderr, "    [ -z | -s ] [ -w ] [ -c ] [ -J ] [ -v ]\n");
 	fprintf(stderr, "    <filename> [<directory>]\n");
 }
@@ -71,12 +71,13 @@
 	int fd;
 	int exitcode;
 	int verbose = 0;
+	time_t fixed_time = -1;
 	struct selabel_handle *sehnd = NULL;
 #ifndef USE_MINGW
 	struct selinux_opt seopts[] = { { SELABEL_OPT_PATH, "" } };
 #endif
 
-	while ((opt = getopt(argc, argv, "l:j:b:g:i:I:L:a:S:fwzJsctv")) != -1) {
+	while ((opt = getopt(argc, argv, "l:j:b:g:i:I:L:a:S:T:fwzJsctv")) != -1) {
 		switch (opt) {
 		case 'l':
 			info.len = parse_num(optarg);
@@ -143,6 +144,9 @@
 		case 'v':
 			verbose = 1;
 			break;
+		case 'T':
+			fixed_time = strtoll(optarg, NULL, 0);
+			break;
 		default: /* '?' */
 			usage(argv[0]);
 			exit(EXIT_FAILURE);
@@ -201,7 +205,7 @@
 	}
 
 	exitcode = make_ext4fs_internal(fd, directory, mountpoint, fs_config_func, gzip,
-			sparse, crc, wipe, sehnd, verbose);
+			sparse, crc, wipe, sehnd, verbose, fixed_time);
 	close(fd);
 
 	return exitcode;
diff --git a/ext4_utils/mkuserimg.sh b/ext4_utils/mkuserimg.sh
index c44129e..6ef0294 100755
--- a/ext4_utils/mkuserimg.sh
+++ b/ext4_utils/mkuserimg.sh
@@ -1,11 +1,11 @@
-#!/bin/bash -x
+#!/bin/bash
 #
 # To call this script, make sure make_ext4fs is somewhere in PATH
 
 function usage() {
 cat<<EOT
 Usage:
-mkuserimg.sh [-s] SRC_DIR OUTPUT_FILE EXT_VARIANT MOUNT_POINT SIZE [FILE_CONTEXTS]
+mkuserimg.sh [-s] SRC_DIR OUTPUT_FILE EXT_VARIANT MOUNT_POINT SIZE [-T TIMESTAMP] [FILE_CONTEXTS]
 EOT
 }
 
@@ -17,7 +17,7 @@
   shift
 fi
 
-if [ $# -ne 5 -a $# -ne 6 ]; then
+if [ $# -lt 5 -o $# -gt 8 ]; then
   usage
   exit 1
 fi
@@ -32,7 +32,14 @@
 EXT_VARIANT=$3
 MOUNT_POINT=$4
 SIZE=$5
-FC=$6
+shift; shift; shift; shift; shift
+
+TIMESTAMP=-1
+if [[ "$1" == "-T" ]]; then
+  TIMESTAMP=$2
+  shift; shift
+fi
+FC=$1
 
 case $EXT_VARIANT in
   ext4) ;;
@@ -53,7 +60,7 @@
     FCOPT="-S $FC"
 fi
 
-MAKE_EXT4FS_CMD="make_ext4fs $ENABLE_SPARSE_IMAGE $FCOPT -l $SIZE -a $MOUNT_POINT $OUTPUT_FILE $SRC_DIR"
+MAKE_EXT4FS_CMD="make_ext4fs $ENABLE_SPARSE_IMAGE -T $TIMESTAMP $FCOPT -l $SIZE -a $MOUNT_POINT $OUTPUT_FILE $SRC_DIR"
 echo $MAKE_EXT4FS_CMD
 $MAKE_EXT4FS_CMD
 if [ $? -ne 0 ]; then