Snap for 4674419 from 64e620a09ef0fadff9b65b93494b26835d37563a to qt-release

Change-Id: I69f935a07dfe10d0cae6f635f05dfa5442c0fbed
diff --git a/tests/component/applypatch_test.cpp b/tests/component/applypatch_test.cpp
index 61e06ad..9160285 100644
--- a/tests/component/applypatch_test.cpp
+++ b/tests/component/applypatch_test.cpp
@@ -205,67 +205,96 @@
   sha1sum(boot_img, &boot_img_sha1, &boot_img_size);
 
   std::string recovery_img = from_testdata_base("recovery.img");
-  size_t size;
+  size_t recovery_img_size;
   std::string recovery_img_sha1;
-  sha1sum(recovery_img, &recovery_img_sha1, &size);
-  std::string recovery_img_size = std::to_string(size);
+  sha1sum(recovery_img, &recovery_img_sha1, &recovery_img_size);
+  std::string recovery_img_size_arg = std::to_string(recovery_img_size);
 
   std::string bonus_file = from_testdata_base("bonus.file");
 
   // applypatch -b <bonus-file> <src-file> <tgt-file> <tgt-sha1> <tgt-size> <src-sha1>:<patch>
-  TemporaryFile tmp1;
-  std::string src_file =
+  std::string src_file_arg =
       "EMMC:" + boot_img + ":" + std::to_string(boot_img_size) + ":" + boot_img_sha1;
-  std::string tgt_file = "EMMC:" + std::string(tmp1.path);
-  std::string patch = boot_img_sha1 + ":" + from_testdata_base("recovery-from-boot.p");
-  std::vector<const char*> args = {
-    "applypatch",
-    "-b",
-    bonus_file.c_str(),
-    src_file.c_str(),
-    tgt_file.c_str(),
-    recovery_img_sha1.c_str(),
-    recovery_img_size.c_str(),
-    patch.c_str()
-  };
+  TemporaryFile tgt_file;
+  std::string tgt_file_arg = "EMMC:"s + tgt_file.path;
+  std::string patch_arg = boot_img_sha1 + ":" + from_testdata_base("recovery-from-boot.p");
+  std::vector<const char*> args = { "applypatch",
+                                    "-b",
+                                    bonus_file.c_str(),
+                                    src_file_arg.c_str(),
+                                    tgt_file_arg.c_str(),
+                                    recovery_img_sha1.c_str(),
+                                    recovery_img_size_arg.c_str(),
+                                    patch_arg.c_str() };
   ASSERT_EQ(0, applypatch_modes(args.size(), args.data()));
+}
+
+// Tests patching the EMMC target without a separate bonus file (i.e. recovery-from-boot patch has
+// everything).
+TEST_F(ApplyPatchModesTest, PatchModeEmmcTargetWithoutBonusFile) {
+  std::string boot_img = from_testdata_base("boot.img");
+  size_t boot_img_size;
+  std::string boot_img_sha1;
+  sha1sum(boot_img, &boot_img_sha1, &boot_img_size);
+
+  std::string recovery_img = from_testdata_base("recovery.img");
+  size_t recovery_img_size;
+  std::string recovery_img_sha1;
+  sha1sum(recovery_img, &recovery_img_sha1, &recovery_img_size);
+  std::string recovery_img_size_arg = std::to_string(recovery_img_size);
 
   // applypatch <src-file> <tgt-file> <tgt-sha1> <tgt-size> <src-sha1>:<patch>
-  TemporaryFile tmp2;
-  patch = boot_img_sha1 + ":" + from_testdata_base("recovery-from-boot-with-bonus.p");
-  tgt_file = "EMMC:" + std::string(tmp2.path);
-  std::vector<const char*> args2 = {
-    "applypatch",
-    src_file.c_str(),
-    tgt_file.c_str(),
-    recovery_img_sha1.c_str(),
-    recovery_img_size.c_str(),
-    patch.c_str()
-  };
-  ASSERT_EQ(0, applypatch_modes(args2.size(), args2.data()));
+  std::string src_file_arg =
+      "EMMC:" + boot_img + ":" + std::to_string(boot_img_size) + ":" + boot_img_sha1;
+  TemporaryFile tgt_file;
+  std::string tgt_file_arg = "EMMC:"s + tgt_file.path;
+  std::string patch_arg =
+      boot_img_sha1 + ":" + from_testdata_base("recovery-from-boot-with-bonus.p");
+  std::vector<const char*> args = { "applypatch",
+                                    src_file_arg.c_str(),
+                                    tgt_file_arg.c_str(),
+                                    recovery_img_sha1.c_str(),
+                                    recovery_img_size_arg.c_str(),
+                                    patch_arg.c_str() };
+  ASSERT_EQ(0, applypatch_modes(args.size(), args.data()));
+}
+
+TEST_F(ApplyPatchModesTest, PatchModeEmmcTargetWithMultiplePatches) {
+  std::string boot_img = from_testdata_base("boot.img");
+  size_t boot_img_size;
+  std::string boot_img_sha1;
+  sha1sum(boot_img, &boot_img_sha1, &boot_img_size);
+
+  std::string recovery_img = from_testdata_base("recovery.img");
+  size_t recovery_img_size;
+  std::string recovery_img_sha1;
+  sha1sum(recovery_img, &recovery_img_sha1, &recovery_img_size);
+  std::string recovery_img_size_arg = std::to_string(recovery_img_size);
+
+  std::string bonus_file = from_testdata_base("bonus.file");
 
   // applypatch -b <bonus-file> <src-file> <tgt-file> <tgt-sha1> <tgt-size> \
-  //               <src-sha1-fake>:<patch1> <src-sha1>:<patch2>
-  TemporaryFile tmp3;
-  tgt_file = "EMMC:" + std::string(tmp3.path);
+  //            <src-sha1-fake1>:<patch1> <src-sha1>:<patch2> <src-sha1-fake2>:<patch3>
+  std::string src_file_arg =
+      "EMMC:" + boot_img + ":" + std::to_string(boot_img_size) + ":" + boot_img_sha1;
+  TemporaryFile tgt_file;
+  std::string tgt_file_arg = "EMMC:"s + tgt_file.path;
   std::string bad_sha1_a = android::base::StringPrintf("%040x", rand());
   std::string bad_sha1_b = android::base::StringPrintf("%040x", rand());
   std::string patch1 = bad_sha1_a + ":" + from_testdata_base("recovery-from-boot.p");
   std::string patch2 = boot_img_sha1 + ":" + from_testdata_base("recovery-from-boot.p");
   std::string patch3 = bad_sha1_b + ":" + from_testdata_base("recovery-from-boot.p");
-  std::vector<const char*> args3 = {
-    "applypatch",
-    "-b",
-    bonus_file.c_str(),
-    src_file.c_str(),
-    tgt_file.c_str(),
-    recovery_img_sha1.c_str(),
-    recovery_img_size.c_str(),
-    patch1.c_str(),
-    patch2.c_str(),
-    patch3.c_str()
-  };
-  ASSERT_EQ(0, applypatch_modes(args3.size(), args3.data()));
+  std::vector<const char*> args = { "applypatch",
+                                    "-b",
+                                    bonus_file.c_str(),
+                                    src_file_arg.c_str(),
+                                    tgt_file_arg.c_str(),
+                                    recovery_img_sha1.c_str(),
+                                    recovery_img_size_arg.c_str(),
+                                    patch1.c_str(),
+                                    patch2.c_str(),
+                                    patch3.c_str() };
+  ASSERT_EQ(0, applypatch_modes(args.size(), args.data()));
 }
 
 // Ensures that applypatch works with a bsdiff based recovery-from-boot.p.
diff --git a/uncrypt/uncrypt.cpp b/uncrypt/uncrypt.cpp
index 645faad..16036f9 100644
--- a/uncrypt/uncrypt.cpp
+++ b/uncrypt/uncrypt.cpp
@@ -172,10 +172,15 @@
     return fstab;
 }
 
-static const char* find_block_device(const char* path, bool* encryptable, bool* encrypted) {
+static const char* find_block_device(const char* path, bool* encryptable,
+                                     bool* encrypted, bool* f2fs_fs) {
     // Look for a volume whose mount point is the prefix of path and
     // return its block device.  Set encrypted if it's currently
     // encrypted.
+
+    // ensure f2fs_fs is set to false first.
+    *f2fs_fs = false;
+
     for (int i = 0; i < fstab->num_entries; ++i) {
         struct fstab_rec* v = &fstab->recs[i];
         if (!v->mount_point) {
@@ -192,6 +197,9 @@
                     *encrypted = true;
                 }
             }
+            if (strcmp(v->fs_type, "f2fs") == 0) {
+                *f2fs_fs = true;
+            }
             return v->blk_device;
         }
     }
@@ -244,7 +252,7 @@
 }
 
 static int produce_block_map(const char* path, const char* map_file, const char* blk_dev,
-                             bool encrypted, int socket) {
+                             bool encrypted, bool f2fs_fs, int socket) {
     std::string err;
     if (!android::base::RemoveFileIfExists(map_file, &err)) {
         LOG(ERROR) << "failed to remove the existing map file " << map_file << ": " << err;
@@ -307,6 +315,31 @@
         }
     }
 
+// F2FS-specific ioctl
+// It requires the below kernel commit merged in v4.16-rc1.
+//   1ad71a27124c ("f2fs: add an ioctl to disable GC for specific file")
+// In android-4.4,
+//   56ee1e817908 ("f2fs: updates on v4.16-rc1")
+// In android-4.9,
+//   2f17e34672a8 ("f2fs: updates on v4.16-rc1")
+// In android-4.14,
+//   ce767d9a55bc ("f2fs: updates on v4.16-rc1")
+#ifndef F2FS_IOC_SET_PIN_FILE
+#ifndef F2FS_IOCTL_MAGIC
+#define F2FS_IOCTL_MAGIC		0xf5
+#endif
+#define F2FS_IOC_SET_PIN_FILE	_IOW(F2FS_IOCTL_MAGIC, 13, __u32)
+#define F2FS_IOC_GET_PIN_FILE	_IOW(F2FS_IOCTL_MAGIC, 14, __u32)
+#endif
+    if (f2fs_fs) {
+        int error = ioctl(fd, F2FS_IOC_SET_PIN_FILE);
+        // Don't break the old kernels which don't support it.
+        if (error && errno != ENOTTY && errno != ENOTSUP) {
+            PLOG(ERROR) << "Failed to set pin_file for f2fs: " << path << " on " << blk_dev;
+            return kUncryptIoctlError;
+        }
+    }
+
     off64_t pos = 0;
     int last_progress = 0;
     while (pos < sb.st_size) {
@@ -458,7 +491,8 @@
 
     bool encryptable;
     bool encrypted;
-    const char* blk_dev = find_block_device(path, &encryptable, &encrypted);
+    bool f2fs_fs;
+    const char* blk_dev = find_block_device(path, &encryptable, &encrypted, &f2fs_fs);
     if (blk_dev == nullptr) {
         LOG(ERROR) << "failed to find block device for " << path;
         return kUncryptBlockDeviceFindError;
@@ -479,7 +513,7 @@
     // and /sdcard we leave the file alone.
     if (strncmp(path, "/data/", 6) == 0) {
         LOG(INFO) << "writing block map " << map_file;
-        return produce_block_map(path, map_file, blk_dev, encrypted, socket);
+        return produce_block_map(path, map_file, blk_dev, encrypted, f2fs_fs, socket);
     }
 
     return 0;