f2fs: support f2fs by setting unmovable bit for package file

This enables to use uncrypt for f2fs update-on-reboot.
It requires kernel patch named:
    "f2fs: add an ioctl to disable GC for specific file"

If any operation fails during uncrypt, please delete package file as soon as
possible, and create the file again to move forward. IOWs, don't leave the
package file for a long time.

Bug: 70309376
Bug: 30170612
Change-Id: I3b4233e7da756f107be35364521699deaf2e7139
Merged-In: I3b4233e7da756f107be35364521699deaf2e7139
Signed-off-by: Jaegeuk Kim <jaegeuk@google.com>
diff --git a/uncrypt/uncrypt.cpp b/uncrypt/uncrypt.cpp
index 645faad..bb43c2c 100644
--- a/uncrypt/uncrypt.cpp
+++ b/uncrypt/uncrypt.cpp
@@ -172,10 +172,14 @@
     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 0 first.
+    if (f2fs_fs)
+        *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 +196,8 @@
                     *encrypted = true;
                 }
             }
+            if (f2fs_fs && strcmp(v->fs_type, "f2fs") == 0)
+                *f2fs_fs = true;
             return v->blk_device;
         }
     }
@@ -244,7 +250,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 +313,17 @@
         }
     }
 
+#ifndef F2FS_IOC_SET_DONTMOVE
+#ifndef F2FS_IOCTL_MAGIC
+#define F2FS_IOCTL_MAGIC		0xf5
+#endif
+#define F2FS_IOC_SET_DONTMOVE		_IO(F2FS_IOCTL_MAGIC, 13)
+#endif
+    if (f2fs_fs && ioctl(fd, F2FS_IOC_SET_DONTMOVE) < 0) {
+        PLOG(ERROR) << "Failed to set non-movable file for f2fs: " << path << " on " << blk_dev;
+        return kUncryptIoctlError;
+    }
+
     off64_t pos = 0;
     int last_progress = 0;
     while (pos < sb.st_size) {
@@ -458,7 +475,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 +497,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;