Reland: Reland: Create hard links in file migration if necessary.

- In addition to reland the CL, this CL moves file_cache_unittest.cc
  under chromeos directory as we have moved file_cache.cc/h there.

Original CL:
Reland: Create hard links in file migration if necessary.

[email protected]

Original CL:
Create hard links in file migration if necessary.

BUG=533750
TEST=unit_tests:FileCacheTest.MigrateCacheFiles

Committed: https://crrev.com/c5c297d58dc4d90423ed222f5bc7c06a84156324
Cr-Commit-Position: refs/heads/master@{#375836}

patch from issue 1698793003 at patchset 20001 (http://crrev.com/1698793003#ps20001)

Committed: https://crrev.com/cbe6dc8d336bcf5e8a9b0e7da7d5b0939bda32e6
Cr-Commit-Position: refs/heads/master@{#381888}

patch from issue 1811933004 at patchset 1 (http://crrev.com/1811933004#ps1)

Review URL: https://codereview.chromium.org/1894973007

Cr-Commit-Position: refs/heads/master@{#388434}
diff --git a/components/drive/chromeos/file_cache.cc b/components/drive/chromeos/file_cache.cc
index f3df512..a2eb6ea 100644
--- a/components/drive/chromeos/file_cache.cc
+++ b/components/drive/chromeos/file_cache.cc
@@ -4,6 +4,8 @@
 
 #include "components/drive/chromeos/file_cache.h"
 
+#include <unistd.h>
+
 #include <queue>
 #include <vector>
 
@@ -684,7 +686,8 @@
 
 // static
 bool FileCache::MigrateCacheFiles(const base::FilePath& from,
-                                  const base::FilePath& to,
+                                  const base::FilePath& to_files,
+                                  const base::FilePath& to_links,
                                   ResourceMetadataStorage* metadata_storage) {
   std::unique_ptr<ResourceMetadataStorage::Iterator> it =
       metadata_storage->GetIterator();
@@ -694,17 +697,31 @@
       continue;
     }
 
+    // Ignore missing cache file case since it never succeeds.
+    // TODO(yawano): handle this case at metadata validation in FileCache.
     const base::FilePath move_from = GetPathForId(from, entry.local_id());
     if (!base::PathExists(move_from)) {
       continue;
     }
 
-    const base::FilePath move_to = GetPathForId(to, entry.local_id());
+    // Create hard link to cache file if it's pinned or dirty. cryptohome will
+    // not delete a cache file if there is a hard link to it.
+    const FileCacheEntry& file_cache_entry =
+        entry.file_specific_info().cache_state();
+    if (file_cache_entry.is_pinned() || file_cache_entry.is_dirty()) {
+      const base::FilePath link_path = GetPathForId(to_links, entry.local_id());
+      int link_result = link(move_from.AsUTF8Unsafe().c_str(),
+                             link_path.AsUTF8Unsafe().c_str());
+      if (link_result != 0 && errno != EEXIST) {
+        return false;
+      }
+    }
+
+    // Move cache file.
+    const base::FilePath move_to = GetPathForId(to_files, entry.local_id());
     if (!base::Move(move_from, move_to)) {
       return false;
     }
-
-    // TODO(yawano): create hard link if entry is marked as pinned or dirty.
   }
 
   return true;