1*6777b538SAndroid Build Coastguard Worker // Copyright 2012 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker
5*6777b538SAndroid Build Coastguard Worker #include "base/files/file_util.h"
6*6777b538SAndroid Build Coastguard Worker
7*6777b538SAndroid Build Coastguard Worker #include <windows.h>
8*6777b538SAndroid Build Coastguard Worker #include <winsock2.h>
9*6777b538SAndroid Build Coastguard Worker
10*6777b538SAndroid Build Coastguard Worker #include <io.h>
11*6777b538SAndroid Build Coastguard Worker #include <psapi.h>
12*6777b538SAndroid Build Coastguard Worker #include <shellapi.h>
13*6777b538SAndroid Build Coastguard Worker #include <shlobj.h>
14*6777b538SAndroid Build Coastguard Worker #include <stddef.h>
15*6777b538SAndroid Build Coastguard Worker #include <stdint.h>
16*6777b538SAndroid Build Coastguard Worker #include <time.h>
17*6777b538SAndroid Build Coastguard Worker
18*6777b538SAndroid Build Coastguard Worker #include <algorithm>
19*6777b538SAndroid Build Coastguard Worker #include <limits>
20*6777b538SAndroid Build Coastguard Worker #include <string>
21*6777b538SAndroid Build Coastguard Worker #include <utility>
22*6777b538SAndroid Build Coastguard Worker #include <vector>
23*6777b538SAndroid Build Coastguard Worker
24*6777b538SAndroid Build Coastguard Worker #include "base/check.h"
25*6777b538SAndroid Build Coastguard Worker #include "base/clang_profiling_buildflags.h"
26*6777b538SAndroid Build Coastguard Worker #include "base/debug/alias.h"
27*6777b538SAndroid Build Coastguard Worker #include "base/feature_list.h"
28*6777b538SAndroid Build Coastguard Worker #include "base/features.h"
29*6777b538SAndroid Build Coastguard Worker #include "base/files/file_enumerator.h"
30*6777b538SAndroid Build Coastguard Worker #include "base/files/file_path.h"
31*6777b538SAndroid Build Coastguard Worker #include "base/files/memory_mapped_file.h"
32*6777b538SAndroid Build Coastguard Worker #include "base/functional/bind.h"
33*6777b538SAndroid Build Coastguard Worker #include "base/functional/callback.h"
34*6777b538SAndroid Build Coastguard Worker #include "base/location.h"
35*6777b538SAndroid Build Coastguard Worker #include "base/logging.h"
36*6777b538SAndroid Build Coastguard Worker #include "base/numerics/safe_conversions.h"
37*6777b538SAndroid Build Coastguard Worker #include "base/path_service.h"
38*6777b538SAndroid Build Coastguard Worker #include "base/process/process_handle.h"
39*6777b538SAndroid Build Coastguard Worker #include "base/rand_util.h"
40*6777b538SAndroid Build Coastguard Worker #include "base/strings/strcat.h"
41*6777b538SAndroid Build Coastguard Worker #include "base/strings/string_number_conversions.h"
42*6777b538SAndroid Build Coastguard Worker #include "base/strings/string_piece.h"
43*6777b538SAndroid Build Coastguard Worker #include "base/strings/string_util.h"
44*6777b538SAndroid Build Coastguard Worker #include "base/strings/string_util_win.h"
45*6777b538SAndroid Build Coastguard Worker #include "base/strings/utf_string_conversions.h"
46*6777b538SAndroid Build Coastguard Worker #include "base/task/bind_post_task.h"
47*6777b538SAndroid Build Coastguard Worker #include "base/task/sequenced_task_runner.h"
48*6777b538SAndroid Build Coastguard Worker #include "base/task/thread_pool.h"
49*6777b538SAndroid Build Coastguard Worker #include "base/threading/scoped_blocking_call.h"
50*6777b538SAndroid Build Coastguard Worker #include "base/threading/scoped_thread_priority.h"
51*6777b538SAndroid Build Coastguard Worker #include "base/time/time.h"
52*6777b538SAndroid Build Coastguard Worker #include "base/uuid.h"
53*6777b538SAndroid Build Coastguard Worker #include "base/win/scoped_handle.h"
54*6777b538SAndroid Build Coastguard Worker #include "base/win/security_util.h"
55*6777b538SAndroid Build Coastguard Worker #include "base/win/sid.h"
56*6777b538SAndroid Build Coastguard Worker #include "base/win/windows_types.h"
57*6777b538SAndroid Build Coastguard Worker #include "base/win/windows_version.h"
58*6777b538SAndroid Build Coastguard Worker
59*6777b538SAndroid Build Coastguard Worker namespace base {
60*6777b538SAndroid Build Coastguard Worker
61*6777b538SAndroid Build Coastguard Worker namespace {
62*6777b538SAndroid Build Coastguard Worker
63*6777b538SAndroid Build Coastguard Worker int g_extra_allowed_path_for_no_execute = 0;
64*6777b538SAndroid Build Coastguard Worker
65*6777b538SAndroid Build Coastguard Worker bool g_disable_secure_system_temp_for_testing = false;
66*6777b538SAndroid Build Coastguard Worker
67*6777b538SAndroid Build Coastguard Worker const DWORD kFileShareAll =
68*6777b538SAndroid Build Coastguard Worker FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
69*6777b538SAndroid Build Coastguard Worker const wchar_t kDefaultTempDirPrefix[] = L"ChromiumTemp";
70*6777b538SAndroid Build Coastguard Worker
71*6777b538SAndroid Build Coastguard Worker // Returns the Win32 last error code or ERROR_SUCCESS if the last error code is
72*6777b538SAndroid Build Coastguard Worker // ERROR_FILE_NOT_FOUND or ERROR_PATH_NOT_FOUND. This is useful in cases where
73*6777b538SAndroid Build Coastguard Worker // the absence of a file or path is a success condition (e.g., when attempting
74*6777b538SAndroid Build Coastguard Worker // to delete an item in the filesystem).
ReturnLastErrorOrSuccessOnNotFound()75*6777b538SAndroid Build Coastguard Worker DWORD ReturnLastErrorOrSuccessOnNotFound() {
76*6777b538SAndroid Build Coastguard Worker const DWORD error_code = ::GetLastError();
77*6777b538SAndroid Build Coastguard Worker return (error_code == ERROR_FILE_NOT_FOUND ||
78*6777b538SAndroid Build Coastguard Worker error_code == ERROR_PATH_NOT_FOUND)
79*6777b538SAndroid Build Coastguard Worker ? ERROR_SUCCESS
80*6777b538SAndroid Build Coastguard Worker : error_code;
81*6777b538SAndroid Build Coastguard Worker }
82*6777b538SAndroid Build Coastguard Worker
83*6777b538SAndroid Build Coastguard Worker // Deletes all files and directories in a path.
84*6777b538SAndroid Build Coastguard Worker // Returns ERROR_SUCCESS on success or the Windows error code corresponding to
85*6777b538SAndroid Build Coastguard Worker // the first error encountered. ERROR_FILE_NOT_FOUND and ERROR_PATH_NOT_FOUND
86*6777b538SAndroid Build Coastguard Worker // are considered success conditions, and are therefore never returned.
DeleteFileRecursive(const FilePath & path,const FilePath::StringType & pattern,bool recursive)87*6777b538SAndroid Build Coastguard Worker DWORD DeleteFileRecursive(const FilePath& path,
88*6777b538SAndroid Build Coastguard Worker const FilePath::StringType& pattern,
89*6777b538SAndroid Build Coastguard Worker bool recursive) {
90*6777b538SAndroid Build Coastguard Worker FileEnumerator traversal(path, false,
91*6777b538SAndroid Build Coastguard Worker FileEnumerator::FILES | FileEnumerator::DIRECTORIES,
92*6777b538SAndroid Build Coastguard Worker pattern);
93*6777b538SAndroid Build Coastguard Worker DWORD result = ERROR_SUCCESS;
94*6777b538SAndroid Build Coastguard Worker for (FilePath current = traversal.Next(); !current.empty();
95*6777b538SAndroid Build Coastguard Worker current = traversal.Next()) {
96*6777b538SAndroid Build Coastguard Worker // Try to clear the read-only bit if we find it.
97*6777b538SAndroid Build Coastguard Worker FileEnumerator::FileInfo info = traversal.GetInfo();
98*6777b538SAndroid Build Coastguard Worker if ((info.find_data().dwFileAttributes & FILE_ATTRIBUTE_READONLY) &&
99*6777b538SAndroid Build Coastguard Worker (recursive || !info.IsDirectory())) {
100*6777b538SAndroid Build Coastguard Worker ::SetFileAttributes(
101*6777b538SAndroid Build Coastguard Worker current.value().c_str(),
102*6777b538SAndroid Build Coastguard Worker info.find_data().dwFileAttributes & ~DWORD{FILE_ATTRIBUTE_READONLY});
103*6777b538SAndroid Build Coastguard Worker }
104*6777b538SAndroid Build Coastguard Worker
105*6777b538SAndroid Build Coastguard Worker DWORD this_result = ERROR_SUCCESS;
106*6777b538SAndroid Build Coastguard Worker if (info.IsDirectory()) {
107*6777b538SAndroid Build Coastguard Worker if (recursive) {
108*6777b538SAndroid Build Coastguard Worker this_result = DeleteFileRecursive(current, pattern, true);
109*6777b538SAndroid Build Coastguard Worker DCHECK_NE(static_cast<LONG>(this_result), ERROR_FILE_NOT_FOUND);
110*6777b538SAndroid Build Coastguard Worker DCHECK_NE(static_cast<LONG>(this_result), ERROR_PATH_NOT_FOUND);
111*6777b538SAndroid Build Coastguard Worker if (this_result == ERROR_SUCCESS &&
112*6777b538SAndroid Build Coastguard Worker !::RemoveDirectory(current.value().c_str())) {
113*6777b538SAndroid Build Coastguard Worker this_result = ReturnLastErrorOrSuccessOnNotFound();
114*6777b538SAndroid Build Coastguard Worker }
115*6777b538SAndroid Build Coastguard Worker }
116*6777b538SAndroid Build Coastguard Worker } else if (!::DeleteFile(current.value().c_str())) {
117*6777b538SAndroid Build Coastguard Worker this_result = ReturnLastErrorOrSuccessOnNotFound();
118*6777b538SAndroid Build Coastguard Worker }
119*6777b538SAndroid Build Coastguard Worker if (result == ERROR_SUCCESS)
120*6777b538SAndroid Build Coastguard Worker result = this_result;
121*6777b538SAndroid Build Coastguard Worker }
122*6777b538SAndroid Build Coastguard Worker return result;
123*6777b538SAndroid Build Coastguard Worker }
124*6777b538SAndroid Build Coastguard Worker
125*6777b538SAndroid Build Coastguard Worker // Appends |mode_char| to |mode| before the optional character set encoding; see
126*6777b538SAndroid Build Coastguard Worker // https://msdn.microsoft.com/library/yeby3zcb.aspx for details.
AppendModeCharacter(wchar_t mode_char,std::wstring * mode)127*6777b538SAndroid Build Coastguard Worker void AppendModeCharacter(wchar_t mode_char, std::wstring* mode) {
128*6777b538SAndroid Build Coastguard Worker size_t comma_pos = mode->find(L',');
129*6777b538SAndroid Build Coastguard Worker mode->insert(comma_pos == std::wstring::npos ? mode->length() : comma_pos, 1,
130*6777b538SAndroid Build Coastguard Worker mode_char);
131*6777b538SAndroid Build Coastguard Worker }
132*6777b538SAndroid Build Coastguard Worker
DoCopyFile(const FilePath & from_path,const FilePath & to_path,bool fail_if_exists)133*6777b538SAndroid Build Coastguard Worker bool DoCopyFile(const FilePath& from_path,
134*6777b538SAndroid Build Coastguard Worker const FilePath& to_path,
135*6777b538SAndroid Build Coastguard Worker bool fail_if_exists) {
136*6777b538SAndroid Build Coastguard Worker ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
137*6777b538SAndroid Build Coastguard Worker if (from_path.ReferencesParent() || to_path.ReferencesParent())
138*6777b538SAndroid Build Coastguard Worker return false;
139*6777b538SAndroid Build Coastguard Worker
140*6777b538SAndroid Build Coastguard Worker // NOTE: I suspect we could support longer paths, but that would involve
141*6777b538SAndroid Build Coastguard Worker // analyzing all our usage of files.
142*6777b538SAndroid Build Coastguard Worker if (from_path.value().length() >= MAX_PATH ||
143*6777b538SAndroid Build Coastguard Worker to_path.value().length() >= MAX_PATH) {
144*6777b538SAndroid Build Coastguard Worker return false;
145*6777b538SAndroid Build Coastguard Worker }
146*6777b538SAndroid Build Coastguard Worker
147*6777b538SAndroid Build Coastguard Worker // Mitigate the issues caused by loading DLLs on a background thread
148*6777b538SAndroid Build Coastguard Worker // (http://crbug/973868).
149*6777b538SAndroid Build Coastguard Worker SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY();
150*6777b538SAndroid Build Coastguard Worker
151*6777b538SAndroid Build Coastguard Worker // Unlike the posix implementation that copies the file manually and discards
152*6777b538SAndroid Build Coastguard Worker // the ACL bits, CopyFile() copies the complete SECURITY_DESCRIPTOR and access
153*6777b538SAndroid Build Coastguard Worker // bits, which is usually not what we want. We can't do much about the
154*6777b538SAndroid Build Coastguard Worker // SECURITY_DESCRIPTOR but at least remove the read only bit.
155*6777b538SAndroid Build Coastguard Worker const wchar_t* dest = to_path.value().c_str();
156*6777b538SAndroid Build Coastguard Worker if (!::CopyFile(from_path.value().c_str(), dest, fail_if_exists)) {
157*6777b538SAndroid Build Coastguard Worker // Copy failed.
158*6777b538SAndroid Build Coastguard Worker return false;
159*6777b538SAndroid Build Coastguard Worker }
160*6777b538SAndroid Build Coastguard Worker DWORD attrs = GetFileAttributes(dest);
161*6777b538SAndroid Build Coastguard Worker if (attrs == INVALID_FILE_ATTRIBUTES) {
162*6777b538SAndroid Build Coastguard Worker return false;
163*6777b538SAndroid Build Coastguard Worker }
164*6777b538SAndroid Build Coastguard Worker if (attrs & FILE_ATTRIBUTE_READONLY) {
165*6777b538SAndroid Build Coastguard Worker SetFileAttributes(dest, attrs & ~DWORD{FILE_ATTRIBUTE_READONLY});
166*6777b538SAndroid Build Coastguard Worker }
167*6777b538SAndroid Build Coastguard Worker return true;
168*6777b538SAndroid Build Coastguard Worker }
169*6777b538SAndroid Build Coastguard Worker
DoCopyDirectory(const FilePath & from_path,const FilePath & to_path,bool recursive,bool fail_if_exists)170*6777b538SAndroid Build Coastguard Worker bool DoCopyDirectory(const FilePath& from_path,
171*6777b538SAndroid Build Coastguard Worker const FilePath& to_path,
172*6777b538SAndroid Build Coastguard Worker bool recursive,
173*6777b538SAndroid Build Coastguard Worker bool fail_if_exists) {
174*6777b538SAndroid Build Coastguard Worker // NOTE(maruel): Previous version of this function used to call
175*6777b538SAndroid Build Coastguard Worker // SHFileOperation(). This used to copy the file attributes and extended
176*6777b538SAndroid Build Coastguard Worker // attributes, OLE structured storage, NTFS file system alternate data
177*6777b538SAndroid Build Coastguard Worker // streams, SECURITY_DESCRIPTOR. In practice, this is not what we want, we
178*6777b538SAndroid Build Coastguard Worker // want the containing directory to propagate its SECURITY_DESCRIPTOR.
179*6777b538SAndroid Build Coastguard Worker ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
180*6777b538SAndroid Build Coastguard Worker
181*6777b538SAndroid Build Coastguard Worker // NOTE: I suspect we could support longer paths, but that would involve
182*6777b538SAndroid Build Coastguard Worker // analyzing all our usage of files.
183*6777b538SAndroid Build Coastguard Worker if (from_path.value().length() >= MAX_PATH ||
184*6777b538SAndroid Build Coastguard Worker to_path.value().length() >= MAX_PATH) {
185*6777b538SAndroid Build Coastguard Worker return false;
186*6777b538SAndroid Build Coastguard Worker }
187*6777b538SAndroid Build Coastguard Worker
188*6777b538SAndroid Build Coastguard Worker // This function does not properly handle destinations within the source.
189*6777b538SAndroid Build Coastguard Worker FilePath real_to_path = to_path;
190*6777b538SAndroid Build Coastguard Worker if (PathExists(real_to_path)) {
191*6777b538SAndroid Build Coastguard Worker real_to_path = MakeAbsoluteFilePath(real_to_path);
192*6777b538SAndroid Build Coastguard Worker if (real_to_path.empty())
193*6777b538SAndroid Build Coastguard Worker return false;
194*6777b538SAndroid Build Coastguard Worker } else {
195*6777b538SAndroid Build Coastguard Worker real_to_path = MakeAbsoluteFilePath(real_to_path.DirName());
196*6777b538SAndroid Build Coastguard Worker if (real_to_path.empty())
197*6777b538SAndroid Build Coastguard Worker return false;
198*6777b538SAndroid Build Coastguard Worker }
199*6777b538SAndroid Build Coastguard Worker FilePath real_from_path = MakeAbsoluteFilePath(from_path);
200*6777b538SAndroid Build Coastguard Worker if (real_from_path.empty())
201*6777b538SAndroid Build Coastguard Worker return false;
202*6777b538SAndroid Build Coastguard Worker if (real_to_path == real_from_path || real_from_path.IsParent(real_to_path))
203*6777b538SAndroid Build Coastguard Worker return false;
204*6777b538SAndroid Build Coastguard Worker
205*6777b538SAndroid Build Coastguard Worker int traverse_type = FileEnumerator::FILES;
206*6777b538SAndroid Build Coastguard Worker if (recursive)
207*6777b538SAndroid Build Coastguard Worker traverse_type |= FileEnumerator::DIRECTORIES;
208*6777b538SAndroid Build Coastguard Worker FileEnumerator traversal(from_path, recursive, traverse_type);
209*6777b538SAndroid Build Coastguard Worker
210*6777b538SAndroid Build Coastguard Worker if (!PathExists(from_path)) {
211*6777b538SAndroid Build Coastguard Worker DLOG(ERROR) << "CopyDirectory() couldn't stat source directory: "
212*6777b538SAndroid Build Coastguard Worker << from_path.value().c_str();
213*6777b538SAndroid Build Coastguard Worker return false;
214*6777b538SAndroid Build Coastguard Worker }
215*6777b538SAndroid Build Coastguard Worker // TODO(maruel): This is not necessary anymore.
216*6777b538SAndroid Build Coastguard Worker DCHECK(recursive || DirectoryExists(from_path));
217*6777b538SAndroid Build Coastguard Worker
218*6777b538SAndroid Build Coastguard Worker FilePath current = from_path;
219*6777b538SAndroid Build Coastguard Worker bool from_is_dir = DirectoryExists(from_path);
220*6777b538SAndroid Build Coastguard Worker bool success = true;
221*6777b538SAndroid Build Coastguard Worker FilePath from_path_base = from_path;
222*6777b538SAndroid Build Coastguard Worker if (recursive && DirectoryExists(to_path)) {
223*6777b538SAndroid Build Coastguard Worker // If the destination already exists and is a directory, then the
224*6777b538SAndroid Build Coastguard Worker // top level of source needs to be copied.
225*6777b538SAndroid Build Coastguard Worker from_path_base = from_path.DirName();
226*6777b538SAndroid Build Coastguard Worker }
227*6777b538SAndroid Build Coastguard Worker
228*6777b538SAndroid Build Coastguard Worker while (success && !current.empty()) {
229*6777b538SAndroid Build Coastguard Worker // current is the source path, including from_path, so append
230*6777b538SAndroid Build Coastguard Worker // the suffix after from_path to to_path to create the target_path.
231*6777b538SAndroid Build Coastguard Worker FilePath target_path(to_path);
232*6777b538SAndroid Build Coastguard Worker if (from_path_base != current) {
233*6777b538SAndroid Build Coastguard Worker if (!from_path_base.AppendRelativePath(current, &target_path)) {
234*6777b538SAndroid Build Coastguard Worker success = false;
235*6777b538SAndroid Build Coastguard Worker break;
236*6777b538SAndroid Build Coastguard Worker }
237*6777b538SAndroid Build Coastguard Worker }
238*6777b538SAndroid Build Coastguard Worker
239*6777b538SAndroid Build Coastguard Worker if (from_is_dir) {
240*6777b538SAndroid Build Coastguard Worker if (!DirectoryExists(target_path) &&
241*6777b538SAndroid Build Coastguard Worker !::CreateDirectory(target_path.value().c_str(), NULL)) {
242*6777b538SAndroid Build Coastguard Worker DLOG(ERROR) << "CopyDirectory() couldn't create directory: "
243*6777b538SAndroid Build Coastguard Worker << target_path.value().c_str();
244*6777b538SAndroid Build Coastguard Worker success = false;
245*6777b538SAndroid Build Coastguard Worker }
246*6777b538SAndroid Build Coastguard Worker } else if (!DoCopyFile(current, target_path, fail_if_exists)) {
247*6777b538SAndroid Build Coastguard Worker DLOG(ERROR) << "CopyDirectory() couldn't create file: "
248*6777b538SAndroid Build Coastguard Worker << target_path.value().c_str();
249*6777b538SAndroid Build Coastguard Worker success = false;
250*6777b538SAndroid Build Coastguard Worker }
251*6777b538SAndroid Build Coastguard Worker
252*6777b538SAndroid Build Coastguard Worker current = traversal.Next();
253*6777b538SAndroid Build Coastguard Worker if (!current.empty())
254*6777b538SAndroid Build Coastguard Worker from_is_dir = traversal.GetInfo().IsDirectory();
255*6777b538SAndroid Build Coastguard Worker }
256*6777b538SAndroid Build Coastguard Worker
257*6777b538SAndroid Build Coastguard Worker return success;
258*6777b538SAndroid Build Coastguard Worker }
259*6777b538SAndroid Build Coastguard Worker
260*6777b538SAndroid Build Coastguard Worker // Returns ERROR_SUCCESS on success, or a Windows error code on failure.
DoDeleteFile(const FilePath & path,bool recursive)261*6777b538SAndroid Build Coastguard Worker DWORD DoDeleteFile(const FilePath& path, bool recursive) {
262*6777b538SAndroid Build Coastguard Worker ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
263*6777b538SAndroid Build Coastguard Worker
264*6777b538SAndroid Build Coastguard Worker if (path.empty())
265*6777b538SAndroid Build Coastguard Worker return ERROR_SUCCESS;
266*6777b538SAndroid Build Coastguard Worker
267*6777b538SAndroid Build Coastguard Worker if (path.value().length() >= MAX_PATH)
268*6777b538SAndroid Build Coastguard Worker return ERROR_BAD_PATHNAME;
269*6777b538SAndroid Build Coastguard Worker
270*6777b538SAndroid Build Coastguard Worker // Handle any path with wildcards.
271*6777b538SAndroid Build Coastguard Worker if (path.BaseName().value().find_first_of(FILE_PATH_LITERAL("*?")) !=
272*6777b538SAndroid Build Coastguard Worker FilePath::StringType::npos) {
273*6777b538SAndroid Build Coastguard Worker const DWORD error_code =
274*6777b538SAndroid Build Coastguard Worker DeleteFileRecursive(path.DirName(), path.BaseName().value(), recursive);
275*6777b538SAndroid Build Coastguard Worker DCHECK_NE(static_cast<LONG>(error_code), ERROR_FILE_NOT_FOUND);
276*6777b538SAndroid Build Coastguard Worker DCHECK_NE(static_cast<LONG>(error_code), ERROR_PATH_NOT_FOUND);
277*6777b538SAndroid Build Coastguard Worker return error_code;
278*6777b538SAndroid Build Coastguard Worker }
279*6777b538SAndroid Build Coastguard Worker
280*6777b538SAndroid Build Coastguard Worker // Report success if the file or path does not exist.
281*6777b538SAndroid Build Coastguard Worker const DWORD attr = ::GetFileAttributes(path.value().c_str());
282*6777b538SAndroid Build Coastguard Worker if (attr == INVALID_FILE_ATTRIBUTES)
283*6777b538SAndroid Build Coastguard Worker return ReturnLastErrorOrSuccessOnNotFound();
284*6777b538SAndroid Build Coastguard Worker
285*6777b538SAndroid Build Coastguard Worker // Clear the read-only bit if it is set.
286*6777b538SAndroid Build Coastguard Worker if ((attr & FILE_ATTRIBUTE_READONLY) &&
287*6777b538SAndroid Build Coastguard Worker !::SetFileAttributes(path.value().c_str(),
288*6777b538SAndroid Build Coastguard Worker attr & ~DWORD{FILE_ATTRIBUTE_READONLY})) {
289*6777b538SAndroid Build Coastguard Worker // It's possible for |path| to be gone now under a race with other deleters.
290*6777b538SAndroid Build Coastguard Worker return ReturnLastErrorOrSuccessOnNotFound();
291*6777b538SAndroid Build Coastguard Worker }
292*6777b538SAndroid Build Coastguard Worker
293*6777b538SAndroid Build Coastguard Worker // Perform a simple delete on anything that isn't a directory.
294*6777b538SAndroid Build Coastguard Worker if (!(attr & FILE_ATTRIBUTE_DIRECTORY)) {
295*6777b538SAndroid Build Coastguard Worker return ::DeleteFile(path.value().c_str())
296*6777b538SAndroid Build Coastguard Worker ? ERROR_SUCCESS
297*6777b538SAndroid Build Coastguard Worker : ReturnLastErrorOrSuccessOnNotFound();
298*6777b538SAndroid Build Coastguard Worker }
299*6777b538SAndroid Build Coastguard Worker
300*6777b538SAndroid Build Coastguard Worker if (recursive) {
301*6777b538SAndroid Build Coastguard Worker const DWORD error_code =
302*6777b538SAndroid Build Coastguard Worker DeleteFileRecursive(path, FILE_PATH_LITERAL("*"), true);
303*6777b538SAndroid Build Coastguard Worker DCHECK_NE(static_cast<LONG>(error_code), ERROR_FILE_NOT_FOUND);
304*6777b538SAndroid Build Coastguard Worker DCHECK_NE(static_cast<LONG>(error_code), ERROR_PATH_NOT_FOUND);
305*6777b538SAndroid Build Coastguard Worker if (error_code != ERROR_SUCCESS)
306*6777b538SAndroid Build Coastguard Worker return error_code;
307*6777b538SAndroid Build Coastguard Worker }
308*6777b538SAndroid Build Coastguard Worker return ::RemoveDirectory(path.value().c_str())
309*6777b538SAndroid Build Coastguard Worker ? ERROR_SUCCESS
310*6777b538SAndroid Build Coastguard Worker : ReturnLastErrorOrSuccessOnNotFound();
311*6777b538SAndroid Build Coastguard Worker }
312*6777b538SAndroid Build Coastguard Worker
313*6777b538SAndroid Build Coastguard Worker // Deletes the file/directory at |path| (recursively if |recursive| and |path|
314*6777b538SAndroid Build Coastguard Worker // names a directory), returning true on success. Sets the Windows last-error
315*6777b538SAndroid Build Coastguard Worker // code and returns false on failure.
DeleteFileOrSetLastError(const FilePath & path,bool recursive)316*6777b538SAndroid Build Coastguard Worker bool DeleteFileOrSetLastError(const FilePath& path, bool recursive) {
317*6777b538SAndroid Build Coastguard Worker const DWORD error = DoDeleteFile(path, recursive);
318*6777b538SAndroid Build Coastguard Worker if (error == ERROR_SUCCESS)
319*6777b538SAndroid Build Coastguard Worker return true;
320*6777b538SAndroid Build Coastguard Worker
321*6777b538SAndroid Build Coastguard Worker ::SetLastError(error);
322*6777b538SAndroid Build Coastguard Worker return false;
323*6777b538SAndroid Build Coastguard Worker }
324*6777b538SAndroid Build Coastguard Worker
325*6777b538SAndroid Build Coastguard Worker constexpr int kMaxDeleteAttempts = 9;
326*6777b538SAndroid Build Coastguard Worker
DeleteFileWithRetry(const FilePath & path,bool recursive,int attempt,OnceCallback<void (bool)> reply_callback)327*6777b538SAndroid Build Coastguard Worker void DeleteFileWithRetry(const FilePath& path,
328*6777b538SAndroid Build Coastguard Worker bool recursive,
329*6777b538SAndroid Build Coastguard Worker int attempt,
330*6777b538SAndroid Build Coastguard Worker OnceCallback<void(bool)> reply_callback) {
331*6777b538SAndroid Build Coastguard Worker // Retry every 250ms for up to two seconds. These values were pulled out of
332*6777b538SAndroid Build Coastguard Worker // thin air, and may be adjusted in the future based on the metrics collected.
333*6777b538SAndroid Build Coastguard Worker static constexpr TimeDelta kDeleteFileRetryDelay = Milliseconds(250);
334*6777b538SAndroid Build Coastguard Worker
335*6777b538SAndroid Build Coastguard Worker if (DeleteFileOrSetLastError(path, recursive)) {
336*6777b538SAndroid Build Coastguard Worker // Consider introducing further retries until the item has been removed from
337*6777b538SAndroid Build Coastguard Worker // the filesystem and its name is ready for reuse; see the comments in
338*6777b538SAndroid Build Coastguard Worker // chrome/installer/mini_installer/delete_with_retry.cc for details.
339*6777b538SAndroid Build Coastguard Worker if (!reply_callback.is_null())
340*6777b538SAndroid Build Coastguard Worker std::move(reply_callback).Run(true);
341*6777b538SAndroid Build Coastguard Worker return;
342*6777b538SAndroid Build Coastguard Worker }
343*6777b538SAndroid Build Coastguard Worker
344*6777b538SAndroid Build Coastguard Worker ++attempt;
345*6777b538SAndroid Build Coastguard Worker DCHECK_LE(attempt, kMaxDeleteAttempts);
346*6777b538SAndroid Build Coastguard Worker if (attempt == kMaxDeleteAttempts) {
347*6777b538SAndroid Build Coastguard Worker if (!reply_callback.is_null())
348*6777b538SAndroid Build Coastguard Worker std::move(reply_callback).Run(false);
349*6777b538SAndroid Build Coastguard Worker return;
350*6777b538SAndroid Build Coastguard Worker }
351*6777b538SAndroid Build Coastguard Worker
352*6777b538SAndroid Build Coastguard Worker ThreadPool::PostDelayedTask(FROM_HERE,
353*6777b538SAndroid Build Coastguard Worker {TaskPriority::BEST_EFFORT, MayBlock()},
354*6777b538SAndroid Build Coastguard Worker BindOnce(&DeleteFileWithRetry, path, recursive,
355*6777b538SAndroid Build Coastguard Worker attempt, std::move(reply_callback)),
356*6777b538SAndroid Build Coastguard Worker kDeleteFileRetryDelay);
357*6777b538SAndroid Build Coastguard Worker }
358*6777b538SAndroid Build Coastguard Worker
GetDeleteFileCallbackInternal(const FilePath & path,bool recursive,OnceCallback<void (bool)> reply_callback)359*6777b538SAndroid Build Coastguard Worker OnceClosure GetDeleteFileCallbackInternal(
360*6777b538SAndroid Build Coastguard Worker const FilePath& path,
361*6777b538SAndroid Build Coastguard Worker bool recursive,
362*6777b538SAndroid Build Coastguard Worker OnceCallback<void(bool)> reply_callback) {
363*6777b538SAndroid Build Coastguard Worker OnceCallback<void(bool)> bound_callback;
364*6777b538SAndroid Build Coastguard Worker if (!reply_callback.is_null()) {
365*6777b538SAndroid Build Coastguard Worker bound_callback = BindPostTask(SequencedTaskRunner::GetCurrentDefault(),
366*6777b538SAndroid Build Coastguard Worker std::move(reply_callback));
367*6777b538SAndroid Build Coastguard Worker }
368*6777b538SAndroid Build Coastguard Worker return BindOnce(&DeleteFileWithRetry, path, recursive, /*attempt=*/0,
369*6777b538SAndroid Build Coastguard Worker std::move(bound_callback));
370*6777b538SAndroid Build Coastguard Worker }
371*6777b538SAndroid Build Coastguard Worker
372*6777b538SAndroid Build Coastguard Worker // This function verifies that no code is attempting to set an ACL on a file
373*6777b538SAndroid Build Coastguard Worker // that is outside of 'safe' paths. A 'safe' path is defined as one that is
374*6777b538SAndroid Build Coastguard Worker // within the user data dir, or the temporary directory. This is explicitly to
375*6777b538SAndroid Build Coastguard Worker // prevent code from trying to pass a writeable handle to a file outside of
376*6777b538SAndroid Build Coastguard Worker // these directories to an untrusted process. E.g. if some future code created a
377*6777b538SAndroid Build Coastguard Worker // writeable handle to a file in c:\users\user\sensitive.dat, this DCHECK would
378*6777b538SAndroid Build Coastguard Worker // hit. Setting an ACL on a file outside of these chrome-controlled directories
379*6777b538SAndroid Build Coastguard Worker // might cause the browser or operating system to fail in unexpected ways.
IsPathSafeToSetAclOn(const FilePath & path)380*6777b538SAndroid Build Coastguard Worker bool IsPathSafeToSetAclOn(const FilePath& path) {
381*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(CLANG_PROFILING)
382*6777b538SAndroid Build Coastguard Worker // TODO(crbug.com/329482479) Use PreventExecuteMappingUnchecked for .profraw.
383*6777b538SAndroid Build Coastguard Worker // Ignore .profraw profiling files, as they can occur anywhere, and only occur
384*6777b538SAndroid Build Coastguard Worker // during testing.
385*6777b538SAndroid Build Coastguard Worker if (path.Extension() == FILE_PATH_LITERAL(".profraw")) {
386*6777b538SAndroid Build Coastguard Worker return true;
387*6777b538SAndroid Build Coastguard Worker }
388*6777b538SAndroid Build Coastguard Worker #endif // BUILDFLAG(CLANG_PROFILING)
389*6777b538SAndroid Build Coastguard Worker std::vector<int> valid_path_keys({DIR_TEMP});
390*6777b538SAndroid Build Coastguard Worker if (g_extra_allowed_path_for_no_execute) {
391*6777b538SAndroid Build Coastguard Worker valid_path_keys.push_back(g_extra_allowed_path_for_no_execute);
392*6777b538SAndroid Build Coastguard Worker }
393*6777b538SAndroid Build Coastguard Worker
394*6777b538SAndroid Build Coastguard Worker // MakeLongFilePath is needed here because temp files can have an 8.3 path
395*6777b538SAndroid Build Coastguard Worker // under certain conditions. See comments in base::MakeLongFilePath.
396*6777b538SAndroid Build Coastguard Worker FilePath long_path = MakeLongFilePath(path);
397*6777b538SAndroid Build Coastguard Worker DCHECK(!long_path.empty()) << "Cannot get long path for " << path;
398*6777b538SAndroid Build Coastguard Worker
399*6777b538SAndroid Build Coastguard Worker std::vector<FilePath> valid_paths;
400*6777b538SAndroid Build Coastguard Worker for (const auto path_key : valid_path_keys) {
401*6777b538SAndroid Build Coastguard Worker FilePath valid_path;
402*6777b538SAndroid Build Coastguard Worker if (!PathService::Get(path_key, &valid_path)) {
403*6777b538SAndroid Build Coastguard Worker DLOG(FATAL) << "Cannot get path for pathservice key " << path_key;
404*6777b538SAndroid Build Coastguard Worker continue;
405*6777b538SAndroid Build Coastguard Worker }
406*6777b538SAndroid Build Coastguard Worker valid_paths.push_back(valid_path);
407*6777b538SAndroid Build Coastguard Worker }
408*6777b538SAndroid Build Coastguard Worker
409*6777b538SAndroid Build Coastguard Worker // Admin users create temporary files in `GetSecureSystemTemp`, see
410*6777b538SAndroid Build Coastguard Worker // `CreateNewTempDirectory` below.
411*6777b538SAndroid Build Coastguard Worker FilePath secure_system_temp;
412*6777b538SAndroid Build Coastguard Worker if (::IsUserAnAdmin() && GetSecureSystemTemp(&secure_system_temp)) {
413*6777b538SAndroid Build Coastguard Worker valid_paths.push_back(secure_system_temp);
414*6777b538SAndroid Build Coastguard Worker }
415*6777b538SAndroid Build Coastguard Worker
416*6777b538SAndroid Build Coastguard Worker for (const auto& valid_path : valid_paths) {
417*6777b538SAndroid Build Coastguard Worker // Temp files can sometimes have an 8.3 path. See comments in
418*6777b538SAndroid Build Coastguard Worker // `MakeLongFilePath`.
419*6777b538SAndroid Build Coastguard Worker FilePath full_path = MakeLongFilePath(valid_path);
420*6777b538SAndroid Build Coastguard Worker DCHECK(!full_path.empty()) << "Cannot get long path for " << valid_path;
421*6777b538SAndroid Build Coastguard Worker if (full_path.IsParent(long_path)) {
422*6777b538SAndroid Build Coastguard Worker return true;
423*6777b538SAndroid Build Coastguard Worker }
424*6777b538SAndroid Build Coastguard Worker }
425*6777b538SAndroid Build Coastguard Worker
426*6777b538SAndroid Build Coastguard Worker return false;
427*6777b538SAndroid Build Coastguard Worker }
428*6777b538SAndroid Build Coastguard Worker
429*6777b538SAndroid Build Coastguard Worker } // namespace
430*6777b538SAndroid Build Coastguard Worker
GetDeleteFileCallback(const FilePath & path,OnceCallback<void (bool)> reply_callback)431*6777b538SAndroid Build Coastguard Worker OnceClosure GetDeleteFileCallback(const FilePath& path,
432*6777b538SAndroid Build Coastguard Worker OnceCallback<void(bool)> reply_callback) {
433*6777b538SAndroid Build Coastguard Worker return GetDeleteFileCallbackInternal(path, /*recursive=*/false,
434*6777b538SAndroid Build Coastguard Worker std::move(reply_callback));
435*6777b538SAndroid Build Coastguard Worker }
436*6777b538SAndroid Build Coastguard Worker
GetDeletePathRecursivelyCallback(const FilePath & path,OnceCallback<void (bool)> reply_callback)437*6777b538SAndroid Build Coastguard Worker OnceClosure GetDeletePathRecursivelyCallback(
438*6777b538SAndroid Build Coastguard Worker const FilePath& path,
439*6777b538SAndroid Build Coastguard Worker OnceCallback<void(bool)> reply_callback) {
440*6777b538SAndroid Build Coastguard Worker return GetDeleteFileCallbackInternal(path, /*recursive=*/true,
441*6777b538SAndroid Build Coastguard Worker std::move(reply_callback));
442*6777b538SAndroid Build Coastguard Worker }
443*6777b538SAndroid Build Coastguard Worker
MakeAbsoluteFilePath(const FilePath & input)444*6777b538SAndroid Build Coastguard Worker FilePath MakeAbsoluteFilePath(const FilePath& input) {
445*6777b538SAndroid Build Coastguard Worker ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
446*6777b538SAndroid Build Coastguard Worker wchar_t file_path[MAX_PATH];
447*6777b538SAndroid Build Coastguard Worker if (!_wfullpath(file_path, input.value().c_str(), MAX_PATH))
448*6777b538SAndroid Build Coastguard Worker return FilePath();
449*6777b538SAndroid Build Coastguard Worker return FilePath(file_path);
450*6777b538SAndroid Build Coastguard Worker }
451*6777b538SAndroid Build Coastguard Worker
DeleteFile(const FilePath & path)452*6777b538SAndroid Build Coastguard Worker bool DeleteFile(const FilePath& path) {
453*6777b538SAndroid Build Coastguard Worker return DeleteFileOrSetLastError(path, /*recursive=*/false);
454*6777b538SAndroid Build Coastguard Worker }
455*6777b538SAndroid Build Coastguard Worker
DeletePathRecursively(const FilePath & path)456*6777b538SAndroid Build Coastguard Worker bool DeletePathRecursively(const FilePath& path) {
457*6777b538SAndroid Build Coastguard Worker return DeleteFileOrSetLastError(path, /*recursive=*/true);
458*6777b538SAndroid Build Coastguard Worker }
459*6777b538SAndroid Build Coastguard Worker
DeleteFileAfterReboot(const FilePath & path)460*6777b538SAndroid Build Coastguard Worker bool DeleteFileAfterReboot(const FilePath& path) {
461*6777b538SAndroid Build Coastguard Worker ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
462*6777b538SAndroid Build Coastguard Worker
463*6777b538SAndroid Build Coastguard Worker if (path.value().length() >= MAX_PATH)
464*6777b538SAndroid Build Coastguard Worker return false;
465*6777b538SAndroid Build Coastguard Worker
466*6777b538SAndroid Build Coastguard Worker return ::MoveFileEx(path.value().c_str(), nullptr,
467*6777b538SAndroid Build Coastguard Worker MOVEFILE_DELAY_UNTIL_REBOOT);
468*6777b538SAndroid Build Coastguard Worker }
469*6777b538SAndroid Build Coastguard Worker
ReplaceFile(const FilePath & from_path,const FilePath & to_path,File::Error * error)470*6777b538SAndroid Build Coastguard Worker bool ReplaceFile(const FilePath& from_path,
471*6777b538SAndroid Build Coastguard Worker const FilePath& to_path,
472*6777b538SAndroid Build Coastguard Worker File::Error* error) {
473*6777b538SAndroid Build Coastguard Worker ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
474*6777b538SAndroid Build Coastguard Worker
475*6777b538SAndroid Build Coastguard Worker // Alias paths for investigation of shutdown hangs. crbug.com/1054164
476*6777b538SAndroid Build Coastguard Worker FilePath::CharType from_path_str[MAX_PATH];
477*6777b538SAndroid Build Coastguard Worker base::wcslcpy(from_path_str, from_path.value().c_str(),
478*6777b538SAndroid Build Coastguard Worker std::size(from_path_str));
479*6777b538SAndroid Build Coastguard Worker base::debug::Alias(from_path_str);
480*6777b538SAndroid Build Coastguard Worker FilePath::CharType to_path_str[MAX_PATH];
481*6777b538SAndroid Build Coastguard Worker base::wcslcpy(to_path_str, to_path.value().c_str(), std::size(to_path_str));
482*6777b538SAndroid Build Coastguard Worker base::debug::Alias(to_path_str);
483*6777b538SAndroid Build Coastguard Worker
484*6777b538SAndroid Build Coastguard Worker // Assume that |to_path| already exists and try the normal replace. This will
485*6777b538SAndroid Build Coastguard Worker // fail with ERROR_FILE_NOT_FOUND if |to_path| does not exist. When writing to
486*6777b538SAndroid Build Coastguard Worker // a network share, we may not be able to change the ACLs. Ignore ACL errors
487*6777b538SAndroid Build Coastguard Worker // then (REPLACEFILE_IGNORE_MERGE_ERRORS).
488*6777b538SAndroid Build Coastguard Worker if (::ReplaceFile(to_path.value().c_str(), from_path.value().c_str(), NULL,
489*6777b538SAndroid Build Coastguard Worker REPLACEFILE_IGNORE_MERGE_ERRORS, NULL, NULL)) {
490*6777b538SAndroid Build Coastguard Worker return true;
491*6777b538SAndroid Build Coastguard Worker }
492*6777b538SAndroid Build Coastguard Worker
493*6777b538SAndroid Build Coastguard Worker File::Error replace_error = File::OSErrorToFileError(GetLastError());
494*6777b538SAndroid Build Coastguard Worker
495*6777b538SAndroid Build Coastguard Worker // Try a simple move next. It will only succeed when |to_path| doesn't already
496*6777b538SAndroid Build Coastguard Worker // exist.
497*6777b538SAndroid Build Coastguard Worker if (::MoveFile(from_path.value().c_str(), to_path.value().c_str()))
498*6777b538SAndroid Build Coastguard Worker return true;
499*6777b538SAndroid Build Coastguard Worker
500*6777b538SAndroid Build Coastguard Worker // In the case of FILE_ERROR_NOT_FOUND from ReplaceFile, it is likely that
501*6777b538SAndroid Build Coastguard Worker // |to_path| does not exist. In this case, the more relevant error comes
502*6777b538SAndroid Build Coastguard Worker // from the call to MoveFile.
503*6777b538SAndroid Build Coastguard Worker if (error) {
504*6777b538SAndroid Build Coastguard Worker *error = replace_error == File::FILE_ERROR_NOT_FOUND
505*6777b538SAndroid Build Coastguard Worker ? File::GetLastFileError()
506*6777b538SAndroid Build Coastguard Worker : replace_error;
507*6777b538SAndroid Build Coastguard Worker }
508*6777b538SAndroid Build Coastguard Worker return false;
509*6777b538SAndroid Build Coastguard Worker }
510*6777b538SAndroid Build Coastguard Worker
CopyDirectory(const FilePath & from_path,const FilePath & to_path,bool recursive)511*6777b538SAndroid Build Coastguard Worker bool CopyDirectory(const FilePath& from_path,
512*6777b538SAndroid Build Coastguard Worker const FilePath& to_path,
513*6777b538SAndroid Build Coastguard Worker bool recursive) {
514*6777b538SAndroid Build Coastguard Worker return DoCopyDirectory(from_path, to_path, recursive, false);
515*6777b538SAndroid Build Coastguard Worker }
516*6777b538SAndroid Build Coastguard Worker
CopyDirectoryExcl(const FilePath & from_path,const FilePath & to_path,bool recursive)517*6777b538SAndroid Build Coastguard Worker bool CopyDirectoryExcl(const FilePath& from_path,
518*6777b538SAndroid Build Coastguard Worker const FilePath& to_path,
519*6777b538SAndroid Build Coastguard Worker bool recursive) {
520*6777b538SAndroid Build Coastguard Worker return DoCopyDirectory(from_path, to_path, recursive, true);
521*6777b538SAndroid Build Coastguard Worker }
522*6777b538SAndroid Build Coastguard Worker
PathExists(const FilePath & path)523*6777b538SAndroid Build Coastguard Worker bool PathExists(const FilePath& path) {
524*6777b538SAndroid Build Coastguard Worker ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
525*6777b538SAndroid Build Coastguard Worker return (GetFileAttributes(path.value().c_str()) != INVALID_FILE_ATTRIBUTES);
526*6777b538SAndroid Build Coastguard Worker }
527*6777b538SAndroid Build Coastguard Worker
528*6777b538SAndroid Build Coastguard Worker namespace {
529*6777b538SAndroid Build Coastguard Worker
PathHasAccess(const FilePath & path,DWORD dir_desired_access,DWORD file_desired_access)530*6777b538SAndroid Build Coastguard Worker bool PathHasAccess(const FilePath& path,
531*6777b538SAndroid Build Coastguard Worker DWORD dir_desired_access,
532*6777b538SAndroid Build Coastguard Worker DWORD file_desired_access) {
533*6777b538SAndroid Build Coastguard Worker ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
534*6777b538SAndroid Build Coastguard Worker
535*6777b538SAndroid Build Coastguard Worker const wchar_t* const path_str = path.value().c_str();
536*6777b538SAndroid Build Coastguard Worker DWORD fileattr = GetFileAttributes(path_str);
537*6777b538SAndroid Build Coastguard Worker if (fileattr == INVALID_FILE_ATTRIBUTES)
538*6777b538SAndroid Build Coastguard Worker return false;
539*6777b538SAndroid Build Coastguard Worker
540*6777b538SAndroid Build Coastguard Worker bool is_directory = fileattr & FILE_ATTRIBUTE_DIRECTORY;
541*6777b538SAndroid Build Coastguard Worker DWORD desired_access =
542*6777b538SAndroid Build Coastguard Worker is_directory ? dir_desired_access : file_desired_access;
543*6777b538SAndroid Build Coastguard Worker DWORD flags_and_attrs =
544*6777b538SAndroid Build Coastguard Worker is_directory ? FILE_FLAG_BACKUP_SEMANTICS : FILE_ATTRIBUTE_NORMAL;
545*6777b538SAndroid Build Coastguard Worker
546*6777b538SAndroid Build Coastguard Worker win::ScopedHandle file(CreateFile(path_str, desired_access, kFileShareAll,
547*6777b538SAndroid Build Coastguard Worker nullptr, OPEN_EXISTING, flags_and_attrs,
548*6777b538SAndroid Build Coastguard Worker nullptr));
549*6777b538SAndroid Build Coastguard Worker
550*6777b538SAndroid Build Coastguard Worker return file.is_valid();
551*6777b538SAndroid Build Coastguard Worker }
552*6777b538SAndroid Build Coastguard Worker
553*6777b538SAndroid Build Coastguard Worker } // namespace
554*6777b538SAndroid Build Coastguard Worker
PathIsReadable(const FilePath & path)555*6777b538SAndroid Build Coastguard Worker bool PathIsReadable(const FilePath& path) {
556*6777b538SAndroid Build Coastguard Worker return PathHasAccess(path, FILE_LIST_DIRECTORY, GENERIC_READ);
557*6777b538SAndroid Build Coastguard Worker }
558*6777b538SAndroid Build Coastguard Worker
PathIsWritable(const FilePath & path)559*6777b538SAndroid Build Coastguard Worker bool PathIsWritable(const FilePath& path) {
560*6777b538SAndroid Build Coastguard Worker return PathHasAccess(path, FILE_ADD_FILE, GENERIC_WRITE);
561*6777b538SAndroid Build Coastguard Worker }
562*6777b538SAndroid Build Coastguard Worker
DirectoryExists(const FilePath & path)563*6777b538SAndroid Build Coastguard Worker bool DirectoryExists(const FilePath& path) {
564*6777b538SAndroid Build Coastguard Worker ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
565*6777b538SAndroid Build Coastguard Worker DWORD fileattr = GetFileAttributes(path.value().c_str());
566*6777b538SAndroid Build Coastguard Worker if (fileattr != INVALID_FILE_ATTRIBUTES)
567*6777b538SAndroid Build Coastguard Worker return (fileattr & FILE_ATTRIBUTE_DIRECTORY) != 0;
568*6777b538SAndroid Build Coastguard Worker return false;
569*6777b538SAndroid Build Coastguard Worker }
570*6777b538SAndroid Build Coastguard Worker
GetTempDir(FilePath * path)571*6777b538SAndroid Build Coastguard Worker bool GetTempDir(FilePath* path) {
572*6777b538SAndroid Build Coastguard Worker wchar_t temp_path[MAX_PATH + 1];
573*6777b538SAndroid Build Coastguard Worker DWORD path_len = ::GetTempPath(MAX_PATH, temp_path);
574*6777b538SAndroid Build Coastguard Worker if (path_len >= MAX_PATH || path_len <= 0)
575*6777b538SAndroid Build Coastguard Worker return false;
576*6777b538SAndroid Build Coastguard Worker // TODO(evanm): the old behavior of this function was to always strip the
577*6777b538SAndroid Build Coastguard Worker // trailing slash. We duplicate this here, but it shouldn't be necessary
578*6777b538SAndroid Build Coastguard Worker // when everyone is using the appropriate FilePath APIs.
579*6777b538SAndroid Build Coastguard Worker *path = FilePath(temp_path).StripTrailingSeparators();
580*6777b538SAndroid Build Coastguard Worker return true;
581*6777b538SAndroid Build Coastguard Worker }
582*6777b538SAndroid Build Coastguard Worker
GetHomeDir()583*6777b538SAndroid Build Coastguard Worker FilePath GetHomeDir() {
584*6777b538SAndroid Build Coastguard Worker wchar_t result[MAX_PATH];
585*6777b538SAndroid Build Coastguard Worker if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_PROFILE, NULL, SHGFP_TYPE_CURRENT,
586*6777b538SAndroid Build Coastguard Worker result)) &&
587*6777b538SAndroid Build Coastguard Worker result[0]) {
588*6777b538SAndroid Build Coastguard Worker return FilePath(result);
589*6777b538SAndroid Build Coastguard Worker }
590*6777b538SAndroid Build Coastguard Worker
591*6777b538SAndroid Build Coastguard Worker // Fall back to the temporary directory on failure.
592*6777b538SAndroid Build Coastguard Worker FilePath temp;
593*6777b538SAndroid Build Coastguard Worker if (GetTempDir(&temp))
594*6777b538SAndroid Build Coastguard Worker return temp;
595*6777b538SAndroid Build Coastguard Worker
596*6777b538SAndroid Build Coastguard Worker // Last resort.
597*6777b538SAndroid Build Coastguard Worker return FilePath(FILE_PATH_LITERAL("C:\\"));
598*6777b538SAndroid Build Coastguard Worker }
599*6777b538SAndroid Build Coastguard Worker
CreateAndOpenTemporaryFileInDir(const FilePath & dir,FilePath * temp_file)600*6777b538SAndroid Build Coastguard Worker File CreateAndOpenTemporaryFileInDir(const FilePath& dir, FilePath* temp_file) {
601*6777b538SAndroid Build Coastguard Worker ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
602*6777b538SAndroid Build Coastguard Worker
603*6777b538SAndroid Build Coastguard Worker // Open the file with exclusive r/w/d access, and allow the caller to decide
604*6777b538SAndroid Build Coastguard Worker // to mark it for deletion upon close after the fact.
605*6777b538SAndroid Build Coastguard Worker constexpr uint32_t kFlags = File::FLAG_CREATE | File::FLAG_READ |
606*6777b538SAndroid Build Coastguard Worker File::FLAG_WRITE | File::FLAG_WIN_EXCLUSIVE_READ |
607*6777b538SAndroid Build Coastguard Worker File::FLAG_WIN_EXCLUSIVE_WRITE |
608*6777b538SAndroid Build Coastguard Worker File::FLAG_CAN_DELETE_ON_CLOSE;
609*6777b538SAndroid Build Coastguard Worker
610*6777b538SAndroid Build Coastguard Worker // Use GUID instead of ::GetTempFileName() to generate unique file names.
611*6777b538SAndroid Build Coastguard Worker // "Due to the algorithm used to generate file names, GetTempFileName can
612*6777b538SAndroid Build Coastguard Worker // perform poorly when creating a large number of files with the same prefix.
613*6777b538SAndroid Build Coastguard Worker // In such cases, it is recommended that you construct unique file names based
614*6777b538SAndroid Build Coastguard Worker // on GUIDs."
615*6777b538SAndroid Build Coastguard Worker // https://msdn.microsoft.com/library/windows/desktop/aa364991.aspx
616*6777b538SAndroid Build Coastguard Worker
617*6777b538SAndroid Build Coastguard Worker FilePath temp_name;
618*6777b538SAndroid Build Coastguard Worker File file;
619*6777b538SAndroid Build Coastguard Worker
620*6777b538SAndroid Build Coastguard Worker // Although it is nearly impossible to get a duplicate name with GUID, we
621*6777b538SAndroid Build Coastguard Worker // still use a loop here in case it happens.
622*6777b538SAndroid Build Coastguard Worker for (int i = 0; i < 100; ++i) {
623*6777b538SAndroid Build Coastguard Worker temp_name = dir.Append(FormatTemporaryFileName(
624*6777b538SAndroid Build Coastguard Worker UTF8ToWide(Uuid::GenerateRandomV4().AsLowercaseString())));
625*6777b538SAndroid Build Coastguard Worker file.Initialize(temp_name, kFlags);
626*6777b538SAndroid Build Coastguard Worker if (file.IsValid())
627*6777b538SAndroid Build Coastguard Worker break;
628*6777b538SAndroid Build Coastguard Worker }
629*6777b538SAndroid Build Coastguard Worker
630*6777b538SAndroid Build Coastguard Worker if (!file.IsValid()) {
631*6777b538SAndroid Build Coastguard Worker DPLOG(WARNING) << "Failed to get temporary file name in " << dir.value();
632*6777b538SAndroid Build Coastguard Worker return file;
633*6777b538SAndroid Build Coastguard Worker }
634*6777b538SAndroid Build Coastguard Worker
635*6777b538SAndroid Build Coastguard Worker wchar_t long_temp_name[MAX_PATH + 1];
636*6777b538SAndroid Build Coastguard Worker const DWORD long_name_len =
637*6777b538SAndroid Build Coastguard Worker GetLongPathName(temp_name.value().c_str(), long_temp_name, MAX_PATH);
638*6777b538SAndroid Build Coastguard Worker if (long_name_len != 0 && long_name_len <= MAX_PATH) {
639*6777b538SAndroid Build Coastguard Worker *temp_file =
640*6777b538SAndroid Build Coastguard Worker FilePath(FilePath::StringPieceType(long_temp_name, long_name_len));
641*6777b538SAndroid Build Coastguard Worker } else {
642*6777b538SAndroid Build Coastguard Worker // GetLongPathName() failed, but we still have a temporary file.
643*6777b538SAndroid Build Coastguard Worker *temp_file = std::move(temp_name);
644*6777b538SAndroid Build Coastguard Worker }
645*6777b538SAndroid Build Coastguard Worker
646*6777b538SAndroid Build Coastguard Worker return file;
647*6777b538SAndroid Build Coastguard Worker }
648*6777b538SAndroid Build Coastguard Worker
CreateTemporaryFileInDir(const FilePath & dir,FilePath * temp_file)649*6777b538SAndroid Build Coastguard Worker bool CreateTemporaryFileInDir(const FilePath& dir, FilePath* temp_file) {
650*6777b538SAndroid Build Coastguard Worker return CreateAndOpenTemporaryFileInDir(dir, temp_file).IsValid();
651*6777b538SAndroid Build Coastguard Worker }
652*6777b538SAndroid Build Coastguard Worker
FormatTemporaryFileName(FilePath::StringPieceType identifier)653*6777b538SAndroid Build Coastguard Worker FilePath FormatTemporaryFileName(FilePath::StringPieceType identifier) {
654*6777b538SAndroid Build Coastguard Worker return FilePath(StrCat({identifier, FILE_PATH_LITERAL(".tmp")}));
655*6777b538SAndroid Build Coastguard Worker }
656*6777b538SAndroid Build Coastguard Worker
CreateAndOpenTemporaryStreamInDir(const FilePath & dir,FilePath * path)657*6777b538SAndroid Build Coastguard Worker ScopedFILE CreateAndOpenTemporaryStreamInDir(const FilePath& dir,
658*6777b538SAndroid Build Coastguard Worker FilePath* path) {
659*6777b538SAndroid Build Coastguard Worker // Open file in binary mode, to avoid problems with fwrite. On Windows
660*6777b538SAndroid Build Coastguard Worker // it replaces \n's with \r\n's, which may surprise you.
661*6777b538SAndroid Build Coastguard Worker // Reference: http://msdn.microsoft.com/en-us/library/h9t88zwz(VS.71).aspx
662*6777b538SAndroid Build Coastguard Worker return ScopedFILE(
663*6777b538SAndroid Build Coastguard Worker FileToFILE(CreateAndOpenTemporaryFileInDir(dir, path), "wb+"));
664*6777b538SAndroid Build Coastguard Worker }
665*6777b538SAndroid Build Coastguard Worker
CreateTemporaryDirInDir(const FilePath & base_dir,const FilePath::StringType & prefix,FilePath * new_dir)666*6777b538SAndroid Build Coastguard Worker bool CreateTemporaryDirInDir(const FilePath& base_dir,
667*6777b538SAndroid Build Coastguard Worker const FilePath::StringType& prefix,
668*6777b538SAndroid Build Coastguard Worker FilePath* new_dir) {
669*6777b538SAndroid Build Coastguard Worker ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
670*6777b538SAndroid Build Coastguard Worker
671*6777b538SAndroid Build Coastguard Worker FilePath path_to_create;
672*6777b538SAndroid Build Coastguard Worker
673*6777b538SAndroid Build Coastguard Worker for (int count = 0; count < 50; ++count) {
674*6777b538SAndroid Build Coastguard Worker // Try create a new temporary directory with random generated name. If
675*6777b538SAndroid Build Coastguard Worker // the one exists, keep trying another path name until we reach some limit.
676*6777b538SAndroid Build Coastguard Worker std::wstring new_dir_name;
677*6777b538SAndroid Build Coastguard Worker new_dir_name.assign(prefix);
678*6777b538SAndroid Build Coastguard Worker new_dir_name.append(AsWString(NumberToString16(GetCurrentProcId())));
679*6777b538SAndroid Build Coastguard Worker new_dir_name.push_back('_');
680*6777b538SAndroid Build Coastguard Worker new_dir_name.append(AsWString(
681*6777b538SAndroid Build Coastguard Worker NumberToString16(RandInt(0, std::numeric_limits<int32_t>::max()))));
682*6777b538SAndroid Build Coastguard Worker
683*6777b538SAndroid Build Coastguard Worker path_to_create = base_dir.Append(new_dir_name);
684*6777b538SAndroid Build Coastguard Worker if (::CreateDirectory(path_to_create.value().c_str(), NULL)) {
685*6777b538SAndroid Build Coastguard Worker *new_dir = path_to_create;
686*6777b538SAndroid Build Coastguard Worker return true;
687*6777b538SAndroid Build Coastguard Worker }
688*6777b538SAndroid Build Coastguard Worker }
689*6777b538SAndroid Build Coastguard Worker
690*6777b538SAndroid Build Coastguard Worker return false;
691*6777b538SAndroid Build Coastguard Worker }
692*6777b538SAndroid Build Coastguard Worker
GetSecureSystemTemp(FilePath * temp)693*6777b538SAndroid Build Coastguard Worker bool GetSecureSystemTemp(FilePath* temp) {
694*6777b538SAndroid Build Coastguard Worker if (g_disable_secure_system_temp_for_testing) {
695*6777b538SAndroid Build Coastguard Worker return false;
696*6777b538SAndroid Build Coastguard Worker }
697*6777b538SAndroid Build Coastguard Worker
698*6777b538SAndroid Build Coastguard Worker ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
699*6777b538SAndroid Build Coastguard Worker
700*6777b538SAndroid Build Coastguard Worker CHECK(temp);
701*6777b538SAndroid Build Coastguard Worker
702*6777b538SAndroid Build Coastguard Worker for (const auto key : {DIR_WINDOWS, DIR_PROGRAM_FILES}) {
703*6777b538SAndroid Build Coastguard Worker FilePath secure_system_temp;
704*6777b538SAndroid Build Coastguard Worker if (!PathService::Get(key, &secure_system_temp)) {
705*6777b538SAndroid Build Coastguard Worker continue;
706*6777b538SAndroid Build Coastguard Worker }
707*6777b538SAndroid Build Coastguard Worker
708*6777b538SAndroid Build Coastguard Worker if (key == DIR_WINDOWS) {
709*6777b538SAndroid Build Coastguard Worker secure_system_temp = secure_system_temp.AppendASCII("SystemTemp");
710*6777b538SAndroid Build Coastguard Worker }
711*6777b538SAndroid Build Coastguard Worker
712*6777b538SAndroid Build Coastguard Worker if (PathExists(secure_system_temp) && PathIsWritable(secure_system_temp)) {
713*6777b538SAndroid Build Coastguard Worker *temp = secure_system_temp;
714*6777b538SAndroid Build Coastguard Worker return true;
715*6777b538SAndroid Build Coastguard Worker }
716*6777b538SAndroid Build Coastguard Worker }
717*6777b538SAndroid Build Coastguard Worker
718*6777b538SAndroid Build Coastguard Worker return false;
719*6777b538SAndroid Build Coastguard Worker }
720*6777b538SAndroid Build Coastguard Worker
SetDisableSecureSystemTempForTesting(bool disabled)721*6777b538SAndroid Build Coastguard Worker void SetDisableSecureSystemTempForTesting(bool disabled) {
722*6777b538SAndroid Build Coastguard Worker g_disable_secure_system_temp_for_testing = disabled;
723*6777b538SAndroid Build Coastguard Worker }
724*6777b538SAndroid Build Coastguard Worker
725*6777b538SAndroid Build Coastguard Worker // The directory is created under `GetSecureSystemTemp` for security reasons if
726*6777b538SAndroid Build Coastguard Worker // the caller is admin to avoid attacks from lower privilege processes.
727*6777b538SAndroid Build Coastguard Worker //
728*6777b538SAndroid Build Coastguard Worker // If unable to create a dir under `GetSecureSystemTemp`, the dir is created
729*6777b538SAndroid Build Coastguard Worker // under %TEMP%. The reasons for not being able to create a dir under
730*6777b538SAndroid Build Coastguard Worker // `GetSecureSystemTemp` could be because `%systemroot%\SystemTemp` does not
731*6777b538SAndroid Build Coastguard Worker // exist, or unable to resolve `DIR_WINDOWS` or `DIR_PROGRAM_FILES`, say due to
732*6777b538SAndroid Build Coastguard Worker // registry redirection, or unable to create a directory due to
733*6777b538SAndroid Build Coastguard Worker // `GetSecureSystemTemp` being read-only or having atypical ACLs. Tests can also
734*6777b538SAndroid Build Coastguard Worker // disable this behavior resulting in false being returned.
CreateNewTempDirectory(const FilePath::StringType & prefix,FilePath * new_temp_path)735*6777b538SAndroid Build Coastguard Worker bool CreateNewTempDirectory(const FilePath::StringType& prefix,
736*6777b538SAndroid Build Coastguard Worker FilePath* new_temp_path) {
737*6777b538SAndroid Build Coastguard Worker ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
738*6777b538SAndroid Build Coastguard Worker
739*6777b538SAndroid Build Coastguard Worker DCHECK(new_temp_path);
740*6777b538SAndroid Build Coastguard Worker
741*6777b538SAndroid Build Coastguard Worker FilePath parent_dir;
742*6777b538SAndroid Build Coastguard Worker if (::IsUserAnAdmin() && GetSecureSystemTemp(&parent_dir) &&
743*6777b538SAndroid Build Coastguard Worker CreateTemporaryDirInDir(parent_dir,
744*6777b538SAndroid Build Coastguard Worker prefix.empty() ? kDefaultTempDirPrefix : prefix,
745*6777b538SAndroid Build Coastguard Worker new_temp_path)) {
746*6777b538SAndroid Build Coastguard Worker return true;
747*6777b538SAndroid Build Coastguard Worker }
748*6777b538SAndroid Build Coastguard Worker
749*6777b538SAndroid Build Coastguard Worker if (!GetTempDir(&parent_dir))
750*6777b538SAndroid Build Coastguard Worker return false;
751*6777b538SAndroid Build Coastguard Worker
752*6777b538SAndroid Build Coastguard Worker return CreateTemporaryDirInDir(parent_dir, prefix, new_temp_path);
753*6777b538SAndroid Build Coastguard Worker }
754*6777b538SAndroid Build Coastguard Worker
CreateDirectoryAndGetError(const FilePath & full_path,File::Error * error)755*6777b538SAndroid Build Coastguard Worker bool CreateDirectoryAndGetError(const FilePath& full_path,
756*6777b538SAndroid Build Coastguard Worker File::Error* error) {
757*6777b538SAndroid Build Coastguard Worker ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
758*6777b538SAndroid Build Coastguard Worker
759*6777b538SAndroid Build Coastguard Worker // If the path exists, we've succeeded if it's a directory, failed otherwise.
760*6777b538SAndroid Build Coastguard Worker const wchar_t* const full_path_str = full_path.value().c_str();
761*6777b538SAndroid Build Coastguard Worker const DWORD fileattr = ::GetFileAttributes(full_path_str);
762*6777b538SAndroid Build Coastguard Worker if (fileattr != INVALID_FILE_ATTRIBUTES) {
763*6777b538SAndroid Build Coastguard Worker if ((fileattr & FILE_ATTRIBUTE_DIRECTORY) != 0) {
764*6777b538SAndroid Build Coastguard Worker return true;
765*6777b538SAndroid Build Coastguard Worker }
766*6777b538SAndroid Build Coastguard Worker DLOG(WARNING) << "CreateDirectory(" << full_path_str << "), "
767*6777b538SAndroid Build Coastguard Worker << "conflicts with existing file.";
768*6777b538SAndroid Build Coastguard Worker if (error)
769*6777b538SAndroid Build Coastguard Worker *error = File::FILE_ERROR_NOT_A_DIRECTORY;
770*6777b538SAndroid Build Coastguard Worker ::SetLastError(ERROR_FILE_EXISTS);
771*6777b538SAndroid Build Coastguard Worker return false;
772*6777b538SAndroid Build Coastguard Worker }
773*6777b538SAndroid Build Coastguard Worker
774*6777b538SAndroid Build Coastguard Worker // Invariant: Path does not exist as file or directory.
775*6777b538SAndroid Build Coastguard Worker
776*6777b538SAndroid Build Coastguard Worker // Attempt to create the parent recursively. This will immediately return
777*6777b538SAndroid Build Coastguard Worker // true if it already exists, otherwise will create all required parent
778*6777b538SAndroid Build Coastguard Worker // directories starting with the highest-level missing parent.
779*6777b538SAndroid Build Coastguard Worker FilePath parent_path(full_path.DirName());
780*6777b538SAndroid Build Coastguard Worker if (parent_path.value() == full_path.value()) {
781*6777b538SAndroid Build Coastguard Worker if (error)
782*6777b538SAndroid Build Coastguard Worker *error = File::FILE_ERROR_NOT_FOUND;
783*6777b538SAndroid Build Coastguard Worker ::SetLastError(ERROR_FILE_NOT_FOUND);
784*6777b538SAndroid Build Coastguard Worker return false;
785*6777b538SAndroid Build Coastguard Worker }
786*6777b538SAndroid Build Coastguard Worker if (!CreateDirectoryAndGetError(parent_path, error)) {
787*6777b538SAndroid Build Coastguard Worker DLOG(WARNING) << "Failed to create one of the parent directories.";
788*6777b538SAndroid Build Coastguard Worker DCHECK(!error || *error != File::FILE_OK);
789*6777b538SAndroid Build Coastguard Worker return false;
790*6777b538SAndroid Build Coastguard Worker }
791*6777b538SAndroid Build Coastguard Worker
792*6777b538SAndroid Build Coastguard Worker if (::CreateDirectory(full_path_str, NULL))
793*6777b538SAndroid Build Coastguard Worker return true;
794*6777b538SAndroid Build Coastguard Worker
795*6777b538SAndroid Build Coastguard Worker const DWORD error_code = ::GetLastError();
796*6777b538SAndroid Build Coastguard Worker if (error_code == ERROR_ALREADY_EXISTS && DirectoryExists(full_path)) {
797*6777b538SAndroid Build Coastguard Worker // This error code ERROR_ALREADY_EXISTS doesn't indicate whether we were
798*6777b538SAndroid Build Coastguard Worker // racing with someone creating the same directory, or a file with the same
799*6777b538SAndroid Build Coastguard Worker // path. If DirectoryExists() returns true, we lost the race to create the
800*6777b538SAndroid Build Coastguard Worker // same directory.
801*6777b538SAndroid Build Coastguard Worker return true;
802*6777b538SAndroid Build Coastguard Worker }
803*6777b538SAndroid Build Coastguard Worker if (error)
804*6777b538SAndroid Build Coastguard Worker *error = File::OSErrorToFileError(error_code);
805*6777b538SAndroid Build Coastguard Worker ::SetLastError(error_code);
806*6777b538SAndroid Build Coastguard Worker DPLOG(WARNING) << "Failed to create directory " << full_path_str;
807*6777b538SAndroid Build Coastguard Worker return false;
808*6777b538SAndroid Build Coastguard Worker }
809*6777b538SAndroid Build Coastguard Worker
NormalizeFilePath(const FilePath & path,FilePath * real_path)810*6777b538SAndroid Build Coastguard Worker bool NormalizeFilePath(const FilePath& path, FilePath* real_path) {
811*6777b538SAndroid Build Coastguard Worker ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
812*6777b538SAndroid Build Coastguard Worker File file(path,
813*6777b538SAndroid Build Coastguard Worker File::FLAG_OPEN | File::FLAG_READ | File::FLAG_WIN_SHARE_DELETE);
814*6777b538SAndroid Build Coastguard Worker if (!file.IsValid())
815*6777b538SAndroid Build Coastguard Worker return false;
816*6777b538SAndroid Build Coastguard Worker
817*6777b538SAndroid Build Coastguard Worker // The expansion of |path| into a full path may make it longer.
818*6777b538SAndroid Build Coastguard Worker constexpr int kMaxPathLength = MAX_PATH + 10;
819*6777b538SAndroid Build Coastguard Worker wchar_t native_file_path[kMaxPathLength];
820*6777b538SAndroid Build Coastguard Worker // On success, `used_wchars` returns the number of written characters, not
821*6777b538SAndroid Build Coastguard Worker // include the trailing '\0'. Thus, failure is indicated by returning 0 or >=
822*6777b538SAndroid Build Coastguard Worker // kMaxPathLength.
823*6777b538SAndroid Build Coastguard Worker DWORD used_wchars = ::GetFinalPathNameByHandle(
824*6777b538SAndroid Build Coastguard Worker file.GetPlatformFile(), native_file_path, kMaxPathLength,
825*6777b538SAndroid Build Coastguard Worker FILE_NAME_NORMALIZED | VOLUME_NAME_NT);
826*6777b538SAndroid Build Coastguard Worker
827*6777b538SAndroid Build Coastguard Worker if (used_wchars >= kMaxPathLength || used_wchars == 0)
828*6777b538SAndroid Build Coastguard Worker return false;
829*6777b538SAndroid Build Coastguard Worker
830*6777b538SAndroid Build Coastguard Worker // GetFinalPathNameByHandle() returns the \\?\ syntax for file names and
831*6777b538SAndroid Build Coastguard Worker // existing code expects we return a path starting 'X:\' so we call
832*6777b538SAndroid Build Coastguard Worker // DevicePathToDriveLetterPath rather than using VOLUME_NAME_DOS above.
833*6777b538SAndroid Build Coastguard Worker return DevicePathToDriveLetterPath(
834*6777b538SAndroid Build Coastguard Worker FilePath(FilePath::StringPieceType(native_file_path, used_wchars)),
835*6777b538SAndroid Build Coastguard Worker real_path);
836*6777b538SAndroid Build Coastguard Worker }
837*6777b538SAndroid Build Coastguard Worker
DevicePathToDriveLetterPath(const FilePath & nt_device_path,FilePath * out_drive_letter_path)838*6777b538SAndroid Build Coastguard Worker bool DevicePathToDriveLetterPath(const FilePath& nt_device_path,
839*6777b538SAndroid Build Coastguard Worker FilePath* out_drive_letter_path) {
840*6777b538SAndroid Build Coastguard Worker ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
841*6777b538SAndroid Build Coastguard Worker
842*6777b538SAndroid Build Coastguard Worker // Get the mapping of drive letters to device paths.
843*6777b538SAndroid Build Coastguard Worker const int kDriveMappingSize = 1024;
844*6777b538SAndroid Build Coastguard Worker wchar_t drive_mapping[kDriveMappingSize] = {'\0'};
845*6777b538SAndroid Build Coastguard Worker if (!::GetLogicalDriveStrings(kDriveMappingSize - 1, drive_mapping)) {
846*6777b538SAndroid Build Coastguard Worker DLOG(ERROR) << "Failed to get drive mapping.";
847*6777b538SAndroid Build Coastguard Worker return false;
848*6777b538SAndroid Build Coastguard Worker }
849*6777b538SAndroid Build Coastguard Worker
850*6777b538SAndroid Build Coastguard Worker // The drive mapping is a sequence of null terminated strings.
851*6777b538SAndroid Build Coastguard Worker // The last string is empty.
852*6777b538SAndroid Build Coastguard Worker wchar_t* drive_map_ptr = drive_mapping;
853*6777b538SAndroid Build Coastguard Worker wchar_t device_path_as_string[MAX_PATH];
854*6777b538SAndroid Build Coastguard Worker wchar_t drive[] = FILE_PATH_LITERAL(" :");
855*6777b538SAndroid Build Coastguard Worker
856*6777b538SAndroid Build Coastguard Worker // For each string in the drive mapping, get the junction that links
857*6777b538SAndroid Build Coastguard Worker // to it. If that junction is a prefix of |device_path|, then we
858*6777b538SAndroid Build Coastguard Worker // know that |drive| is the real path prefix.
859*6777b538SAndroid Build Coastguard Worker while (*drive_map_ptr) {
860*6777b538SAndroid Build Coastguard Worker drive[0] = drive_map_ptr[0]; // Copy the drive letter.
861*6777b538SAndroid Build Coastguard Worker
862*6777b538SAndroid Build Coastguard Worker if (QueryDosDevice(drive, device_path_as_string, MAX_PATH)) {
863*6777b538SAndroid Build Coastguard Worker FilePath device_path(device_path_as_string);
864*6777b538SAndroid Build Coastguard Worker if (device_path == nt_device_path ||
865*6777b538SAndroid Build Coastguard Worker device_path.IsParent(nt_device_path)) {
866*6777b538SAndroid Build Coastguard Worker *out_drive_letter_path =
867*6777b538SAndroid Build Coastguard Worker FilePath(drive + nt_device_path.value().substr(
868*6777b538SAndroid Build Coastguard Worker wcslen(device_path_as_string)));
869*6777b538SAndroid Build Coastguard Worker return true;
870*6777b538SAndroid Build Coastguard Worker }
871*6777b538SAndroid Build Coastguard Worker }
872*6777b538SAndroid Build Coastguard Worker // Move to the next drive letter string, which starts one
873*6777b538SAndroid Build Coastguard Worker // increment after the '\0' that terminates the current string.
874*6777b538SAndroid Build Coastguard Worker while (*drive_map_ptr++) {}
875*6777b538SAndroid Build Coastguard Worker }
876*6777b538SAndroid Build Coastguard Worker
877*6777b538SAndroid Build Coastguard Worker // No drive matched. The path does not start with a device junction
878*6777b538SAndroid Build Coastguard Worker // that is mounted as a drive letter. This means there is no drive
879*6777b538SAndroid Build Coastguard Worker // letter path to the volume that holds |device_path|, so fail.
880*6777b538SAndroid Build Coastguard Worker return false;
881*6777b538SAndroid Build Coastguard Worker }
882*6777b538SAndroid Build Coastguard Worker
MakeLongFilePath(const FilePath & input)883*6777b538SAndroid Build Coastguard Worker FilePath MakeLongFilePath(const FilePath& input) {
884*6777b538SAndroid Build Coastguard Worker ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
885*6777b538SAndroid Build Coastguard Worker
886*6777b538SAndroid Build Coastguard Worker DWORD path_long_len = ::GetLongPathName(input.value().c_str(), nullptr, 0);
887*6777b538SAndroid Build Coastguard Worker if (path_long_len == 0UL)
888*6777b538SAndroid Build Coastguard Worker return FilePath();
889*6777b538SAndroid Build Coastguard Worker
890*6777b538SAndroid Build Coastguard Worker std::wstring path_long_str;
891*6777b538SAndroid Build Coastguard Worker path_long_len = ::GetLongPathName(input.value().c_str(),
892*6777b538SAndroid Build Coastguard Worker WriteInto(&path_long_str, path_long_len),
893*6777b538SAndroid Build Coastguard Worker path_long_len);
894*6777b538SAndroid Build Coastguard Worker if (path_long_len == 0UL)
895*6777b538SAndroid Build Coastguard Worker return FilePath();
896*6777b538SAndroid Build Coastguard Worker
897*6777b538SAndroid Build Coastguard Worker return FilePath(path_long_str);
898*6777b538SAndroid Build Coastguard Worker }
899*6777b538SAndroid Build Coastguard Worker
CreateWinHardLink(const FilePath & to_file,const FilePath & from_file)900*6777b538SAndroid Build Coastguard Worker bool CreateWinHardLink(const FilePath& to_file, const FilePath& from_file) {
901*6777b538SAndroid Build Coastguard Worker ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
902*6777b538SAndroid Build Coastguard Worker return ::CreateHardLink(to_file.value().c_str(), from_file.value().c_str(),
903*6777b538SAndroid Build Coastguard Worker nullptr);
904*6777b538SAndroid Build Coastguard Worker }
905*6777b538SAndroid Build Coastguard Worker
IsLink(const FilePath & file_path)906*6777b538SAndroid Build Coastguard Worker bool IsLink(const FilePath& file_path) {
907*6777b538SAndroid Build Coastguard Worker ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
908*6777b538SAndroid Build Coastguard Worker
909*6777b538SAndroid Build Coastguard Worker // Opens the file or directory specified by file_path for querying attributes.
910*6777b538SAndroid Build Coastguard Worker // No access rights are requested (FILE_READ_ATTRIBUTES), as we're only
911*6777b538SAndroid Build Coastguard Worker // interested in the attributes. The file share mode allows other processes to
912*6777b538SAndroid Build Coastguard Worker // read, write, and delete the file while we have it open. The flags
913*6777b538SAndroid Build Coastguard Worker // FILE_FLAG_BACKUP_SEMANTICS and FILE_FLAG_OPEN_REPARSE_POINT are used to
914*6777b538SAndroid Build Coastguard Worker // ensure we can open directories and work with reparse points, respectively.
915*6777b538SAndroid Build Coastguard Worker //
916*6777b538SAndroid Build Coastguard Worker // NOTE: In future, we can consider using GetFileInformationByName(...)
917*6777b538SAndroid Build Coastguard Worker // instead.
918*6777b538SAndroid Build Coastguard Worker win::ScopedHandle file(
919*6777b538SAndroid Build Coastguard Worker ::CreateFile(file_path.value().c_str(), FILE_READ_ATTRIBUTES,
920*6777b538SAndroid Build Coastguard Worker FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
921*6777b538SAndroid Build Coastguard Worker /*lpSecurityAttributes=*/nullptr, OPEN_EXISTING,
922*6777b538SAndroid Build Coastguard Worker FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT,
923*6777b538SAndroid Build Coastguard Worker /*hTemplateFile=*/nullptr));
924*6777b538SAndroid Build Coastguard Worker
925*6777b538SAndroid Build Coastguard Worker if (!file.is_valid()) {
926*6777b538SAndroid Build Coastguard Worker return false;
927*6777b538SAndroid Build Coastguard Worker }
928*6777b538SAndroid Build Coastguard Worker
929*6777b538SAndroid Build Coastguard Worker FILE_ATTRIBUTE_TAG_INFO attr_taginfo;
930*6777b538SAndroid Build Coastguard Worker if (!::GetFileInformationByHandleEx(file.get(), FileAttributeTagInfo,
931*6777b538SAndroid Build Coastguard Worker &attr_taginfo, sizeof(attr_taginfo))) {
932*6777b538SAndroid Build Coastguard Worker return false;
933*6777b538SAndroid Build Coastguard Worker }
934*6777b538SAndroid Build Coastguard Worker
935*6777b538SAndroid Build Coastguard Worker return (attr_taginfo.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) &&
936*6777b538SAndroid Build Coastguard Worker (attr_taginfo.ReparseTag == IO_REPARSE_TAG_SYMLINK);
937*6777b538SAndroid Build Coastguard Worker }
938*6777b538SAndroid Build Coastguard Worker
GetFileInfo(const FilePath & file_path,File::Info * results)939*6777b538SAndroid Build Coastguard Worker bool GetFileInfo(const FilePath& file_path, File::Info* results) {
940*6777b538SAndroid Build Coastguard Worker ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
941*6777b538SAndroid Build Coastguard Worker
942*6777b538SAndroid Build Coastguard Worker WIN32_FILE_ATTRIBUTE_DATA attr;
943*6777b538SAndroid Build Coastguard Worker if (!GetFileAttributesEx(file_path.value().c_str(), GetFileExInfoStandard,
944*6777b538SAndroid Build Coastguard Worker &attr)) {
945*6777b538SAndroid Build Coastguard Worker return false;
946*6777b538SAndroid Build Coastguard Worker }
947*6777b538SAndroid Build Coastguard Worker
948*6777b538SAndroid Build Coastguard Worker ULARGE_INTEGER size;
949*6777b538SAndroid Build Coastguard Worker size.HighPart = attr.nFileSizeHigh;
950*6777b538SAndroid Build Coastguard Worker size.LowPart = attr.nFileSizeLow;
951*6777b538SAndroid Build Coastguard Worker // TODO(crbug.com/1333521): Change Info::size to uint64_t and eliminate this
952*6777b538SAndroid Build Coastguard Worker // cast.
953*6777b538SAndroid Build Coastguard Worker results->size = checked_cast<int64_t>(size.QuadPart);
954*6777b538SAndroid Build Coastguard Worker
955*6777b538SAndroid Build Coastguard Worker results->is_directory =
956*6777b538SAndroid Build Coastguard Worker (attr.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
957*6777b538SAndroid Build Coastguard Worker results->last_modified = Time::FromFileTime(attr.ftLastWriteTime);
958*6777b538SAndroid Build Coastguard Worker results->last_accessed = Time::FromFileTime(attr.ftLastAccessTime);
959*6777b538SAndroid Build Coastguard Worker results->creation_time = Time::FromFileTime(attr.ftCreationTime);
960*6777b538SAndroid Build Coastguard Worker
961*6777b538SAndroid Build Coastguard Worker return true;
962*6777b538SAndroid Build Coastguard Worker }
963*6777b538SAndroid Build Coastguard Worker
OpenFile(const FilePath & filename,const char * mode)964*6777b538SAndroid Build Coastguard Worker FILE* OpenFile(const FilePath& filename, const char* mode) {
965*6777b538SAndroid Build Coastguard Worker // 'N' is unconditionally added below, so be sure there is not one already
966*6777b538SAndroid Build Coastguard Worker // present before a comma in |mode|.
967*6777b538SAndroid Build Coastguard Worker DCHECK(
968*6777b538SAndroid Build Coastguard Worker strchr(mode, 'N') == nullptr ||
969*6777b538SAndroid Build Coastguard Worker (strchr(mode, ',') != nullptr && strchr(mode, 'N') > strchr(mode, ',')));
970*6777b538SAndroid Build Coastguard Worker ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
971*6777b538SAndroid Build Coastguard Worker std::wstring w_mode = UTF8ToWide(mode);
972*6777b538SAndroid Build Coastguard Worker AppendModeCharacter(L'N', &w_mode);
973*6777b538SAndroid Build Coastguard Worker return _wfsopen(filename.value().c_str(), w_mode.c_str(), _SH_DENYNO);
974*6777b538SAndroid Build Coastguard Worker }
975*6777b538SAndroid Build Coastguard Worker
FileToFILE(File file,const char * mode)976*6777b538SAndroid Build Coastguard Worker FILE* FileToFILE(File file, const char* mode) {
977*6777b538SAndroid Build Coastguard Worker DCHECK(!file.async());
978*6777b538SAndroid Build Coastguard Worker if (!file.IsValid())
979*6777b538SAndroid Build Coastguard Worker return NULL;
980*6777b538SAndroid Build Coastguard Worker int fd =
981*6777b538SAndroid Build Coastguard Worker _open_osfhandle(reinterpret_cast<intptr_t>(file.GetPlatformFile()), 0);
982*6777b538SAndroid Build Coastguard Worker if (fd < 0)
983*6777b538SAndroid Build Coastguard Worker return NULL;
984*6777b538SAndroid Build Coastguard Worker file.TakePlatformFile();
985*6777b538SAndroid Build Coastguard Worker FILE* stream = _fdopen(fd, mode);
986*6777b538SAndroid Build Coastguard Worker if (!stream)
987*6777b538SAndroid Build Coastguard Worker _close(fd);
988*6777b538SAndroid Build Coastguard Worker return stream;
989*6777b538SAndroid Build Coastguard Worker }
990*6777b538SAndroid Build Coastguard Worker
FILEToFile(FILE * file_stream)991*6777b538SAndroid Build Coastguard Worker File FILEToFile(FILE* file_stream) {
992*6777b538SAndroid Build Coastguard Worker if (!file_stream)
993*6777b538SAndroid Build Coastguard Worker return File();
994*6777b538SAndroid Build Coastguard Worker
995*6777b538SAndroid Build Coastguard Worker int fd = _fileno(file_stream);
996*6777b538SAndroid Build Coastguard Worker DCHECK_GE(fd, 0);
997*6777b538SAndroid Build Coastguard Worker intptr_t file_handle = _get_osfhandle(fd);
998*6777b538SAndroid Build Coastguard Worker DCHECK_NE(file_handle, reinterpret_cast<intptr_t>(INVALID_HANDLE_VALUE));
999*6777b538SAndroid Build Coastguard Worker
1000*6777b538SAndroid Build Coastguard Worker HANDLE other_handle = nullptr;
1001*6777b538SAndroid Build Coastguard Worker if (!::DuplicateHandle(
1002*6777b538SAndroid Build Coastguard Worker /*hSourceProcessHandle=*/GetCurrentProcess(),
1003*6777b538SAndroid Build Coastguard Worker reinterpret_cast<HANDLE>(file_handle),
1004*6777b538SAndroid Build Coastguard Worker /*hTargetProcessHandle=*/GetCurrentProcess(), &other_handle,
1005*6777b538SAndroid Build Coastguard Worker /*dwDesiredAccess=*/0,
1006*6777b538SAndroid Build Coastguard Worker /*bInheritHandle=*/FALSE,
1007*6777b538SAndroid Build Coastguard Worker /*dwOptions=*/DUPLICATE_SAME_ACCESS)) {
1008*6777b538SAndroid Build Coastguard Worker return File(File::GetLastFileError());
1009*6777b538SAndroid Build Coastguard Worker }
1010*6777b538SAndroid Build Coastguard Worker
1011*6777b538SAndroid Build Coastguard Worker return File(ScopedPlatformFile(other_handle));
1012*6777b538SAndroid Build Coastguard Worker }
1013*6777b538SAndroid Build Coastguard Worker
ReadFile(const FilePath & filename,span<char> buffer)1014*6777b538SAndroid Build Coastguard Worker std::optional<uint64_t> ReadFile(const FilePath& filename, span<char> buffer) {
1015*6777b538SAndroid Build Coastguard Worker ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
1016*6777b538SAndroid Build Coastguard Worker win::ScopedHandle file(CreateFile(filename.value().c_str(), GENERIC_READ,
1017*6777b538SAndroid Build Coastguard Worker FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
1018*6777b538SAndroid Build Coastguard Worker OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN,
1019*6777b538SAndroid Build Coastguard Worker NULL));
1020*6777b538SAndroid Build Coastguard Worker if (!file.is_valid()) {
1021*6777b538SAndroid Build Coastguard Worker return std::nullopt;
1022*6777b538SAndroid Build Coastguard Worker }
1023*6777b538SAndroid Build Coastguard Worker
1024*6777b538SAndroid Build Coastguard Worker // TODO(crbug.com/1333521): Consider supporting reading more than INT_MAX
1025*6777b538SAndroid Build Coastguard Worker // bytes.
1026*6777b538SAndroid Build Coastguard Worker DWORD bytes_to_read = static_cast<DWORD>(checked_cast<int>(buffer.size()));
1027*6777b538SAndroid Build Coastguard Worker
1028*6777b538SAndroid Build Coastguard Worker DWORD bytes_read;
1029*6777b538SAndroid Build Coastguard Worker if (!::ReadFile(file.get(), buffer.data(), bytes_to_read, &bytes_read,
1030*6777b538SAndroid Build Coastguard Worker nullptr)) {
1031*6777b538SAndroid Build Coastguard Worker return std::nullopt;
1032*6777b538SAndroid Build Coastguard Worker }
1033*6777b538SAndroid Build Coastguard Worker return bytes_read;
1034*6777b538SAndroid Build Coastguard Worker }
1035*6777b538SAndroid Build Coastguard Worker
WriteFile(const FilePath & filename,const char * data,int size)1036*6777b538SAndroid Build Coastguard Worker int WriteFile(const FilePath& filename, const char* data, int size) {
1037*6777b538SAndroid Build Coastguard Worker ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
1038*6777b538SAndroid Build Coastguard Worker win::ScopedHandle file(CreateFile(filename.value().c_str(), GENERIC_WRITE, 0,
1039*6777b538SAndroid Build Coastguard Worker NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,
1040*6777b538SAndroid Build Coastguard Worker NULL));
1041*6777b538SAndroid Build Coastguard Worker if (!file.is_valid() || size < 0) {
1042*6777b538SAndroid Build Coastguard Worker DPLOG(WARNING) << "WriteFile failed for path " << filename.value();
1043*6777b538SAndroid Build Coastguard Worker return -1;
1044*6777b538SAndroid Build Coastguard Worker }
1045*6777b538SAndroid Build Coastguard Worker
1046*6777b538SAndroid Build Coastguard Worker DWORD written;
1047*6777b538SAndroid Build Coastguard Worker BOOL result =
1048*6777b538SAndroid Build Coastguard Worker ::WriteFile(file.get(), data, static_cast<DWORD>(size), &written, NULL);
1049*6777b538SAndroid Build Coastguard Worker if (result && static_cast<int>(written) == size)
1050*6777b538SAndroid Build Coastguard Worker return static_cast<int>(written);
1051*6777b538SAndroid Build Coastguard Worker
1052*6777b538SAndroid Build Coastguard Worker if (!result) {
1053*6777b538SAndroid Build Coastguard Worker // WriteFile failed.
1054*6777b538SAndroid Build Coastguard Worker DPLOG(WARNING) << "writing file " << filename.value() << " failed";
1055*6777b538SAndroid Build Coastguard Worker } else {
1056*6777b538SAndroid Build Coastguard Worker // Didn't write all the bytes.
1057*6777b538SAndroid Build Coastguard Worker DLOG(WARNING) << "wrote" << written << " bytes to " << filename.value()
1058*6777b538SAndroid Build Coastguard Worker << " expected " << size;
1059*6777b538SAndroid Build Coastguard Worker }
1060*6777b538SAndroid Build Coastguard Worker return -1;
1061*6777b538SAndroid Build Coastguard Worker }
1062*6777b538SAndroid Build Coastguard Worker
AppendToFile(const FilePath & filename,span<const uint8_t> data)1063*6777b538SAndroid Build Coastguard Worker bool AppendToFile(const FilePath& filename, span<const uint8_t> data) {
1064*6777b538SAndroid Build Coastguard Worker ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
1065*6777b538SAndroid Build Coastguard Worker win::ScopedHandle file(CreateFile(filename.value().c_str(), FILE_APPEND_DATA,
1066*6777b538SAndroid Build Coastguard Worker 0, nullptr, OPEN_EXISTING, 0, nullptr));
1067*6777b538SAndroid Build Coastguard Worker if (!file.is_valid()) {
1068*6777b538SAndroid Build Coastguard Worker VPLOG(1) << "CreateFile failed for path " << filename.value();
1069*6777b538SAndroid Build Coastguard Worker return false;
1070*6777b538SAndroid Build Coastguard Worker }
1071*6777b538SAndroid Build Coastguard Worker
1072*6777b538SAndroid Build Coastguard Worker DWORD written;
1073*6777b538SAndroid Build Coastguard Worker DWORD size = checked_cast<DWORD>(data.size());
1074*6777b538SAndroid Build Coastguard Worker BOOL result = ::WriteFile(file.get(), data.data(), size, &written, nullptr);
1075*6777b538SAndroid Build Coastguard Worker if (result && written == size)
1076*6777b538SAndroid Build Coastguard Worker return true;
1077*6777b538SAndroid Build Coastguard Worker
1078*6777b538SAndroid Build Coastguard Worker if (!result) {
1079*6777b538SAndroid Build Coastguard Worker // WriteFile failed.
1080*6777b538SAndroid Build Coastguard Worker VPLOG(1) << "Writing file " << filename.value() << " failed";
1081*6777b538SAndroid Build Coastguard Worker } else {
1082*6777b538SAndroid Build Coastguard Worker // Didn't write all the bytes.
1083*6777b538SAndroid Build Coastguard Worker VPLOG(1) << "Only wrote " << written << " out of " << size << " byte(s) to "
1084*6777b538SAndroid Build Coastguard Worker << filename.value();
1085*6777b538SAndroid Build Coastguard Worker }
1086*6777b538SAndroid Build Coastguard Worker return false;
1087*6777b538SAndroid Build Coastguard Worker }
1088*6777b538SAndroid Build Coastguard Worker
AppendToFile(const FilePath & filename,StringPiece data)1089*6777b538SAndroid Build Coastguard Worker bool AppendToFile(const FilePath& filename, StringPiece data) {
1090*6777b538SAndroid Build Coastguard Worker return AppendToFile(filename, as_bytes(make_span(data)));
1091*6777b538SAndroid Build Coastguard Worker }
1092*6777b538SAndroid Build Coastguard Worker
GetCurrentDirectory(FilePath * dir)1093*6777b538SAndroid Build Coastguard Worker bool GetCurrentDirectory(FilePath* dir) {
1094*6777b538SAndroid Build Coastguard Worker ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
1095*6777b538SAndroid Build Coastguard Worker
1096*6777b538SAndroid Build Coastguard Worker wchar_t system_buffer[MAX_PATH];
1097*6777b538SAndroid Build Coastguard Worker system_buffer[0] = 0;
1098*6777b538SAndroid Build Coastguard Worker DWORD len = ::GetCurrentDirectory(MAX_PATH, system_buffer);
1099*6777b538SAndroid Build Coastguard Worker if (len == 0 || len > MAX_PATH)
1100*6777b538SAndroid Build Coastguard Worker return false;
1101*6777b538SAndroid Build Coastguard Worker // TODO(evanm): the old behavior of this function was to always strip the
1102*6777b538SAndroid Build Coastguard Worker // trailing slash. We duplicate this here, but it shouldn't be necessary
1103*6777b538SAndroid Build Coastguard Worker // when everyone is using the appropriate FilePath APIs.
1104*6777b538SAndroid Build Coastguard Worker *dir = FilePath(FilePath::StringPieceType(system_buffer))
1105*6777b538SAndroid Build Coastguard Worker .StripTrailingSeparators();
1106*6777b538SAndroid Build Coastguard Worker return true;
1107*6777b538SAndroid Build Coastguard Worker }
1108*6777b538SAndroid Build Coastguard Worker
SetCurrentDirectory(const FilePath & directory)1109*6777b538SAndroid Build Coastguard Worker bool SetCurrentDirectory(const FilePath& directory) {
1110*6777b538SAndroid Build Coastguard Worker ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
1111*6777b538SAndroid Build Coastguard Worker return ::SetCurrentDirectory(directory.value().c_str()) != 0;
1112*6777b538SAndroid Build Coastguard Worker }
1113*6777b538SAndroid Build Coastguard Worker
GetMaximumPathComponentLength(const FilePath & path)1114*6777b538SAndroid Build Coastguard Worker int GetMaximumPathComponentLength(const FilePath& path) {
1115*6777b538SAndroid Build Coastguard Worker ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
1116*6777b538SAndroid Build Coastguard Worker
1117*6777b538SAndroid Build Coastguard Worker wchar_t volume_path[MAX_PATH];
1118*6777b538SAndroid Build Coastguard Worker if (!GetVolumePathNameW(path.NormalizePathSeparators().value().c_str(),
1119*6777b538SAndroid Build Coastguard Worker volume_path, std::size(volume_path))) {
1120*6777b538SAndroid Build Coastguard Worker return -1;
1121*6777b538SAndroid Build Coastguard Worker }
1122*6777b538SAndroid Build Coastguard Worker
1123*6777b538SAndroid Build Coastguard Worker DWORD max_length = 0;
1124*6777b538SAndroid Build Coastguard Worker if (!GetVolumeInformationW(volume_path, NULL, 0, NULL, &max_length, NULL,
1125*6777b538SAndroid Build Coastguard Worker NULL, 0)) {
1126*6777b538SAndroid Build Coastguard Worker return -1;
1127*6777b538SAndroid Build Coastguard Worker }
1128*6777b538SAndroid Build Coastguard Worker
1129*6777b538SAndroid Build Coastguard Worker // Length of |path| with path separator appended.
1130*6777b538SAndroid Build Coastguard Worker size_t prefix = path.StripTrailingSeparators().value().size() + 1;
1131*6777b538SAndroid Build Coastguard Worker // The whole path string must be shorter than MAX_PATH. That is, it must be
1132*6777b538SAndroid Build Coastguard Worker // prefix + component_length < MAX_PATH (or equivalently, <= MAX_PATH - 1).
1133*6777b538SAndroid Build Coastguard Worker int whole_path_limit = std::max(0, MAX_PATH - 1 - static_cast<int>(prefix));
1134*6777b538SAndroid Build Coastguard Worker return std::min(whole_path_limit, static_cast<int>(max_length));
1135*6777b538SAndroid Build Coastguard Worker }
1136*6777b538SAndroid Build Coastguard Worker
CopyFile(const FilePath & from_path,const FilePath & to_path)1137*6777b538SAndroid Build Coastguard Worker bool CopyFile(const FilePath& from_path, const FilePath& to_path) {
1138*6777b538SAndroid Build Coastguard Worker return DoCopyFile(from_path, to_path, false);
1139*6777b538SAndroid Build Coastguard Worker }
1140*6777b538SAndroid Build Coastguard Worker
SetNonBlocking(int fd)1141*6777b538SAndroid Build Coastguard Worker bool SetNonBlocking(int fd) {
1142*6777b538SAndroid Build Coastguard Worker unsigned long nonblocking = 1;
1143*6777b538SAndroid Build Coastguard Worker if (ioctlsocket(static_cast<SOCKET>(fd), static_cast<long>(FIONBIO),
1144*6777b538SAndroid Build Coastguard Worker &nonblocking) == 0)
1145*6777b538SAndroid Build Coastguard Worker return true;
1146*6777b538SAndroid Build Coastguard Worker return false;
1147*6777b538SAndroid Build Coastguard Worker }
1148*6777b538SAndroid Build Coastguard Worker
PreReadFile(const FilePath & file_path,bool is_executable,bool sequential,int64_t max_bytes)1149*6777b538SAndroid Build Coastguard Worker bool PreReadFile(const FilePath& file_path,
1150*6777b538SAndroid Build Coastguard Worker bool is_executable,
1151*6777b538SAndroid Build Coastguard Worker bool sequential,
1152*6777b538SAndroid Build Coastguard Worker int64_t max_bytes) {
1153*6777b538SAndroid Build Coastguard Worker DCHECK_GE(max_bytes, 0);
1154*6777b538SAndroid Build Coastguard Worker
1155*6777b538SAndroid Build Coastguard Worker if (max_bytes == 0) {
1156*6777b538SAndroid Build Coastguard Worker // ::PrefetchVirtualMemory() fails when asked to read zero bytes.
1157*6777b538SAndroid Build Coastguard Worker // base::MemoryMappedFile::Initialize() fails on an empty file.
1158*6777b538SAndroid Build Coastguard Worker return true;
1159*6777b538SAndroid Build Coastguard Worker }
1160*6777b538SAndroid Build Coastguard Worker
1161*6777b538SAndroid Build Coastguard Worker // ::PrefetchVirtualMemory() fails if the file is opened with write access.
1162*6777b538SAndroid Build Coastguard Worker MemoryMappedFile::Access access = is_executable
1163*6777b538SAndroid Build Coastguard Worker ? MemoryMappedFile::READ_CODE_IMAGE
1164*6777b538SAndroid Build Coastguard Worker : MemoryMappedFile::READ_ONLY;
1165*6777b538SAndroid Build Coastguard Worker MemoryMappedFile mapped_file;
1166*6777b538SAndroid Build Coastguard Worker if (!mapped_file.Initialize(file_path, access)) {
1167*6777b538SAndroid Build Coastguard Worker return false;
1168*6777b538SAndroid Build Coastguard Worker }
1169*6777b538SAndroid Build Coastguard Worker
1170*6777b538SAndroid Build Coastguard Worker const ::SIZE_T length =
1171*6777b538SAndroid Build Coastguard Worker std::min(base::saturated_cast<::SIZE_T>(max_bytes),
1172*6777b538SAndroid Build Coastguard Worker base::saturated_cast<::SIZE_T>(mapped_file.length()));
1173*6777b538SAndroid Build Coastguard Worker ::_WIN32_MEMORY_RANGE_ENTRY address_range = {mapped_file.data(), length};
1174*6777b538SAndroid Build Coastguard Worker // Use ::PrefetchVirtualMemory(). This is better than a
1175*6777b538SAndroid Build Coastguard Worker // simple data file read, more from a RAM perspective than CPU. This is
1176*6777b538SAndroid Build Coastguard Worker // because reading the file as data results in double mapping to
1177*6777b538SAndroid Build Coastguard Worker // Image/executable pages for all pages of code executed.
1178*6777b538SAndroid Build Coastguard Worker return ::PrefetchVirtualMemory(::GetCurrentProcess(),
1179*6777b538SAndroid Build Coastguard Worker /*NumberOfEntries=*/1, &address_range,
1180*6777b538SAndroid Build Coastguard Worker /*Flags=*/0);
1181*6777b538SAndroid Build Coastguard Worker }
1182*6777b538SAndroid Build Coastguard Worker
PreventExecuteMappingInternal(const FilePath & path,bool skip_path_check)1183*6777b538SAndroid Build Coastguard Worker bool PreventExecuteMappingInternal(const FilePath& path, bool skip_path_check) {
1184*6777b538SAndroid Build Coastguard Worker if (!base::FeatureList::IsEnabled(
1185*6777b538SAndroid Build Coastguard Worker features::kEnforceNoExecutableFileHandles)) {
1186*6777b538SAndroid Build Coastguard Worker return true;
1187*6777b538SAndroid Build Coastguard Worker }
1188*6777b538SAndroid Build Coastguard Worker
1189*6777b538SAndroid Build Coastguard Worker bool is_path_safe = skip_path_check || IsPathSafeToSetAclOn(path);
1190*6777b538SAndroid Build Coastguard Worker
1191*6777b538SAndroid Build Coastguard Worker if (!is_path_safe) {
1192*6777b538SAndroid Build Coastguard Worker // To mitigate the effect of past OS bugs where attackers are able to use
1193*6777b538SAndroid Build Coastguard Worker // writeable handles to create malicious executable images which can be
1194*6777b538SAndroid Build Coastguard Worker // later mapped into unsandboxed processes, file handles that permit writing
1195*6777b538SAndroid Build Coastguard Worker // that are passed to untrusted processes, e.g. renderers, should be marked
1196*6777b538SAndroid Build Coastguard Worker // with a deny execute ACE. This prevents re-opening the file for execute
1197*6777b538SAndroid Build Coastguard Worker // later on.
1198*6777b538SAndroid Build Coastguard Worker //
1199*6777b538SAndroid Build Coastguard Worker // To accomplish this, code that needs to pass writable file handles to a
1200*6777b538SAndroid Build Coastguard Worker // renderer should open the file with the flags added by
1201*6777b538SAndroid Build Coastguard Worker // `AddFlagsForPassingToUntrustedProcess()` (explicitly
1202*6777b538SAndroid Build Coastguard Worker // FLAG_WIN_NO_EXECUTE). This results in this PreventExecuteMapping being
1203*6777b538SAndroid Build Coastguard Worker // called by base::File.
1204*6777b538SAndroid Build Coastguard Worker //
1205*6777b538SAndroid Build Coastguard Worker // However, simply using this universally on all files that are opened
1206*6777b538SAndroid Build Coastguard Worker // writeable is also undesirable: things can and will randomly break if they
1207*6777b538SAndroid Build Coastguard Worker // are marked no-exec (e.g. marking an exe that the user downloads as
1208*6777b538SAndroid Build Coastguard Worker // no-exec will prevent the user from running it). There are also
1209*6777b538SAndroid Build Coastguard Worker // performance implications of doing this for all files unnecessarily.
1210*6777b538SAndroid Build Coastguard Worker //
1211*6777b538SAndroid Build Coastguard Worker // Code that passes writable files to the renderer is also expected to
1212*6777b538SAndroid Build Coastguard Worker // reference files in places like the user data dir (e.g. for the filesystem
1213*6777b538SAndroid Build Coastguard Worker // API) or temp files. Any attempt to pass a writeable handle to a path
1214*6777b538SAndroid Build Coastguard Worker // outside these areas is likely its own security issue as an untrusted
1215*6777b538SAndroid Build Coastguard Worker // renderer process should never have write access to e.g. system files or
1216*6777b538SAndroid Build Coastguard Worker // downloads.
1217*6777b538SAndroid Build Coastguard Worker //
1218*6777b538SAndroid Build Coastguard Worker // This check aims to catch misuse of
1219*6777b538SAndroid Build Coastguard Worker // `AddFlagsForPassingToUntrustedProcess()` on paths outside these
1220*6777b538SAndroid Build Coastguard Worker // locations. Any time it hits it is also likely that a handle to a
1221*6777b538SAndroid Build Coastguard Worker // dangerous path is being passed to a renderer, which is inherently unsafe.
1222*6777b538SAndroid Build Coastguard Worker //
1223*6777b538SAndroid Build Coastguard Worker // If this check hits, please do not ignore it but consult security team.
1224*6777b538SAndroid Build Coastguard Worker DLOG(FATAL) << "Unsafe to deny execute access to path : " << path;
1225*6777b538SAndroid Build Coastguard Worker
1226*6777b538SAndroid Build Coastguard Worker return false;
1227*6777b538SAndroid Build Coastguard Worker }
1228*6777b538SAndroid Build Coastguard Worker
1229*6777b538SAndroid Build Coastguard Worker static constexpr wchar_t kEveryoneSid[] = L"WD";
1230*6777b538SAndroid Build Coastguard Worker auto sids = win::Sid::FromSddlStringVector({kEveryoneSid});
1231*6777b538SAndroid Build Coastguard Worker
1232*6777b538SAndroid Build Coastguard Worker // Remove executable access from the file. The API does not add a duplicate
1233*6777b538SAndroid Build Coastguard Worker // ACE if it already exists.
1234*6777b538SAndroid Build Coastguard Worker return win::DenyAccessToPath(path, *sids, FILE_EXECUTE, /*NO_INHERITANCE=*/0,
1235*6777b538SAndroid Build Coastguard Worker /*recursive=*/false);
1236*6777b538SAndroid Build Coastguard Worker }
1237*6777b538SAndroid Build Coastguard Worker
PreventExecuteMapping(const FilePath & path)1238*6777b538SAndroid Build Coastguard Worker bool PreventExecuteMapping(const FilePath& path) {
1239*6777b538SAndroid Build Coastguard Worker return PreventExecuteMappingInternal(path, false);
1240*6777b538SAndroid Build Coastguard Worker }
1241*6777b538SAndroid Build Coastguard Worker
PreventExecuteMappingUnchecked(const FilePath & path,base::PassKey<PreventExecuteMappingClasses> passkey)1242*6777b538SAndroid Build Coastguard Worker bool PreventExecuteMappingUnchecked(
1243*6777b538SAndroid Build Coastguard Worker const FilePath& path,
1244*6777b538SAndroid Build Coastguard Worker base::PassKey<PreventExecuteMappingClasses> passkey) {
1245*6777b538SAndroid Build Coastguard Worker return PreventExecuteMappingInternal(path, true);
1246*6777b538SAndroid Build Coastguard Worker }
1247*6777b538SAndroid Build Coastguard Worker
SetExtraNoExecuteAllowedPath(int path_key)1248*6777b538SAndroid Build Coastguard Worker void SetExtraNoExecuteAllowedPath(int path_key) {
1249*6777b538SAndroid Build Coastguard Worker DCHECK(!g_extra_allowed_path_for_no_execute ||
1250*6777b538SAndroid Build Coastguard Worker g_extra_allowed_path_for_no_execute == path_key);
1251*6777b538SAndroid Build Coastguard Worker g_extra_allowed_path_for_no_execute = path_key;
1252*6777b538SAndroid Build Coastguard Worker base::FilePath valid_path;
1253*6777b538SAndroid Build Coastguard Worker DCHECK(
1254*6777b538SAndroid Build Coastguard Worker base::PathService::Get(g_extra_allowed_path_for_no_execute, &valid_path));
1255*6777b538SAndroid Build Coastguard Worker }
1256*6777b538SAndroid Build Coastguard Worker
1257*6777b538SAndroid Build Coastguard Worker // -----------------------------------------------------------------------------
1258*6777b538SAndroid Build Coastguard Worker
1259*6777b538SAndroid Build Coastguard Worker namespace internal {
1260*6777b538SAndroid Build Coastguard Worker
MoveUnsafe(const FilePath & from_path,const FilePath & to_path)1261*6777b538SAndroid Build Coastguard Worker bool MoveUnsafe(const FilePath& from_path, const FilePath& to_path) {
1262*6777b538SAndroid Build Coastguard Worker ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
1263*6777b538SAndroid Build Coastguard Worker
1264*6777b538SAndroid Build Coastguard Worker // NOTE: I suspect we could support longer paths, but that would involve
1265*6777b538SAndroid Build Coastguard Worker // analyzing all our usage of files.
1266*6777b538SAndroid Build Coastguard Worker if (from_path.value().length() >= MAX_PATH ||
1267*6777b538SAndroid Build Coastguard Worker to_path.value().length() >= MAX_PATH) {
1268*6777b538SAndroid Build Coastguard Worker return false;
1269*6777b538SAndroid Build Coastguard Worker }
1270*6777b538SAndroid Build Coastguard Worker if (MoveFileEx(from_path.value().c_str(), to_path.value().c_str(),
1271*6777b538SAndroid Build Coastguard Worker MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING) != 0)
1272*6777b538SAndroid Build Coastguard Worker return true;
1273*6777b538SAndroid Build Coastguard Worker
1274*6777b538SAndroid Build Coastguard Worker // Keep the last error value from MoveFileEx around in case the below
1275*6777b538SAndroid Build Coastguard Worker // fails.
1276*6777b538SAndroid Build Coastguard Worker bool ret = false;
1277*6777b538SAndroid Build Coastguard Worker DWORD last_error = ::GetLastError();
1278*6777b538SAndroid Build Coastguard Worker
1279*6777b538SAndroid Build Coastguard Worker if (DirectoryExists(from_path)) {
1280*6777b538SAndroid Build Coastguard Worker // MoveFileEx fails if moving directory across volumes. We will simulate
1281*6777b538SAndroid Build Coastguard Worker // the move by using Copy and Delete. Ideally we could check whether
1282*6777b538SAndroid Build Coastguard Worker // from_path and to_path are indeed in different volumes.
1283*6777b538SAndroid Build Coastguard Worker ret = internal::CopyAndDeleteDirectory(from_path, to_path);
1284*6777b538SAndroid Build Coastguard Worker }
1285*6777b538SAndroid Build Coastguard Worker
1286*6777b538SAndroid Build Coastguard Worker if (!ret) {
1287*6777b538SAndroid Build Coastguard Worker // Leave a clue about what went wrong so that it can be (at least) picked
1288*6777b538SAndroid Build Coastguard Worker // up by a PLOG entry.
1289*6777b538SAndroid Build Coastguard Worker ::SetLastError(last_error);
1290*6777b538SAndroid Build Coastguard Worker }
1291*6777b538SAndroid Build Coastguard Worker
1292*6777b538SAndroid Build Coastguard Worker return ret;
1293*6777b538SAndroid Build Coastguard Worker }
1294*6777b538SAndroid Build Coastguard Worker
CopyAndDeleteDirectory(const FilePath & from_path,const FilePath & to_path)1295*6777b538SAndroid Build Coastguard Worker bool CopyAndDeleteDirectory(const FilePath& from_path,
1296*6777b538SAndroid Build Coastguard Worker const FilePath& to_path) {
1297*6777b538SAndroid Build Coastguard Worker ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
1298*6777b538SAndroid Build Coastguard Worker if (CopyDirectory(from_path, to_path, true)) {
1299*6777b538SAndroid Build Coastguard Worker if (DeletePathRecursively(from_path))
1300*6777b538SAndroid Build Coastguard Worker return true;
1301*6777b538SAndroid Build Coastguard Worker
1302*6777b538SAndroid Build Coastguard Worker // Like Move, this function is not transactional, so we just
1303*6777b538SAndroid Build Coastguard Worker // leave the copied bits behind if deleting from_path fails.
1304*6777b538SAndroid Build Coastguard Worker // If to_path exists previously then we have already overwritten
1305*6777b538SAndroid Build Coastguard Worker // it by now, we don't get better off by deleting the new bits.
1306*6777b538SAndroid Build Coastguard Worker }
1307*6777b538SAndroid Build Coastguard Worker return false;
1308*6777b538SAndroid Build Coastguard Worker }
1309*6777b538SAndroid Build Coastguard Worker
1310*6777b538SAndroid Build Coastguard Worker } // namespace internal
1311*6777b538SAndroid Build Coastguard Worker } // namespace base
1312