File: user_data_dir.cc

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (189 lines) | stat: -rw-r--r-- 6,955 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/install_static/user_data_dir.h"

#include <windows.h>

#include <assert.h>
#include <stdlib.h>

#include <optional>

#include "chrome/chrome_elf/nt_registry/nt_registry.h"
#include "chrome/install_static/install_details.h"
#include "chrome/install_static/install_util.h"
#include "chrome/install_static/policy_path_parser.h"

namespace install_static {

namespace {

std::wstring* g_user_data_dir;
std::wstring* g_invalid_user_data_dir;
bool g_temp_user_data_dir_created_for_headless = false;

// Retrieves a registry policy for the user data directory from the registry, if
// one is set. If there's none set in either HKLM or HKCU, |user_data_dir| will
// be unmodified.
void GetUserDataDirFromRegistryPolicyIfSet(const InstallConstants& mode,
                                           std::wstring* user_data_dir) {
  assert(user_data_dir);
  std::wstring policies_path = L"SOFTWARE\\Policies\\";
  AppendChromeInstallSubDirectory(mode, false /* !include_suffix */,
                                  &policies_path);

  std::wstring value;

  constexpr wchar_t kUserDataDirRegistryKeyName[] = L"UserDataDir";

  // First, try HKLM.
  if (nt::QueryRegValueSZ(nt::HKLM, nt::NONE, policies_path.c_str(),
                          kUserDataDirRegistryKeyName, &value)) {
    *user_data_dir = ExpandPathVariables(value);
    return;
  }

  // Second, try HKCU.
  if (nt::QueryRegValueSZ(nt::HKCU, nt::NONE, policies_path.c_str(),
                          kUserDataDirRegistryKeyName, &value)) {
    *user_data_dir = ExpandPathVariables(value);
    return;
  }
}

std::wstring MakeAbsoluteFilePath(const std::wstring& input) {
  wchar_t file_path[MAX_PATH];
  if (!_wfullpath(file_path, input.c_str(), _countof(file_path)))
    return std::wstring();
  return file_path;
}

// The same as GetUserDataDirectory(), but directly queries the global command
// line object for the --user-data-dir flag. This is the more commonly used
// function, where GetUserDataDirectory() is used primiarily for testing.
bool GetUserDataDirectoryUsingProcessCommandLine(
    const InstallConstants& mode,
    std::wstring* result,
    std::wstring* invalid_supplied_directory) {
  return GetUserDataDirectoryImpl(::GetCommandLine(), mode, result,
                                  invalid_supplied_directory);
}

// Populates |result| with the default User Data directory for the current
// user. Returns false if all attempts at locating a User Data directory fail.
// TODO(ananta)
// http://crbug.com/604923
// Unify this with the Browser Distribution code.
bool GetDefaultUserDataDirectory(const InstallConstants& mode,
                                 std::wstring* result) {
  // This environment variable should be set on Windows Vista and later
  // (https://msdn.microsoft.com/library/windows/desktop/dd378457.aspx).
  std::wstring user_data_dir = GetEnvironmentString(L"LOCALAPPDATA");

  if (user_data_dir.empty()) {
    // LOCALAPPDATA was not set; fallback to the temporary files path.
    DWORD size = ::GetTempPath(0, nullptr);
    if (!size)
      return false;
    user_data_dir.resize(size + 1);
    size = ::GetTempPath(size + 1, &user_data_dir[0]);
    if (!size || size >= user_data_dir.size())
      return false;
    user_data_dir.resize(size);
  }

  result->swap(user_data_dir);
  if ((*result)[result->length() - 1] != L'\\')
    result->push_back(L'\\');
  AppendChromeInstallSubDirectory(mode, true /* include_suffix */, result);
  result->push_back(L'\\');
  result->append(L"User Data");
  return true;
}

// Returns true if the |command_line| contains --headless or --headless=<value>
// where "<value>" is anything but "old". Note that the value checking portion
// should go away when the old headless code is removed from the Chrome binary,
// see https://crbug.com/366381673.
bool IsHeadlessMode(const std::wstring& command_line) {
  std::optional<std::wstring> opt =
      GetCommandLineSwitch(command_line, L"headless");
  return opt ? opt.value() != L"old" : false;
}

}  // namespace

bool GetUserDataDirectoryImpl(const std::wstring& command_line,
                              const InstallConstants& mode,
                              std::wstring* result,
                              std::wstring* invalid_supplied_directory) {
  std::wstring user_data_dir =
      GetCommandLineSwitchValue(command_line, kUserDataDirSwitch);

  GetUserDataDirFromRegistryPolicyIfSet(mode, &user_data_dir);

  // Headless Chrome instances are expected to run in parallel with the headful
  // Chrome and other headless Chrome instances. In order to do so, headless
  // Chrome needs a dedicated user data directory for each headless instance.
  // Provide one here unless user data directory is explicitly specified.
  g_temp_user_data_dir_created_for_headless = false;
  if (user_data_dir.empty() && IsHeadlessMode(command_line)) {
    // Avoid calling IsBrowserProcess() here because process type may not be
    // initialized yet at this point. This happens in unit tests.
    assert(GetCommandLineSwitchValue(command_line, kProcessType).empty());
    user_data_dir = CreateUniqueTempDirectory(L"Headless");
    if (!user_data_dir.empty()) {
      g_temp_user_data_dir_created_for_headless = true;
    }
  }

  // On Windows, trailing separators leave Chrome in a bad state. See
  // crbug.com/464616.
  while (!user_data_dir.empty() &&
         (user_data_dir.back() == '\\' || user_data_dir.back() == '/')) {
    user_data_dir.pop_back();
  }

  bool got_valid_directory =
      !user_data_dir.empty() && RecursiveDirectoryCreate(user_data_dir);
  if (!got_valid_directory) {
    *invalid_supplied_directory = user_data_dir;
    got_valid_directory = GetDefaultUserDataDirectory(mode, &user_data_dir);
  }

  // The Chrome implementation CHECKs() here in the browser process. We
  // don't as this function is used to initialize crash reporting, so
  // we would get no report of this failure.
  assert(got_valid_directory);
  if (!got_valid_directory)
    return false;

  *result = MakeAbsoluteFilePath(user_data_dir);
  return true;
}

bool GetUserDataDirectory(std::wstring* user_data_dir,
                          std::wstring* invalid_user_data_dir) {
  if (!g_user_data_dir) {
    g_user_data_dir = new std::wstring();
    g_invalid_user_data_dir = new std::wstring();
    if (!GetUserDataDirectoryUsingProcessCommandLine(
            InstallDetails::Get().mode(), g_user_data_dir,
            g_invalid_user_data_dir)) {
      return false;
    }
    assert(!g_user_data_dir->empty());
  }
  *user_data_dir = *g_user_data_dir;
  if (invalid_user_data_dir)
    *invalid_user_data_dir = *g_invalid_user_data_dir;
  return true;
}

bool IsTemporaryUserDataDirectoryCreatedForHeadless() {
  return g_temp_user_data_dir_created_for_headless;
}

}  // namespace install_static