cryptohome: Fix GetAccountDiskUsage() count file size twice.

/home/.shadow/$hash, which contains /home/.shadow/$hash/mount/user (bind
mounted to /home/user/$hash), and /home/.shadow/$hash/mount/root (bind
mounted to /home/root/$hash), is counted together with /home/root/$hash
and /home/user/$hash, thus causing the final calculated size to be off
by a factor of 2.

BUG=b:151092607
TEST=tast run $dut hwsec.AccountDiskUsage && unit tests

Change-Id: I0f70914ac078fcbeb150a2e794a749ddaaa3bcad
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform2/+/2095053
Tested-by: John L Chen <zuan@chromium.org>
Commit-Queue: John L Chen <zuan@chromium.org>
Reviewed-by: Gwendal Grignou <gwendal@chromium.org>
Reviewed-by: Victor-Gabriel Savu <vsavu@google.com>
diff --git a/cryptohome/homedirs.cc b/cryptohome/homedirs.cc
index d148552..2f790b3 100644
--- a/cryptohome/homedirs.cc
+++ b/cryptohome/homedirs.cc
@@ -1559,24 +1559,41 @@
     return 0;
   }
 
+  // Note that for ephemeral mounts, there could be a vault that's not
+  // ephemeral, but the current mount is ephemeral. In this case, ComputeSize()
+  // return the non ephemeral on disk vault's size.
   std::string obfuscated = BuildObfuscatedUsername(account_id, system_salt_);
   FilePath user_dir = FilePath(shadow_root_).Append(obfuscated);
-  FilePath user_path = brillo::cryptohome::home::GetUserPath(account_id);
-  FilePath root_path = brillo::cryptohome::home::GetRootPath(account_id);
-  int64_t total_size = 0;
-  int64_t size = platform_->ComputeDirectorySize(user_dir);
-  if (size > 0) {
-    total_size += size;
+
+  int64_t size = 0;
+  if (!platform_->DirectoryExists(user_dir)) {
+    // It's either ephemeral or the user doesn't exist. In either case, we check
+    // /home/user/$hash.
+    FilePath user_home_dir = brillo::cryptohome::home::GetUserPath(account_id);
+    size = platform_->ComputeDirectorySize(user_home_dir);
+  } else {
+    // Note that we'll need to handle both ecryptfs and dircrypto.
+    // dircrypto:
+    // /home/.shadow/$hash/mount: Always equal to the size occupied.
+    // ecryptfs:
+    // /home/.shadow/$hash/vault: Always equal to the size occupied.
+    // /home/.shadow/$hash/mount: Equal to the size occupied only when mounted.
+    // Therefore, we check to see if vault exists, if it exists, we compute
+    // vault's size, otherwise, we check mount's size.
+    FilePath mount_dir = user_dir.Append(kMountDir);
+    FilePath vault_dir = user_dir.Append(kEcryptfsVaultDir);
+    if (platform_->DirectoryExists(vault_dir)) {
+      // ecryptfs
+      size = platform_->ComputeDirectorySize(vault_dir);
+    } else {
+      // dircrypto
+      size = platform_->ComputeDirectorySize(mount_dir);
+    }
   }
-  size = platform_->ComputeDirectorySize(user_path);
   if (size > 0) {
-    total_size += size;
+    return size;
   }
-  size = platform_->ComputeDirectorySize(root_path);
-  if (size > 0) {
-    total_size += size;
-  }
-  return total_size;
+  return 0;
 }
 
 bool HomeDirs::Migrate(const Credentials& newcreds,
diff --git a/cryptohome/homedirs_unittest.cc b/cryptohome/homedirs_unittest.cc
index 4ce94a7..b7f4e03 100644
--- a/cryptohome/homedirs_unittest.cc
+++ b/cryptohome/homedirs_unittest.cc
@@ -276,38 +276,89 @@
   EXPECT_TRUE(homedirs_.Rename(kNewUserId, kDefaultUsers[0].username));
 }
 
-TEST_P(HomeDirsTest, ComputeSize) {
+TEST_P(HomeDirsTest, ComputeSizeDircrypto) {
   FilePath base_path(test_helper_.users[0].base_path);
-  FilePath user_path = brillo::cryptohome::home::GetUserPathPrefix()
-      .Append(test_helper_.users[0].obfuscated_username);
-  FilePath root_path = brillo::cryptohome::home::GetRootPathPrefix()
-      .Append(test_helper_.users[0].obfuscated_username);
+  // /home/.shadow in production code.
+  FilePath shadow_home =
+      homedirs_.shadow_root().Append(base_path.BaseName().value());
+  // /home/.shadow/$hash/mount in production code.
+  FilePath mount_dir = shadow_home.Append(kMountDir);
+  // /home/.shadow/$hash/vault in production code.
+  FilePath vault_dir = shadow_home.Append(kEcryptfsVaultDir);
+  // /home/user/$hash in production code and here in unit test.
+  FilePath user_dir = brillo::cryptohome::home::GetUserPathPrefix().Append(
+      test_helper_.users[0].obfuscated_username);
 
-  ASSERT_TRUE(base::CreateDirectory(base_path));
+  // If anyone asks, shadow_home, mount_dir and user_dir exists but not
+  // vault_dir.
+  ON_CALL(platform_, DirectoryExists(shadow_home)).WillByDefault(Return(true));
+  ON_CALL(platform_, DirectoryExists(mount_dir)).WillByDefault(Return(true));
+  ON_CALL(platform_, DirectoryExists(vault_dir)).WillByDefault(Return(false));
+  ON_CALL(platform_, DirectoryExists(user_dir)).WillByDefault(Return(true));
 
-  // Put test files under base_path and user_path.
-  const char kTestFileName0[] = "test.txt";
-  const char kExpectedData0[] = "file content";
-  int expected_bytes_0 = base::size(kExpectedData0);
-  ASSERT_EQ(expected_bytes_0,
-            base::WriteFile(base_path.Append(kTestFileName0),
-                            kExpectedData0, expected_bytes_0));
-  const char kTestFileName1[] = "test1.txt";
-  const char kExpectedData1[] = "file content";
-  int expected_bytes_1 = base::size(kExpectedData1);
-  ASSERT_EQ(expected_bytes_1,
-            base::WriteFile(base_path.Append(kTestFileName1),
-                            kExpectedData1, expected_bytes_1));
+  constexpr int64_t expected_bytes = 123456789012345;
+  constexpr int64_t unexpected_bytes = 98765432154321;
+  EXPECT_CALL(platform_, ComputeDirectorySize(mount_dir))
+      .WillOnce(Return(expected_bytes));
+  ON_CALL(platform_, ComputeDirectorySize(vault_dir))
+      .WillByDefault(Return(unexpected_bytes));
 
-  EXPECT_CALL(platform_, ComputeDirectorySize(base_path))
-    .WillOnce(Return(expected_bytes_0));
-  EXPECT_CALL(platform_, ComputeDirectorySize(user_path))
-    .WillOnce(Return(expected_bytes_1));
-  EXPECT_CALL(platform_, ComputeDirectorySize(root_path))
-    .WillOnce(Return(0));
+  EXPECT_EQ(expected_bytes, homedirs_.ComputeSize(kDefaultUsers[0].username));
+}
 
-  EXPECT_EQ(expected_bytes_0 + expected_bytes_1,
-            homedirs_.ComputeSize(kDefaultUsers[0].username));
+TEST_P(HomeDirsTest, ComputeSizeEcryptfs) {
+  FilePath base_path(test_helper_.users[0].base_path);
+  FilePath shadow_home =
+      homedirs_.shadow_root().Append(base_path.BaseName().value());
+  FilePath mount_dir = shadow_home.Append(kMountDir);
+  FilePath vault_dir = shadow_home.Append(kEcryptfsVaultDir);
+  FilePath user_dir = brillo::cryptohome::home::GetUserPathPrefix().Append(
+      test_helper_.users[0].obfuscated_username);
+
+  // If anyone asks, shadow_home, mount_dir, vault_dir and user_dir all exists.
+  ON_CALL(platform_, DirectoryExists(shadow_home)).WillByDefault(Return(true));
+  ON_CALL(platform_, DirectoryExists(mount_dir)).WillByDefault(Return(true));
+  ON_CALL(platform_, DirectoryExists(vault_dir)).WillByDefault(Return(true));
+  ON_CALL(platform_, DirectoryExists(user_dir)).WillByDefault(Return(true));
+
+  constexpr int64_t expected_bytes = 123456789012345;
+  constexpr int64_t unexpected_bytes = 98765432154321;
+  EXPECT_CALL(platform_, ComputeDirectorySize(vault_dir))
+      .WillOnce(Return(expected_bytes));
+  ON_CALL(platform_, ComputeDirectorySize(mount_dir))
+      .WillByDefault(Return(unexpected_bytes));
+
+  EXPECT_EQ(expected_bytes, homedirs_.ComputeSize(kDefaultUsers[0].username));
+}
+
+TEST_P(HomeDirsTest, ComputeSizeEphemeral) {
+  FilePath base_path(test_helper_.users[0].base_path);
+  FilePath shadow_home =
+      homedirs_.shadow_root().Append(base_path.BaseName().value());
+  FilePath mount_dir = shadow_home.Append(kMountDir);
+  FilePath vault_dir = shadow_home.Append(kEcryptfsVaultDir);
+  FilePath user_dir = brillo::cryptohome::home::GetUserPathPrefix().Append(
+      test_helper_.users[0].obfuscated_username);
+
+  // If anyone asks, shadow_home, mount_dir and vault_dir doesn't exist, but
+  // user_dir exists.
+  ON_CALL(platform_, DirectoryExists(shadow_home)).WillByDefault(Return(false));
+  ON_CALL(platform_, DirectoryExists(mount_dir)).WillByDefault(Return(false));
+  ON_CALL(platform_, DirectoryExists(vault_dir)).WillByDefault(Return(false));
+  ON_CALL(platform_, DirectoryExists(user_dir)).WillByDefault(Return(true));
+
+  constexpr int64_t expected_bytes = 123456789012345;
+  constexpr int64_t unexpected_bytes = 98765432154321;
+  EXPECT_CALL(platform_, ComputeDirectorySize(user_dir))
+      .WillOnce(Return(expected_bytes));
+  ON_CALL(platform_, ComputeDirectorySize(mount_dir))
+      .WillByDefault(Return(unexpected_bytes));
+  ON_CALL(platform_, ComputeDirectorySize(vault_dir))
+      .WillByDefault(Return(unexpected_bytes));
+  ON_CALL(platform_, ComputeDirectorySize(shadow_home))
+      .WillByDefault(Return(unexpected_bytes));
+
+  EXPECT_EQ(expected_bytes, homedirs_.ComputeSize(kDefaultUsers[0].username));
 }
 
 TEST_P(HomeDirsTest, ComputeSizeWithNonexistentUser) {