Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/file_util.h"
7 #include <windows.h>
8 #include <shellapi.h>
9 #include <shlobj.h>
10 #include <time.h>
11 #include <string>
13 #include "base/file_path.h"
14 #include "base/logging.h"
15 #include "base/scoped_handle.h"
16 #include "base/string_util.h"
17 #include "base/time.h"
18 #include "base/win_util.h"
20 namespace file_util {
22 bool AbsolutePath(FilePath* path) {
23 wchar_t file_path_buf[MAX_PATH];
24 if (!_wfullpath(file_path_buf, path->value().c_str(), MAX_PATH))
25 return false;
26 *path = FilePath(file_path_buf);
27 return true;
28 }
30 bool Delete(const FilePath& path, bool recursive) {
31 if (path.value().length() >= MAX_PATH)
32 return false;
34 // If we're not recursing use DeleteFile; it should be faster. DeleteFile
35 // fails if passed a directory though, which is why we fall through on
36 // failure to the SHFileOperation.
37 if (!recursive && DeleteFile(path.value().c_str()) != 0)
38 return true;
40 // SHFILEOPSTRUCT wants the path to be terminated with two NULLs,
41 // so we have to use wcscpy because wcscpy_s writes non-NULLs
42 // into the rest of the buffer.
43 wchar_t double_terminated_path[MAX_PATH + 1] = {0};
44 #pragma warning(suppress:4996) // don't complain about wcscpy deprecation
45 wcscpy(double_terminated_path, path.value().c_str());
47 SHFILEOPSTRUCT file_operation = {0};
48 file_operation.wFunc = FO_DELETE;
49 file_operation.pFrom = double_terminated_path;
50 file_operation.fFlags = FOF_NOERRORUI | FOF_SILENT | FOF_NOCONFIRMATION;
51 if (!recursive)
52 file_operation.fFlags |= FOF_NORECURSION | FOF_FILESONLY;
53 int err = SHFileOperation(&file_operation);
54 // Some versions of Windows return ERROR_FILE_NOT_FOUND when
55 // deleting an empty directory.
56 return (err == 0 || err == ERROR_FILE_NOT_FOUND);
57 }
59 bool CopyFile(const FilePath& from_path, const FilePath& to_path) {
60 // NOTE: I suspect we could support longer paths, but that would involve
61 // analyzing all our usage of files.
62 if (from_path.value().length() >= MAX_PATH ||
63 to_path.value().length() >= MAX_PATH) {
64 return false;
65 }
66 return (::CopyFile(from_path.value().c_str(), to_path.value().c_str(),
67 false) != 0);
68 }
70 bool ShellCopy(const FilePath& from_path, const FilePath& to_path,
71 bool recursive) {
72 // NOTE: I suspect we could support longer paths, but that would involve
73 // analyzing all our usage of files.
74 if (from_path.value().length() >= MAX_PATH ||
75 to_path.value().length() >= MAX_PATH) {
76 return false;
77 }
79 // SHFILEOPSTRUCT wants the path to be terminated with two NULLs,
80 // so we have to use wcscpy because wcscpy_s writes non-NULLs
81 // into the rest of the buffer.
82 wchar_t double_terminated_path_from[MAX_PATH + 1] = {0};
83 wchar_t double_terminated_path_to[MAX_PATH + 1] = {0};
84 #pragma warning(suppress:4996) // don't complain about wcscpy deprecation
85 wcscpy(double_terminated_path_from, from_path.value().c_str());
86 #pragma warning(suppress:4996) // don't complain about wcscpy deprecation
87 wcscpy(double_terminated_path_to, to_path.value().c_str());
89 SHFILEOPSTRUCT file_operation = {0};
90 file_operation.wFunc = FO_COPY;
91 file_operation.pFrom = double_terminated_path_from;
92 file_operation.pTo = double_terminated_path_to;
93 file_operation.fFlags = FOF_NOERRORUI | FOF_SILENT | FOF_NOCONFIRMATION |
94 FOF_NOCONFIRMMKDIR;
95 if (!recursive)
96 file_operation.fFlags |= FOF_NORECURSION | FOF_FILESONLY;
98 return (SHFileOperation(&file_operation) == 0);
99 }
101 bool CopyDirectory(const FilePath& from_path, const FilePath& to_path,
102 bool recursive) {
103 if (recursive)
104 return ShellCopy(from_path, to_path, true);
106 // Instead of creating a new directory, we copy the old one to include the
107 // security information of the folder as part of the copy.
108 if (!PathExists(to_path)) {
109 // Except that Vista fails to do that, and instead do a recursive copy if
110 // the target directory doesn't exist.
111 if (win_util::GetWinVersion() >= win_util::WINVERSION_VISTA)
112 CreateDirectory(to_path);
113 else
114 ShellCopy(from_path, to_path, false);
115 }
117 FilePath directory = from_path.Append(L"*.*");
118 return ShellCopy(directory, to_path, false);
119 }
121 bool PathExists(const FilePath& path) {
122 return (GetFileAttributes(path.value().c_str()) != INVALID_FILE_ATTRIBUTES);
123 }
125 bool PathIsWritable(const FilePath& path) {
126 HANDLE dir =
127 CreateFile(path.value().c_str(), FILE_ADD_FILE,
128 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
129 NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
131 if (dir == INVALID_HANDLE_VALUE)
132 return false;
134 CloseHandle(dir);
135 return true;
136 }
138 bool DirectoryExists(const FilePath& path) {
139 DWORD fileattr = GetFileAttributes(path.value().c_str());
140 if (fileattr != INVALID_FILE_ATTRIBUTES)
141 return (fileattr & FILE_ATTRIBUTE_DIRECTORY) != 0;
142 return false;
143 }
145 bool GetTempDir(FilePath* path) {
146 wchar_t temp_path[MAX_PATH + 1];
147 DWORD path_len = ::GetTempPath(MAX_PATH, temp_path);
148 if (path_len >= MAX_PATH || path_len <= 0)
149 return false;
150 // TODO(evanm): the old behavior of this function was to always strip the
151 // trailing slash. We duplicate this here, but it shouldn't be necessary
152 // when everyone is using the appropriate FilePath APIs.
153 std::wstring path_str(temp_path);
154 TrimTrailingSeparator(&path_str);
155 *path = FilePath(path_str);
156 return true;
157 }
159 bool GetShmemTempDir(FilePath* path) {
160 return GetTempDir(path);
161 }
163 bool CreateTemporaryFileName(FilePath* path) {
164 std::wstring temp_path, temp_file;
166 if (!GetTempDir(&temp_path))
167 return false;
169 if (CreateTemporaryFileNameInDir(temp_path, &temp_file)) {
170 *path = FilePath(temp_file);
171 return true;
172 }
174 return false;
175 }
177 FILE* CreateAndOpenTemporaryShmemFile(FilePath* path) {
178 return CreateAndOpenTemporaryFile(path);
179 }
181 // On POSIX we have semantics to create and open a temporary file
182 // atomically.
183 // TODO(jrg): is there equivalent call to use on Windows instead of
184 // going 2-step?
185 FILE* CreateAndOpenTemporaryFileInDir(const FilePath& dir, FilePath* path) {
186 std::wstring wstring_path;
187 if (!CreateTemporaryFileNameInDir(dir.value(), &wstring_path)) {
188 return NULL;
189 }
190 *path = FilePath(wstring_path);
191 // Open file in binary mode, to avoid problems with fwrite. On Windows
192 // it replaces \n's with \r\n's, which may surprise you.
193 // Reference: http://msdn.microsoft.com/en-us/library/h9t88zwz(VS.71).aspx
194 return OpenFile(*path, "wb+");
195 }
197 bool CreateTemporaryFileNameInDir(const std::wstring& dir,
198 std::wstring* temp_file) {
199 wchar_t temp_name[MAX_PATH + 1];
201 if (!GetTempFileName(dir.c_str(), L"", 0, temp_name))
202 return false; // fail!
204 DWORD path_len = GetLongPathName(temp_name, temp_name, MAX_PATH);
205 if (path_len > MAX_PATH + 1 || path_len == 0)
206 return false; // fail!
208 temp_file->assign(temp_name, path_len);
209 return true;
210 }
212 bool CreateNewTempDirectory(const FilePath::StringType& prefix,
213 FilePath* new_temp_path) {
214 FilePath system_temp_dir;
215 if (!GetTempDir(&system_temp_dir))
216 return false;
218 FilePath path_to_create;
219 srand(static_cast<uint32_t>(time(NULL)));
221 int count = 0;
222 while (count < 50) {
223 // Try create a new temporary directory with random generated name. If
224 // the one exists, keep trying another path name until we reach some limit.
225 path_to_create = system_temp_dir;
226 std::wstring new_dir_name;
227 new_dir_name.assign(prefix);
228 new_dir_name.append(IntToWString(rand() % kint16max));
229 path_to_create = path_to_create.Append(new_dir_name);
231 if (::CreateDirectory(path_to_create.value().c_str(), NULL))
232 break;
233 count++;
234 }
236 if (count == 50) {
237 return false;
238 }
240 *new_temp_path = path_to_create;
241 return true;
242 }
244 bool CreateDirectory(const FilePath& full_path) {
245 if (DirectoryExists(full_path))
246 return true;
247 int err = SHCreateDirectoryEx(NULL, full_path.value().c_str(), NULL);
248 return err == ERROR_SUCCESS;
249 }
251 bool GetFileInfo(const FilePath& file_path, FileInfo* results) {
252 WIN32_FILE_ATTRIBUTE_DATA attr;
253 if (!GetFileAttributesEx(file_path.ToWStringHack().c_str(),
254 GetFileExInfoStandard, &attr)) {
255 return false;
256 }
258 ULARGE_INTEGER size;
259 size.HighPart = attr.nFileSizeHigh;
260 size.LowPart = attr.nFileSizeLow;
261 results->size = size.QuadPart;
263 results->is_directory =
264 (attr.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
265 return true;
266 }
268 FILE* OpenFile(const FilePath& filename, const char* mode) {
269 std::wstring w_mode = ASCIIToWide(std::string(mode));
270 FILE* file;
271 if (_wfopen_s(&file, filename.value().c_str(), w_mode.c_str()) != 0) {
272 return NULL;
273 }
274 return file;
275 }
277 FILE* OpenFile(const std::string& filename, const char* mode) {
278 FILE* file;
279 if (fopen_s(&file, filename.c_str(), mode) != 0) {
280 return NULL;
281 }
282 return file;
283 }
285 int ReadFile(const FilePath& filename, char* data, int size) {
286 ScopedHandle file(CreateFile(filename.value().c_str(),
287 GENERIC_READ,
288 FILE_SHARE_READ | FILE_SHARE_WRITE,
289 NULL,
290 OPEN_EXISTING,
291 FILE_FLAG_SEQUENTIAL_SCAN,
292 NULL));
293 if (file == INVALID_HANDLE_VALUE)
294 return -1;
296 int ret_value;
297 DWORD read;
298 if (::ReadFile(file, data, size, &read, NULL) && read == size) {
299 ret_value = static_cast<int>(read);
300 } else {
301 ret_value = -1;
302 }
304 return ret_value;
305 }
307 int WriteFile(const FilePath& filename, const char* data, int size) {
308 ScopedHandle file(CreateFile(filename.value().c_str(),
309 GENERIC_WRITE,
310 0,
311 NULL,
312 CREATE_ALWAYS,
313 0,
314 NULL));
315 if (file == INVALID_HANDLE_VALUE) {
316 CHROMIUM_LOG(WARNING) << "CreateFile failed for path " << filename.value() <<
317 " error code=" << GetLastError() <<
318 " error text=" << win_util::FormatLastWin32Error();
319 return -1;
320 }
322 DWORD written;
323 BOOL result = ::WriteFile(file, data, size, &written, NULL);
324 if (result && written == size)
325 return static_cast<int>(written);
327 if (!result) {
328 // WriteFile failed.
329 CHROMIUM_LOG(WARNING) << "writing file " << filename.value() <<
330 " failed, error code=" << GetLastError() <<
331 " description=" << win_util::FormatLastWin32Error();
332 } else {
333 // Didn't write all the bytes.
334 CHROMIUM_LOG(WARNING) << "wrote" << written << " bytes to " <<
335 filename.value() << " expected " << size;
336 }
337 return -1;
338 }
340 // Gets the current working directory for the process.
341 bool GetCurrentDirectory(FilePath* dir) {
342 wchar_t system_buffer[MAX_PATH];
343 system_buffer[0] = 0;
344 DWORD len = ::GetCurrentDirectory(MAX_PATH, system_buffer);
345 if (len == 0 || len > MAX_PATH)
346 return false;
347 // TODO(evanm): the old behavior of this function was to always strip the
348 // trailing slash. We duplicate this here, but it shouldn't be necessary
349 // when everyone is using the appropriate FilePath APIs.
350 std::wstring dir_str(system_buffer);
351 file_util::TrimTrailingSeparator(&dir_str);
352 *dir = FilePath(dir_str);
353 return true;
354 }
356 // Sets the current working directory for the process.
357 bool SetCurrentDirectory(const FilePath& directory) {
358 BOOL ret = ::SetCurrentDirectory(directory.value().c_str());
359 return ret != 0;
360 }
362 // Deprecated functions ----------------------------------------------------
364 void InsertBeforeExtension(std::wstring* path_str,
365 const std::wstring& suffix) {
366 FilePath path(*path_str);
367 InsertBeforeExtension(&path, suffix);
368 path_str->assign(path.value());
369 }
370 void ReplaceExtension(std::wstring* file_name, const std::wstring& extension) {
371 FilePath path(*file_name);
372 ReplaceExtension(&path, extension);
373 file_name->assign(path.value());
374 }
375 } // namespace file_util