Snap for 8414339 from b26dbef946efb872f0a2b904ec59a83745c9df19 to tm-qpr1-release

Change-Id: Ibdb835e27053c0069c7bf89e16a1f2de471f665f
diff --git a/Android.bp b/Android.bp
index 1c56d0c..a622074 100644
--- a/Android.bp
+++ b/Android.bp
@@ -183,18 +183,3 @@
         },
     },
 }
-
-sh_binary_host {
-    name: "mkerofsimage.sh",
-    src: "mkerofsimage.sh",
-    required: [
-        "img2simg",
-        "mkfs.erofs",
-    ],
-
-    target: {
-        darwin: {
-            enabled: false,
-        },
-    },
-}
diff --git a/dump/main.c b/dump/main.c
index bb1bd7f..72761bd 100644
--- a/dump/main.c
+++ b/dump/main.c
@@ -84,6 +84,7 @@
 
 static struct erofsdump_feature feature_lists[] = {
 	{ true, EROFS_FEATURE_COMPAT_SB_CHKSUM, "sb_csum" },
+	{ true, EROFS_FEATURE_COMPAT_MTIME, "mtime" },
 	{ false, EROFS_FEATURE_INCOMPAT_LZ4_0PADDING, "0padding" },
 	{ false, EROFS_FEATURE_INCOMPAT_BIG_PCLUSTER, "big_pcluster" },
 	{ false, EROFS_FEATURE_INCOMPAT_CHUNKED_FILE, "chunked_file" },
@@ -488,7 +489,7 @@
 	}
 
 	strftime(timebuf, sizeof(timebuf),
-		 "%Y-%m-%d %H:%M:%S", localtime((time_t *)&inode.i_ctime));
+		 "%Y-%m-%d %H:%M:%S", localtime((time_t *)&inode.i_mtime));
 	access_mode = inode.i_mode & 0777;
 	for (i = 8; i >= 0; i--)
 		if (((access_mode >> i) & 1) == 0)
@@ -507,7 +508,7 @@
 	fprintf(stdout,	"Xattr size: %u\n", inode.xattr_isize);
 	fprintf(stdout, "Uid: %u   Gid: %u  ", inode.i_uid, inode.i_gid);
 	fprintf(stdout, "Access: %04o/%s\n", access_mode, access_mode_str);
-	fprintf(stdout, "Timestamp: %s.%09d\n", timebuf, inode.i_ctime_nsec);
+	fprintf(stdout, "Timestamp: %s.%09d\n", timebuf, inode.i_mtime_nsec);
 
 	if (!dumpcfg.show_extent)
 		return;
diff --git a/fsck/main.c b/fsck/main.c
index e669b44..0af15b4 100644
--- a/fsck/main.c
+++ b/fsck/main.c
@@ -229,14 +229,14 @@
 
 #ifdef HAVE_UTIMENSAT
 	if (utimensat(AT_FDCWD, path, (struct timespec []) {
-				[0] = { .tv_sec = inode->i_ctime,
-					.tv_nsec = inode->i_ctime_nsec },
-				[1] = { .tv_sec = inode->i_ctime,
-					.tv_nsec = inode->i_ctime_nsec },
+				[0] = { .tv_sec = inode->i_mtime,
+					.tv_nsec = inode->i_mtime_nsec },
+				[1] = { .tv_sec = inode->i_mtime,
+					.tv_nsec = inode->i_mtime_nsec },
 			}, AT_SYMLINK_NOFOLLOW) < 0)
 #else
-	if (utime(path, &((struct utimbuf){.actime = inode->i_ctime,
-					   .modtime = inode->i_ctime})) < 0)
+	if (utime(path, &((struct utimbuf){.actime = inode->i_mtime,
+					   .modtime = inode->i_mtime})) < 0)
 #endif
 		erofs_warn("failed to set times: %s", path);
 
diff --git a/fuse/main.c b/fuse/main.c
index 2549d8a..ae377ae 100644
--- a/fuse/main.c
+++ b/fuse/main.c
@@ -98,7 +98,7 @@
 	stbuf->st_gid = vi.i_gid;
 	if (S_ISBLK(vi.i_mode) || S_ISCHR(vi.i_mode))
 		stbuf->st_rdev = vi.u.i_rdev;
-	stbuf->st_ctime = vi.i_ctime;
+	stbuf->st_ctime = vi.i_mtime;
 	stbuf->st_mtime = stbuf->st_ctime;
 	stbuf->st_atime = stbuf->st_ctime;
 	return 0;
diff --git a/include/erofs/config.h b/include/erofs/config.h
index cb064b6..0a1b18b 100644
--- a/include/erofs/config.h
+++ b/include/erofs/config.h
@@ -43,6 +43,7 @@
 	char c_timeinherit;
 	char c_chunkbits;
 	bool c_noinline_data;
+	bool c_ignore_mtime;
 
 #ifdef HAVE_LIBSELINUX
 	struct selabel_handle *sehnd;
diff --git a/include/erofs/internal.h b/include/erofs/internal.h
index 947304f..56627e9 100644
--- a/include/erofs/internal.h
+++ b/include/erofs/internal.h
@@ -154,8 +154,8 @@
 	u64 i_ino[2];
 	u32 i_uid;
 	u32 i_gid;
-	u64 i_ctime;
-	u32 i_ctime_nsec;
+	u64 i_mtime;
+	u32 i_mtime_nsec;
 	u32 i_nlink;
 
 	union {
diff --git a/include/erofs_fs.h b/include/erofs_fs.h
index 9a91877..7956a62 100644
--- a/include/erofs_fs.h
+++ b/include/erofs_fs.h
@@ -13,6 +13,7 @@
 #define EROFS_SUPER_OFFSET      1024
 
 #define EROFS_FEATURE_COMPAT_SB_CHKSUM		0x00000001
+#define EROFS_FEATURE_COMPAT_MTIME		0x00000002
 
 /*
  * Any bits that aren't in EROFS_ALL_FEATURE_INCOMPAT should
@@ -183,8 +184,8 @@
 
 	__le32 i_uid;
 	__le32 i_gid;
-	__le64 i_ctime;
-	__le32 i_ctime_nsec;
+	__le64 i_mtime;
+	__le32 i_mtime_nsec;
 	__le32 i_nlink;
 	__u8   i_reserved2[16];
 };
diff --git a/lib/config.c b/lib/config.c
index f1c8edf..cc15e57 100644
--- a/lib/config.c
+++ b/lib/config.c
@@ -20,6 +20,7 @@
 	cfg.c_dbg_lvl  = EROFS_WARN;
 	cfg.c_version  = PACKAGE_VERSION;
 	cfg.c_dry_run  = false;
+	cfg.c_ignore_mtime = false;
 	cfg.c_compr_level_master = -1;
 	cfg.c_force_inodeversion = 0;
 	cfg.c_inline_xattr_tolerance = 2;
diff --git a/lib/inode.c b/lib/inode.c
index 461c797..77ea8bf 100644
--- a/lib/inode.c
+++ b/lib/inode.c
@@ -477,8 +477,8 @@
 		u.die.i_uid = cpu_to_le32(inode->i_uid);
 		u.die.i_gid = cpu_to_le32(inode->i_gid);
 
-		u.die.i_ctime = cpu_to_le64(inode->i_ctime);
-		u.die.i_ctime_nsec = cpu_to_le32(inode->i_ctime_nsec);
+		u.die.i_mtime = cpu_to_le64(inode->i_mtime);
+		u.die.i_mtime_nsec = cpu_to_le32(inode->i_mtime_nsec);
 
 		switch (inode->i_mode & S_IFMT) {
 		case S_IFCHR:
@@ -730,6 +730,10 @@
 		return true;
 	if (inode->i_nlink > USHRT_MAX)
 		return true;
+	if ((inode->i_mtime != sbi.build_time ||
+	     inode->i_mtime_nsec != sbi.build_time_nsec) &&
+	    !cfg.c_ignore_mtime)
+		return true;
 	return false;
 }
 
@@ -806,16 +810,16 @@
 	inode->i_mode = st->st_mode;
 	inode->i_uid = cfg.c_uid == -1 ? st->st_uid : cfg.c_uid;
 	inode->i_gid = cfg.c_gid == -1 ? st->st_gid : cfg.c_gid;
-	inode->i_ctime = st->st_ctime;
-	inode->i_ctime_nsec = ST_CTIM_NSEC(st);
+	inode->i_mtime = st->st_mtime;
+	inode->i_mtime_nsec = ST_MTIM_NSEC(st);
 
 	switch (cfg.c_timeinherit) {
 	case TIMESTAMP_CLAMPING:
-		if (st->st_ctime < sbi.build_time)
+		if (inode->i_mtime < sbi.build_time)
 			break;
 	case TIMESTAMP_FIXED:
-		inode->i_ctime = sbi.build_time;
-		inode->i_ctime_nsec = sbi.build_time_nsec;
+		inode->i_mtime = sbi.build_time;
+		inode->i_mtime_nsec = sbi.build_time_nsec;
 	default:
 		break;
 	}
diff --git a/lib/namei.c b/lib/namei.c
index 7377e74..2c8891a 100644
--- a/lib/namei.c
+++ b/lib/namei.c
@@ -79,8 +79,8 @@
 		vi->i_gid = le32_to_cpu(die->i_gid);
 		vi->i_nlink = le32_to_cpu(die->i_nlink);
 
-		vi->i_ctime = le64_to_cpu(die->i_ctime);
-		vi->i_ctime_nsec = le64_to_cpu(die->i_ctime_nsec);
+		vi->i_mtime = le64_to_cpu(die->i_mtime);
+		vi->i_mtime_nsec = le64_to_cpu(die->i_mtime_nsec);
 		vi->i_size = le64_to_cpu(die->i_size);
 		if (vi->datalayout == EROFS_INODE_CHUNK_BASED)
 			/* fill chunked inode summary info */
@@ -114,8 +114,8 @@
 		vi->i_gid = le16_to_cpu(dic->i_gid);
 		vi->i_nlink = le16_to_cpu(dic->i_nlink);
 
-		vi->i_ctime = sbi.build_time;
-		vi->i_ctime_nsec = sbi.build_time_nsec;
+		vi->i_mtime = sbi.build_time;
+		vi->i_mtime_nsec = sbi.build_time_nsec;
 
 		vi->i_size = le32_to_cpu(dic->i_size);
 		if (vi->datalayout == EROFS_INODE_CHUNK_BASED)
diff --git a/man/mkfs.erofs.1 b/man/mkfs.erofs.1
index 9c7788e..d61e33e 100644
--- a/man/mkfs.erofs.1
+++ b/man/mkfs.erofs.1
@@ -112,6 +112,11 @@
 .B \-\-help
 Display this help and exit.
 .TP
+.B "\-\-ignore-mtime"
+File modification time is ignored whenever it would cause \fBmkfs.erofs\fR to
+use extended inodes over compact inodes. When not using a fixed timestamp, this
+can reduce total metadata size.
+.TP
 .BI "\-\-max-extent-bytes " #
 Specify maximum decompressed extent size # in bytes.
 .SH AUTHOR
diff --git a/mkerofsimage.sh b/mkerofsimage.sh
deleted file mode 100755
index c449352..0000000
--- a/mkerofsimage.sh
+++ /dev/null
@@ -1,146 +0,0 @@
-#!/bin/bash
-#
-# To call this script, make sure mkfs.erofs is somewhere in PATH
-
-function usage() {
-cat<<EOT
-Usage:
-${0##*/} SRC_DIR OUTPUT_FILE [-s] [-m MOUNT_POINT] [-d PRODUCT_OUT] [-C FS_CONFIG ] [-c FILE_CONTEXTS] [-z COMPRESSOR] [-T TIMESTAMP] [-U UUID] [-B BLOCK_MAP] [-P PCLUSTER_SIZE] [-k CHUNK_SIZE]
-EOT
-}
-
-echo "in mkerofsimage.sh PATH=$PATH"
-
-if [ $# -lt 2 ]; then
-    usage
-    exit 1
-fi
-
-SRC_DIR=$1
-if [ ! -d $SRC_DIR ]; then
-  echo "Can not find directory $SRC_DIR!"
-  exit 2
-fi
-OUTPUT_FILE=$2
-shift; shift
-
-SPARSE=false
-if [[ "$1" == "-s" ]]; then
-    SPARSE=true
-    shift;
-fi
-
-MOUNT_POINT=
-if [[ "$1" == "-m" ]]; then
-    MOUNT_POINT=$2
-    shift; shift
-fi
-
-PRODUCT_OUT=
-if [[ "$1" == "-d" ]]; then
-    PRODUCT_OUT=$2
-    shift; shift
-fi
-
-FS_CONFIG=
-if [[ "$1" == "-C" ]]; then
-    FS_CONFIG=$2
-    shift; shift
-fi
-
-FILE_CONTEXTS=
-if [[ "$1" == "-c" ]]; then
-    FILE_CONTEXTS=$2
-    shift; shift
-fi
-
-COMPRESSOR="lz4hc"
-if [[ "$1" == "-z" ]]; then
-    COMPRESSOR=$2
-    shift; shift
-fi
-
-if [[ "$COMPRESSOR" == "none" ]]; then
-    COMPRESS_ARGS=
-else
-    COMPRESS_ARGS="-z ${COMPRESSOR}"
-fi
-
-TIMESTAMP=
-if [[ "$1" == "-T" ]]; then
-    TIMESTAMP=$2
-    shift; shift
-fi
-
-UUID=
-if [[ "$1" == "-U" ]]; then
-    UUID=$2
-    shift; shift
-fi
-
-BLOCK_MAP=
-if [[ "$1" == "-B" ]]; then
-    BLOCK_MAP=$2
-    shift; shift;
-fi
-
-PCLUSTER_SIZE=
-if [[ "$1" == "-P" ]]; then
-    PCLUSTER_SIZE=$2
-    shift; shift;
-fi
-
-CHUNK_SIZE=
-if [[ "$1" == "-k" ]]; then
-    CHUNK_SIZE=$2
-    shift; shift;
-fi
-
-OPT=""
-if [ -n "$MOUNT_POINT" ]; then
-  OPT="$OPT --mount-point $MOUNT_POINT"
-fi
-if [ -n "$PRODUCT_OUT" ]; then
-  OPT="$OPT --product-out $PRODUCT_OUT"
-fi
-if [ -n "$FS_CONFIG" ]; then
-  OPT="$OPT --fs-config-file $FS_CONFIG"
-fi
-if [ -n "$FILE_CONTEXTS" ]; then
-  OPT="$OPT --file-contexts $FILE_CONTEXTS"
-fi
-if [ -n "$TIMESTAMP" ]; then
-  OPT="$OPT -T $TIMESTAMP"
-fi
-if [ -n "$UUID" ]; then
-  OPT="$OPT -U $UUID"
-fi
-if [ -n "$BLOCK_MAP" ]; then
-  OPT="$OPT --block-list-file=$BLOCK_MAP"
-fi
-if [ -n "$PCLUSTER_SIZE" ]; then
-  OPT="$OPT -C${PCLUSTER_SIZE}"
-fi
-if [ -n "$CHUNK_SIZE" ]; then
-  OPT="$OPT --chunksize=$CHUNK_SIZE"
-fi
-
-MAKE_EROFS_CMD="mkfs.erofs $COMPRESS_ARGS $OPT $OUTPUT_FILE $SRC_DIR"
-echo $MAKE_EROFS_CMD
-$MAKE_EROFS_CMD
-
-if [ $? -ne 0 ]; then
-    exit 4
-fi
-
-fsck.erofs --extract $OUTPUT_FILE
-
-SPARSE_SUFFIX=".sparse"
-if [ "$SPARSE" = true ]; then
-    img2simg $OUTPUT_FILE $OUTPUT_FILE$SPARSE_SUFFIX
-    if [ $? -ne 0 ]; then
-        exit 4
-    fi
-    mv $OUTPUT_FILE$SPARSE_SUFFIX $OUTPUT_FILE
-fi
-
diff --git a/mkfs/main.c b/mkfs/main.c
index 3f34450..b62a8aa 100644
--- a/mkfs/main.c
+++ b/mkfs/main.c
@@ -49,6 +49,7 @@
 	{"chunksize", required_argument, NULL, 11},
 	{"quiet", no_argument, 0, 12},
 	{"blobdev", required_argument, NULL, 13},
+	{"ignore-mtime", no_argument, NULL, 14},
 #ifdef WITH_ANDROID
 	{"mount-point", required_argument, NULL, 512},
 	{"product-out", required_argument, NULL, 513},
@@ -96,6 +97,7 @@
 	      " --force-uid=#         set all file uids to # (# = UID)\n"
 	      " --force-gid=#         set all file gids to # (# = GID)\n"
 	      " --help                display this help and exit\n"
+	      " --ignore-mtime        use build time instead of strict per-file modification time\n"
 	      " --max-extent-bytes=#  set maximum decompressed extent size # in bytes\n"
 	      " --quiet               quiet execution (do not write anything to standard output.)\n"
 #ifndef NDEBUG
@@ -366,6 +368,9 @@
 		case 13:
 			cfg.c_blobdev_path = optarg;
 			break;
+		case 14:
+			cfg.c_ignore_mtime = true;
+			break;
 		case 1:
 			usage();
 			exit(0);
@@ -511,7 +516,8 @@
 {
 	cfg.c_legacy_compress = false;
 	sbi.feature_incompat = EROFS_FEATURE_INCOMPAT_LZ4_0PADDING;
-	sbi.feature_compat = EROFS_FEATURE_COMPAT_SB_CHKSUM;
+	sbi.feature_compat = EROFS_FEATURE_COMPAT_SB_CHKSUM |
+			     EROFS_FEATURE_COMPAT_MTIME;
 
 	/* generate a default uuid first */
 #ifdef HAVE_LIBUUID