123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237 |
- // Copyright 2020 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "weblayer/browser/profile_disk_operations.h"
- #include "base/files/file_enumerator.h"
- #include "base/files/file_util.h"
- #include "base/logging.h"
- #include "base/path_service.h"
- #include "base/strings/string_number_conversions.h"
- #include "base/strings/string_split.h"
- #include "base/strings/string_util.h"
- #include "build/build_config.h"
- #include "components/base32/base32.h"
- #include "weblayer/common/weblayer_paths.h"
- namespace weblayer {
- // Variables named |name| is a string passed in from the embedder to identify a
- // profile. It can only contain alphanumeric and underscore.
- //
- // Variables named |dir_name| generally refers to the directory name of the
- // profile. It may be the |name| exactly, or it may be <name>.<number>, if a
- // profile is created with a name matching a profile marked for deletion.
- // |dir_name| is an implementation detail of this file and should not be exposed
- // as a concept out of this file.
- namespace {
- // Cannot be part of a valid name. This prevents the client ever specifying a
- // name that collides a different one with a suffix.
- constexpr char kSuffixDelimiter = '.';
- bool IsValidProfileNameChar(char c) {
- return base::IsAsciiDigit(c) || base::IsAsciiAlpha(c) || c == '_';
- }
- // Return the data path directory to profiles.
- base::FilePath GetProfileRootDataDir() {
- base::FilePath path;
- CHECK(base::PathService::Get(DIR_USER_DATA, &path));
- return path.AppendASCII("profiles");
- }
- base::FilePath GetProfileMarkerRootDataDir() {
- base::FilePath path;
- CHECK(base::PathService::Get(DIR_USER_DATA, &path));
- path = path.AppendASCII("profiles_to_delete");
- base::CreateDirectory(path);
- return path;
- }
- base::FilePath GetDataPathFromDirName(const std::string& dir_name) {
- return GetProfileRootDataDir().AppendASCII(dir_name.c_str());
- }
- #if BUILDFLAG(IS_POSIX)
- base::FilePath GetCachePathFromDirName(const std::string& dir_name) {
- base::FilePath cache_path;
- CHECK(base::PathService::Get(base::DIR_CACHE, &cache_path));
- cache_path = cache_path.AppendASCII("profiles").AppendASCII(dir_name.c_str());
- return cache_path;
- }
- #endif // BUILDFLAG(IS_POSIX)
- } // namespace
- ProfileInfo::ProfileInfo(bool is_incognito,
- const std::string& name,
- const base::FilePath& data_path,
- const base::FilePath& cache_path)
- : is_incognito(is_incognito),
- name(name),
- data_path(data_path),
- cache_path(cache_path) {}
- ProfileInfo::ProfileInfo() = default;
- ProfileInfo::ProfileInfo(const ProfileInfo&) = default;
- ProfileInfo& ProfileInfo::operator=(const ProfileInfo&) = default;
- ProfileInfo::~ProfileInfo() = default;
- ProfileInfo CreateProfileInfo(const std::string& name, bool is_incognito) {
- if (is_incognito)
- return {is_incognito, name, base::FilePath(), base::FilePath()};
- CHECK(internal::IsValidNameForNonIncognitoProfile(name));
- std::string dir_name = name;
- int suffix = 0;
- while (internal::IsProfileMarkedForDeletion(dir_name)) {
- suffix++;
- dir_name = name;
- dir_name.append(1, kSuffixDelimiter).append(base::NumberToString(suffix));
- }
- base::FilePath data_path = GetDataPathFromDirName(dir_name);
- base::CreateDirectory(data_path);
- base::FilePath cache_path = data_path;
- #if BUILDFLAG(IS_POSIX)
- cache_path = GetCachePathFromDirName(dir_name);
- base::CreateDirectory(cache_path);
- #endif
- return {is_incognito, name, data_path, cache_path};
- }
- base::FilePath ComputeBrowserPersisterDataBaseDir(const ProfileInfo& info) {
- base::FilePath base_path;
- if (info.is_incognito) {
- CHECK(base::PathService::Get(DIR_USER_DATA, &base_path));
- if (info.name.empty()) {
- // Originally the Android side of WebLayer only supported a single
- // incognito file with an empty name.
- std::string file_name = "Incognito Restore Data";
- base_path = base_path.AppendASCII(file_name);
- } else {
- std::string file_name = "Named Profile Incognito Restore Data";
- base_path = base_path.AppendASCII(file_name).AppendASCII(
- base32::Base32Encode(info.name));
- }
- } else {
- base_path = info.data_path.AppendASCII("Restore Data");
- }
- return base_path;
- }
- void MarkProfileAsDeleted(const ProfileInfo& info) {
- if (info.is_incognito)
- return;
- base::FilePath data_root_path = GetProfileRootDataDir();
- base::FilePath marker_path = GetProfileMarkerRootDataDir();
- CHECK(data_root_path.AppendRelativePath(info.data_path, &marker_path));
- base::File file(marker_path,
- base::File::FLAG_CREATE | base::File::FLAG_WRITE);
- if (!base::PathExists(marker_path)) {
- LOG(WARNING) << "Failure in deleting profile data. Profile:" << info.name
- << " error:" << static_cast<int>(file.error_details());
- }
- }
- void TryNukeProfileFromDisk(const ProfileInfo& info) {
- if (info.is_incognito) {
- // Incognito. Just delete session data.
- base::DeletePathRecursively(ComputeBrowserPersisterDataBaseDir(info));
- return;
- }
- // This may fail, but that is ok since the marker is not deleted.
- base::DeletePathRecursively(info.data_path);
- #if BUILDFLAG(IS_POSIX)
- base::DeletePathRecursively(info.cache_path);
- #endif
- }
- std::vector<std::string> ListProfileNames() {
- base::FilePath root_dir = GetProfileRootDataDir();
- std::vector<std::string> profile_names;
- base::FileEnumerator enumerator(root_dir, /*recursive=*/false,
- base::FileEnumerator::DIRECTORIES);
- for (base::FilePath path = enumerator.Next(); !path.empty();
- path = enumerator.Next()) {
- std::string dir_name = enumerator.GetInfo().GetName().MaybeAsASCII();
- std::string name = internal::CheckDirNameAndExtractName(dir_name);
- if (!name.empty() && !internal::IsProfileMarkedForDeletion(dir_name))
- profile_names.push_back(name);
- }
- return profile_names;
- }
- void NukeProfilesMarkedForDeletion() {
- base::FilePath marker_root_dir = GetProfileMarkerRootDataDir();
- base::FileEnumerator enumerator(marker_root_dir, /*recursive=*/false,
- base::FileEnumerator::FILES);
- for (base::FilePath marker_path = enumerator.Next(); !marker_path.empty();
- marker_path = enumerator.Next()) {
- std::string dir_name = enumerator.GetInfo().GetName().MaybeAsASCII();
- if (!internal::CheckDirNameAndExtractName(dir_name).empty()) {
- // Delete cache and data directory first before deleting marker.
- bool delete_success = true;
- #if BUILDFLAG(IS_POSIX)
- delete_success |=
- base::DeletePathRecursively(GetCachePathFromDirName(dir_name));
- #endif // BUILDFLAG(IS_POSIX)
- delete_success |=
- base::DeletePathRecursively(GetDataPathFromDirName(dir_name));
- // Only delete the marker if deletion is successful.
- if (delete_success) {
- base::DeleteFile(marker_path);
- }
- }
- }
- }
- namespace internal {
- bool IsValidNameForNonIncognitoProfile(const std::string& name) {
- for (char c : name) {
- if (!IsValidProfileNameChar(c))
- return false;
- }
- return !name.empty();
- }
- // If |dir_name| is valid, then return the |name|. Otherwise return the empty
- // string.
- std::string CheckDirNameAndExtractName(const std::string& dir_name) {
- std::vector<std::string> parts =
- base::SplitString(dir_name, std::string(1, kSuffixDelimiter),
- base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
- if (parts.size() == 0 || parts.size() > 2)
- return std::string();
- if (!IsValidNameForNonIncognitoProfile(parts[0]))
- return std::string();
- if (parts.size() > 1) {
- if (parts[1].empty())
- return std::string();
- for (char c : parts[1]) {
- if (!base::IsAsciiDigit(c))
- return std::string();
- }
- }
- return parts[0];
- }
- bool IsProfileMarkedForDeletion(const std::string& dir_name) {
- base::FilePath marker =
- GetProfileMarkerRootDataDir().AppendASCII(dir_name.c_str());
- return base::PathExists(marker);
- }
- } // namespace internal
- } // namespace weblayer
|