profile_disk_operations.cc 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. // Copyright 2020 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "weblayer/browser/profile_disk_operations.h"
  5. #include "base/files/file_enumerator.h"
  6. #include "base/files/file_util.h"
  7. #include "base/logging.h"
  8. #include "base/path_service.h"
  9. #include "base/strings/string_number_conversions.h"
  10. #include "base/strings/string_split.h"
  11. #include "base/strings/string_util.h"
  12. #include "build/build_config.h"
  13. #include "components/base32/base32.h"
  14. #include "weblayer/common/weblayer_paths.h"
  15. namespace weblayer {
  16. // Variables named |name| is a string passed in from the embedder to identify a
  17. // profile. It can only contain alphanumeric and underscore.
  18. //
  19. // Variables named |dir_name| generally refers to the directory name of the
  20. // profile. It may be the |name| exactly, or it may be <name>.<number>, if a
  21. // profile is created with a name matching a profile marked for deletion.
  22. // |dir_name| is an implementation detail of this file and should not be exposed
  23. // as a concept out of this file.
  24. namespace {
  25. // Cannot be part of a valid name. This prevents the client ever specifying a
  26. // name that collides a different one with a suffix.
  27. constexpr char kSuffixDelimiter = '.';
  28. bool IsValidProfileNameChar(char c) {
  29. return base::IsAsciiDigit(c) || base::IsAsciiAlpha(c) || c == '_';
  30. }
  31. // Return the data path directory to profiles.
  32. base::FilePath GetProfileRootDataDir() {
  33. base::FilePath path;
  34. CHECK(base::PathService::Get(DIR_USER_DATA, &path));
  35. return path.AppendASCII("profiles");
  36. }
  37. base::FilePath GetProfileMarkerRootDataDir() {
  38. base::FilePath path;
  39. CHECK(base::PathService::Get(DIR_USER_DATA, &path));
  40. path = path.AppendASCII("profiles_to_delete");
  41. base::CreateDirectory(path);
  42. return path;
  43. }
  44. base::FilePath GetDataPathFromDirName(const std::string& dir_name) {
  45. return GetProfileRootDataDir().AppendASCII(dir_name.c_str());
  46. }
  47. #if BUILDFLAG(IS_POSIX)
  48. base::FilePath GetCachePathFromDirName(const std::string& dir_name) {
  49. base::FilePath cache_path;
  50. CHECK(base::PathService::Get(base::DIR_CACHE, &cache_path));
  51. cache_path = cache_path.AppendASCII("profiles").AppendASCII(dir_name.c_str());
  52. return cache_path;
  53. }
  54. #endif // BUILDFLAG(IS_POSIX)
  55. } // namespace
  56. ProfileInfo::ProfileInfo(bool is_incognito,
  57. const std::string& name,
  58. const base::FilePath& data_path,
  59. const base::FilePath& cache_path)
  60. : is_incognito(is_incognito),
  61. name(name),
  62. data_path(data_path),
  63. cache_path(cache_path) {}
  64. ProfileInfo::ProfileInfo() = default;
  65. ProfileInfo::ProfileInfo(const ProfileInfo&) = default;
  66. ProfileInfo& ProfileInfo::operator=(const ProfileInfo&) = default;
  67. ProfileInfo::~ProfileInfo() = default;
  68. ProfileInfo CreateProfileInfo(const std::string& name, bool is_incognito) {
  69. if (is_incognito)
  70. return {is_incognito, name, base::FilePath(), base::FilePath()};
  71. CHECK(internal::IsValidNameForNonIncognitoProfile(name));
  72. std::string dir_name = name;
  73. int suffix = 0;
  74. while (internal::IsProfileMarkedForDeletion(dir_name)) {
  75. suffix++;
  76. dir_name = name;
  77. dir_name.append(1, kSuffixDelimiter).append(base::NumberToString(suffix));
  78. }
  79. base::FilePath data_path = GetDataPathFromDirName(dir_name);
  80. base::CreateDirectory(data_path);
  81. base::FilePath cache_path = data_path;
  82. #if BUILDFLAG(IS_POSIX)
  83. cache_path = GetCachePathFromDirName(dir_name);
  84. base::CreateDirectory(cache_path);
  85. #endif
  86. return {is_incognito, name, data_path, cache_path};
  87. }
  88. base::FilePath ComputeBrowserPersisterDataBaseDir(const ProfileInfo& info) {
  89. base::FilePath base_path;
  90. if (info.is_incognito) {
  91. CHECK(base::PathService::Get(DIR_USER_DATA, &base_path));
  92. if (info.name.empty()) {
  93. // Originally the Android side of WebLayer only supported a single
  94. // incognito file with an empty name.
  95. std::string file_name = "Incognito Restore Data";
  96. base_path = base_path.AppendASCII(file_name);
  97. } else {
  98. std::string file_name = "Named Profile Incognito Restore Data";
  99. base_path = base_path.AppendASCII(file_name).AppendASCII(
  100. base32::Base32Encode(info.name));
  101. }
  102. } else {
  103. base_path = info.data_path.AppendASCII("Restore Data");
  104. }
  105. return base_path;
  106. }
  107. void MarkProfileAsDeleted(const ProfileInfo& info) {
  108. if (info.is_incognito)
  109. return;
  110. base::FilePath data_root_path = GetProfileRootDataDir();
  111. base::FilePath marker_path = GetProfileMarkerRootDataDir();
  112. CHECK(data_root_path.AppendRelativePath(info.data_path, &marker_path));
  113. base::File file(marker_path,
  114. base::File::FLAG_CREATE | base::File::FLAG_WRITE);
  115. if (!base::PathExists(marker_path)) {
  116. LOG(WARNING) << "Failure in deleting profile data. Profile:" << info.name
  117. << " error:" << static_cast<int>(file.error_details());
  118. }
  119. }
  120. void TryNukeProfileFromDisk(const ProfileInfo& info) {
  121. if (info.is_incognito) {
  122. // Incognito. Just delete session data.
  123. base::DeletePathRecursively(ComputeBrowserPersisterDataBaseDir(info));
  124. return;
  125. }
  126. // This may fail, but that is ok since the marker is not deleted.
  127. base::DeletePathRecursively(info.data_path);
  128. #if BUILDFLAG(IS_POSIX)
  129. base::DeletePathRecursively(info.cache_path);
  130. #endif
  131. }
  132. std::vector<std::string> ListProfileNames() {
  133. base::FilePath root_dir = GetProfileRootDataDir();
  134. std::vector<std::string> profile_names;
  135. base::FileEnumerator enumerator(root_dir, /*recursive=*/false,
  136. base::FileEnumerator::DIRECTORIES);
  137. for (base::FilePath path = enumerator.Next(); !path.empty();
  138. path = enumerator.Next()) {
  139. std::string dir_name = enumerator.GetInfo().GetName().MaybeAsASCII();
  140. std::string name = internal::CheckDirNameAndExtractName(dir_name);
  141. if (!name.empty() && !internal::IsProfileMarkedForDeletion(dir_name))
  142. profile_names.push_back(name);
  143. }
  144. return profile_names;
  145. }
  146. void NukeProfilesMarkedForDeletion() {
  147. base::FilePath marker_root_dir = GetProfileMarkerRootDataDir();
  148. base::FileEnumerator enumerator(marker_root_dir, /*recursive=*/false,
  149. base::FileEnumerator::FILES);
  150. for (base::FilePath marker_path = enumerator.Next(); !marker_path.empty();
  151. marker_path = enumerator.Next()) {
  152. std::string dir_name = enumerator.GetInfo().GetName().MaybeAsASCII();
  153. if (!internal::CheckDirNameAndExtractName(dir_name).empty()) {
  154. // Delete cache and data directory first before deleting marker.
  155. bool delete_success = true;
  156. #if BUILDFLAG(IS_POSIX)
  157. delete_success |=
  158. base::DeletePathRecursively(GetCachePathFromDirName(dir_name));
  159. #endif // BUILDFLAG(IS_POSIX)
  160. delete_success |=
  161. base::DeletePathRecursively(GetDataPathFromDirName(dir_name));
  162. // Only delete the marker if deletion is successful.
  163. if (delete_success) {
  164. base::DeleteFile(marker_path);
  165. }
  166. }
  167. }
  168. }
  169. namespace internal {
  170. bool IsValidNameForNonIncognitoProfile(const std::string& name) {
  171. for (char c : name) {
  172. if (!IsValidProfileNameChar(c))
  173. return false;
  174. }
  175. return !name.empty();
  176. }
  177. // If |dir_name| is valid, then return the |name|. Otherwise return the empty
  178. // string.
  179. std::string CheckDirNameAndExtractName(const std::string& dir_name) {
  180. std::vector<std::string> parts =
  181. base::SplitString(dir_name, std::string(1, kSuffixDelimiter),
  182. base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
  183. if (parts.size() == 0 || parts.size() > 2)
  184. return std::string();
  185. if (!IsValidNameForNonIncognitoProfile(parts[0]))
  186. return std::string();
  187. if (parts.size() > 1) {
  188. if (parts[1].empty())
  189. return std::string();
  190. for (char c : parts[1]) {
  191. if (!base::IsAsciiDigit(c))
  192. return std::string();
  193. }
  194. }
  195. return parts[0];
  196. }
  197. bool IsProfileMarkedForDeletion(const std::string& dir_name) {
  198. base::FilePath marker =
  199. GetProfileMarkerRootDataDir().AppendASCII(dir_name.c_str());
  200. return base::PathExists(marker);
  201. }
  202. } // namespace internal
  203. } // namespace weblayer