| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "base/file_util.h" | 5 #include "base/file_util.h" |
| 6 | 6 |
| 7 #include <windows.h> | 7 #include <windows.h> |
| 8 #include <propvarutil.h> | 8 #include <propvarutil.h> |
| 9 #include <psapi.h> | 9 #include <psapi.h> |
| 10 #include <shellapi.h> | 10 #include <shellapi.h> |
| 11 #include <shlobj.h> | 11 #include <shlobj.h> |
| 12 #include <time.h> | 12 #include <time.h> |
| 13 #include <string> | 13 #include <string> |
| 14 | 14 |
| 15 #include "base/file_path.h" | 15 #include "base/file_path.h" |
| 16 #include "base/logging.h" | 16 #include "base/logging.h" |
| 17 #include "base/metrics/histogram.h" | 17 #include "base/metrics/histogram.h" |
| 18 #include "base/pe_image.h" | 18 #include "base/pe_image.h" |
| 19 #include "base/scoped_comptr_win.h" | 19 #include "base/win/scoped_handle.h" |
| 20 #include "base/scoped_handle.h" | |
| 21 #include "base/string_number_conversions.h" | 20 #include "base/string_number_conversions.h" |
| 22 #include "base/string_util.h" | 21 #include "base/string_util.h" |
| 23 #include "base/time.h" | 22 #include "base/time.h" |
| 24 #include "base/utf_string_conversions.h" | 23 #include "base/utf_string_conversions.h" |
| 25 #include "base/win_util.h" | 24 #include "base/win_util.h" |
| 25 #include "base/win/scoped_comptr.h" |
| 26 #include "base/win/windows_version.h" | 26 #include "base/win/windows_version.h" |
| 27 | 27 |
| 28 namespace file_util { | 28 namespace file_util { |
| 29 | 29 |
| 30 namespace { | 30 namespace { |
| 31 | 31 |
| 32 const DWORD kFileShareAll = | 32 const DWORD kFileShareAll = |
| 33 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE; | 33 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE; |
| 34 | 34 |
| 35 // Helper for NormalizeFilePath(), defined below. | 35 // Helper for NormalizeFilePath(), defined below. |
| (...skipping 285 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 321 | 321 |
| 322 FILETIME local_filetime; | 322 FILETIME local_filetime; |
| 323 if (!FileTimeToLocalFileTime(&utc_filetime, &local_filetime)) | 323 if (!FileTimeToLocalFileTime(&utc_filetime, &local_filetime)) |
| 324 return false; | 324 return false; |
| 325 | 325 |
| 326 return !!FileTimeToSystemTime(&local_filetime, creation_time); | 326 return !!FileTimeToSystemTime(&local_filetime, creation_time); |
| 327 } | 327 } |
| 328 | 328 |
| 329 bool GetFileCreationLocalTime(const std::wstring& filename, | 329 bool GetFileCreationLocalTime(const std::wstring& filename, |
| 330 LPSYSTEMTIME creation_time) { | 330 LPSYSTEMTIME creation_time) { |
| 331 ScopedHandle file_handle( | 331 base::win::ScopedHandle file_handle( |
| 332 CreateFile(filename.c_str(), GENERIC_READ, kFileShareAll, NULL, | 332 CreateFile(filename.c_str(), GENERIC_READ, kFileShareAll, NULL, |
| 333 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)); | 333 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)); |
| 334 return GetFileCreationLocalTimeFromHandle(file_handle.Get(), creation_time); | 334 return GetFileCreationLocalTimeFromHandle(file_handle.Get(), creation_time); |
| 335 } | 335 } |
| 336 | 336 |
| 337 bool ResolveShortcut(FilePath* path) { | 337 bool ResolveShortcut(FilePath* path) { |
| 338 HRESULT result; | 338 HRESULT result; |
| 339 ScopedComPtr<IShellLink> i_shell_link; | 339 base::win::ScopedComPtr<IShellLink> i_shell_link; |
| 340 bool is_resolved = false; | 340 bool is_resolved = false; |
| 341 | 341 |
| 342 // Get pointer to the IShellLink interface | 342 // Get pointer to the IShellLink interface |
| 343 result = i_shell_link.CreateInstance(CLSID_ShellLink, NULL, | 343 result = i_shell_link.CreateInstance(CLSID_ShellLink, NULL, |
| 344 CLSCTX_INPROC_SERVER); | 344 CLSCTX_INPROC_SERVER); |
| 345 if (SUCCEEDED(result)) { | 345 if (SUCCEEDED(result)) { |
| 346 ScopedComPtr<IPersistFile> persist; | 346 base::win::ScopedComPtr<IPersistFile> persist; |
| 347 // Query IShellLink for the IPersistFile interface | 347 // Query IShellLink for the IPersistFile interface |
| 348 result = persist.QueryFrom(i_shell_link); | 348 result = persist.QueryFrom(i_shell_link); |
| 349 if (SUCCEEDED(result)) { | 349 if (SUCCEEDED(result)) { |
| 350 WCHAR temp_path[MAX_PATH]; | 350 WCHAR temp_path[MAX_PATH]; |
| 351 // Load the shell link | 351 // Load the shell link |
| 352 result = persist->Load(path->value().c_str(), STGM_READ); | 352 result = persist->Load(path->value().c_str(), STGM_READ); |
| 353 if (SUCCEEDED(result)) { | 353 if (SUCCEEDED(result)) { |
| 354 // Try to find the target of a shortcut | 354 // Try to find the target of a shortcut |
| 355 result = i_shell_link->Resolve(0, SLR_NO_UI); | 355 result = i_shell_link->Resolve(0, SLR_NO_UI); |
| 356 if (SUCCEEDED(result)) { | 356 if (SUCCEEDED(result)) { |
| (...skipping 10 matching lines...) Expand all Loading... |
| 367 } | 367 } |
| 368 | 368 |
| 369 bool CreateShortcutLink(const wchar_t *source, const wchar_t *destination, | 369 bool CreateShortcutLink(const wchar_t *source, const wchar_t *destination, |
| 370 const wchar_t *working_dir, const wchar_t *arguments, | 370 const wchar_t *working_dir, const wchar_t *arguments, |
| 371 const wchar_t *description, const wchar_t *icon, | 371 const wchar_t *description, const wchar_t *icon, |
| 372 int icon_index, const wchar_t* app_id) { | 372 int icon_index, const wchar_t* app_id) { |
| 373 // Length of arguments and description must be less than MAX_PATH. | 373 // Length of arguments and description must be less than MAX_PATH. |
| 374 DCHECK(lstrlen(arguments) < MAX_PATH); | 374 DCHECK(lstrlen(arguments) < MAX_PATH); |
| 375 DCHECK(lstrlen(description) < MAX_PATH); | 375 DCHECK(lstrlen(description) < MAX_PATH); |
| 376 | 376 |
| 377 ScopedComPtr<IShellLink> i_shell_link; | 377 base::win::ScopedComPtr<IShellLink> i_shell_link; |
| 378 ScopedComPtr<IPersistFile> i_persist_file; | 378 base::win::ScopedComPtr<IPersistFile> i_persist_file; |
| 379 | 379 |
| 380 // Get pointer to the IShellLink interface | 380 // Get pointer to the IShellLink interface |
| 381 HRESULT result = i_shell_link.CreateInstance(CLSID_ShellLink, NULL, | 381 HRESULT result = i_shell_link.CreateInstance(CLSID_ShellLink, NULL, |
| 382 CLSCTX_INPROC_SERVER); | 382 CLSCTX_INPROC_SERVER); |
| 383 if (FAILED(result)) | 383 if (FAILED(result)) |
| 384 return false; | 384 return false; |
| 385 | 385 |
| 386 // Query IShellLink for the IPersistFile interface | 386 // Query IShellLink for the IPersistFile interface |
| 387 result = i_persist_file.QueryFrom(i_shell_link); | 387 result = i_persist_file.QueryFrom(i_shell_link); |
| 388 if (FAILED(result)) | 388 if (FAILED(result)) |
| 389 return false; | 389 return false; |
| 390 | 390 |
| 391 if (FAILED(i_shell_link->SetPath(source))) | 391 if (FAILED(i_shell_link->SetPath(source))) |
| 392 return false; | 392 return false; |
| 393 | 393 |
| 394 if (working_dir && FAILED(i_shell_link->SetWorkingDirectory(working_dir))) | 394 if (working_dir && FAILED(i_shell_link->SetWorkingDirectory(working_dir))) |
| 395 return false; | 395 return false; |
| 396 | 396 |
| 397 if (arguments && FAILED(i_shell_link->SetArguments(arguments))) | 397 if (arguments && FAILED(i_shell_link->SetArguments(arguments))) |
| 398 return false; | 398 return false; |
| 399 | 399 |
| 400 if (description && FAILED(i_shell_link->SetDescription(description))) | 400 if (description && FAILED(i_shell_link->SetDescription(description))) |
| 401 return false; | 401 return false; |
| 402 | 402 |
| 403 if (icon && FAILED(i_shell_link->SetIconLocation(icon, icon_index))) | 403 if (icon && FAILED(i_shell_link->SetIconLocation(icon, icon_index))) |
| 404 return false; | 404 return false; |
| 405 | 405 |
| 406 if (app_id && (base::win::GetVersion() >= base::win::VERSION_WIN7)) { | 406 if (app_id && (base::win::GetVersion() >= base::win::VERSION_WIN7)) { |
| 407 ScopedComPtr<IPropertyStore> property_store; | 407 base::win::ScopedComPtr<IPropertyStore> property_store; |
| 408 if (FAILED(property_store.QueryFrom(i_shell_link))) | 408 if (FAILED(property_store.QueryFrom(i_shell_link))) |
| 409 return false; | 409 return false; |
| 410 | 410 |
| 411 if (!win_util::SetAppIdForPropertyStore(property_store, app_id)) | 411 if (!win_util::SetAppIdForPropertyStore(property_store, app_id)) |
| 412 return false; | 412 return false; |
| 413 } | 413 } |
| 414 | 414 |
| 415 result = i_persist_file->Save(destination, TRUE); | 415 result = i_persist_file->Save(destination, TRUE); |
| 416 return SUCCEEDED(result); | 416 return SUCCEEDED(result); |
| 417 } | 417 } |
| 418 | 418 |
| 419 | 419 |
| 420 bool UpdateShortcutLink(const wchar_t *source, const wchar_t *destination, | 420 bool UpdateShortcutLink(const wchar_t *source, const wchar_t *destination, |
| 421 const wchar_t *working_dir, const wchar_t *arguments, | 421 const wchar_t *working_dir, const wchar_t *arguments, |
| 422 const wchar_t *description, const wchar_t *icon, | 422 const wchar_t *description, const wchar_t *icon, |
| 423 int icon_index, const wchar_t* app_id) { | 423 int icon_index, const wchar_t* app_id) { |
| 424 // Length of arguments and description must be less than MAX_PATH. | 424 // Length of arguments and description must be less than MAX_PATH. |
| 425 DCHECK(lstrlen(arguments) < MAX_PATH); | 425 DCHECK(lstrlen(arguments) < MAX_PATH); |
| 426 DCHECK(lstrlen(description) < MAX_PATH); | 426 DCHECK(lstrlen(description) < MAX_PATH); |
| 427 | 427 |
| 428 // Get pointer to the IPersistFile interface and load existing link | 428 // Get pointer to the IPersistFile interface and load existing link |
| 429 ScopedComPtr<IShellLink> i_shell_link; | 429 base::win::ScopedComPtr<IShellLink> i_shell_link; |
| 430 if (FAILED(i_shell_link.CreateInstance(CLSID_ShellLink, NULL, | 430 if (FAILED(i_shell_link.CreateInstance(CLSID_ShellLink, NULL, |
| 431 CLSCTX_INPROC_SERVER))) | 431 CLSCTX_INPROC_SERVER))) |
| 432 return false; | 432 return false; |
| 433 | 433 |
| 434 ScopedComPtr<IPersistFile> i_persist_file; | 434 base::win::ScopedComPtr<IPersistFile> i_persist_file; |
| 435 if (FAILED(i_persist_file.QueryFrom(i_shell_link))) | 435 if (FAILED(i_persist_file.QueryFrom(i_shell_link))) |
| 436 return false; | 436 return false; |
| 437 | 437 |
| 438 if (FAILED(i_persist_file->Load(destination, STGM_READWRITE))) | 438 if (FAILED(i_persist_file->Load(destination, STGM_READWRITE))) |
| 439 return false; | 439 return false; |
| 440 | 440 |
| 441 if (source && FAILED(i_shell_link->SetPath(source))) | 441 if (source && FAILED(i_shell_link->SetPath(source))) |
| 442 return false; | 442 return false; |
| 443 | 443 |
| 444 if (working_dir && FAILED(i_shell_link->SetWorkingDirectory(working_dir))) | 444 if (working_dir && FAILED(i_shell_link->SetWorkingDirectory(working_dir))) |
| 445 return false; | 445 return false; |
| 446 | 446 |
| 447 if (arguments && FAILED(i_shell_link->SetArguments(arguments))) | 447 if (arguments && FAILED(i_shell_link->SetArguments(arguments))) |
| 448 return false; | 448 return false; |
| 449 | 449 |
| 450 if (description && FAILED(i_shell_link->SetDescription(description))) | 450 if (description && FAILED(i_shell_link->SetDescription(description))) |
| 451 return false; | 451 return false; |
| 452 | 452 |
| 453 if (icon && FAILED(i_shell_link->SetIconLocation(icon, icon_index))) | 453 if (icon && FAILED(i_shell_link->SetIconLocation(icon, icon_index))) |
| 454 return false; | 454 return false; |
| 455 | 455 |
| 456 if (app_id && base::win::GetVersion() >= base::win::VERSION_WIN7) { | 456 if (app_id && base::win::GetVersion() >= base::win::VERSION_WIN7) { |
| 457 ScopedComPtr<IPropertyStore> property_store; | 457 base::win::ScopedComPtr<IPropertyStore> property_store; |
| 458 if (FAILED(property_store.QueryFrom(i_shell_link))) | 458 if (FAILED(property_store.QueryFrom(i_shell_link))) |
| 459 return false; | 459 return false; |
| 460 | 460 |
| 461 if (!win_util::SetAppIdForPropertyStore(property_store, app_id)) | 461 if (!win_util::SetAppIdForPropertyStore(property_store, app_id)) |
| 462 return false; | 462 return false; |
| 463 } | 463 } |
| 464 | 464 |
| 465 HRESULT result = i_persist_file->Save(destination, TRUE); | 465 HRESULT result = i_persist_file->Save(destination, TRUE); |
| 466 return SUCCEEDED(result); | 466 return SUCCEEDED(result); |
| 467 } | 467 } |
| (...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 665 FILE* OpenFile(const FilePath& filename, const char* mode) { | 665 FILE* OpenFile(const FilePath& filename, const char* mode) { |
| 666 std::wstring w_mode = ASCIIToWide(std::string(mode)); | 666 std::wstring w_mode = ASCIIToWide(std::string(mode)); |
| 667 return _wfsopen(filename.value().c_str(), w_mode.c_str(), _SH_DENYNO); | 667 return _wfsopen(filename.value().c_str(), w_mode.c_str(), _SH_DENYNO); |
| 668 } | 668 } |
| 669 | 669 |
| 670 FILE* OpenFile(const std::string& filename, const char* mode) { | 670 FILE* OpenFile(const std::string& filename, const char* mode) { |
| 671 return _fsopen(filename.c_str(), mode, _SH_DENYNO); | 671 return _fsopen(filename.c_str(), mode, _SH_DENYNO); |
| 672 } | 672 } |
| 673 | 673 |
| 674 int ReadFile(const FilePath& filename, char* data, int size) { | 674 int ReadFile(const FilePath& filename, char* data, int size) { |
| 675 ScopedHandle file(CreateFile(filename.value().c_str(), | 675 base::win::ScopedHandle file(CreateFile(filename.value().c_str(), |
| 676 GENERIC_READ, | 676 GENERIC_READ, |
| 677 FILE_SHARE_READ | FILE_SHARE_WRITE, | 677 FILE_SHARE_READ | FILE_SHARE_WRITE, |
| 678 NULL, | 678 NULL, |
| 679 OPEN_EXISTING, | 679 OPEN_EXISTING, |
| 680 FILE_FLAG_SEQUENTIAL_SCAN, | 680 FILE_FLAG_SEQUENTIAL_SCAN, |
| 681 NULL)); | 681 NULL)); |
| 682 if (!file) | 682 if (!file) |
| 683 return -1; | 683 return -1; |
| 684 | 684 |
| 685 DWORD read; | 685 DWORD read; |
| 686 if (::ReadFile(file, data, size, &read, NULL) && | 686 if (::ReadFile(file, data, size, &read, NULL) && |
| 687 static_cast<int>(read) == size) | 687 static_cast<int>(read) == size) |
| 688 return read; | 688 return read; |
| 689 return -1; | 689 return -1; |
| 690 } | 690 } |
| 691 | 691 |
| 692 int WriteFile(const FilePath& filename, const char* data, int size) { | 692 int WriteFile(const FilePath& filename, const char* data, int size) { |
| 693 ScopedHandle file(CreateFile(filename.value().c_str(), | 693 base::win::ScopedHandle file(CreateFile(filename.value().c_str(), |
| 694 GENERIC_WRITE, | 694 GENERIC_WRITE, |
| 695 0, | 695 0, |
| 696 NULL, | 696 NULL, |
| 697 CREATE_ALWAYS, | 697 CREATE_ALWAYS, |
| 698 0, | 698 0, |
| 699 NULL)); | 699 NULL)); |
| 700 if (!file) { | 700 if (!file) { |
| 701 LOG(WARNING) << "CreateFile failed for path " << filename.value() << | 701 LOG(WARNING) << "CreateFile failed for path " << filename.value() << |
| 702 " error code=" << GetLastError() << | 702 " error code=" << GetLastError() << |
| 703 " error text=" << win_util::FormatLastWin32Error(); | 703 " error text=" << win_util::FormatLastWin32Error(); |
| 704 return -1; | 704 return -1; |
| 705 } | 705 } |
| 706 | 706 |
| 707 DWORD written; | 707 DWORD written; |
| 708 BOOL result = ::WriteFile(file, data, size, &written, NULL); | 708 BOOL result = ::WriteFile(file, data, size, &written, NULL); |
| 709 if (result && static_cast<int>(written) == size) | 709 if (result && static_cast<int>(written) == size) |
| (...skipping 241 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 951 // that we return a path starting with a drive letter. | 951 // that we return a path starting with a drive letter. |
| 952 return DevicePathToDriveLetterPath(mapped_file, real_path); | 952 return DevicePathToDriveLetterPath(mapped_file, real_path); |
| 953 } | 953 } |
| 954 | 954 |
| 955 bool NormalizeToNativeFilePath(const FilePath& path, FilePath* nt_path) { | 955 bool NormalizeToNativeFilePath(const FilePath& path, FilePath* nt_path) { |
| 956 // In Vista, GetFinalPathNameByHandle() would give us the real path | 956 // In Vista, GetFinalPathNameByHandle() would give us the real path |
| 957 // from a file handle. If we ever deprecate XP, consider changing the | 957 // from a file handle. If we ever deprecate XP, consider changing the |
| 958 // code below to a call to GetFinalPathNameByHandle(). The method this | 958 // code below to a call to GetFinalPathNameByHandle(). The method this |
| 959 // function uses is explained in the following msdn article: | 959 // function uses is explained in the following msdn article: |
| 960 // http://msdn.microsoft.com/en-us/library/aa366789(VS.85).aspx | 960 // http://msdn.microsoft.com/en-us/library/aa366789(VS.85).aspx |
| 961 ScopedHandle file_handle( | 961 base::win::ScopedHandle file_handle( |
| 962 ::CreateFile(path.value().c_str(), | 962 ::CreateFile(path.value().c_str(), |
| 963 GENERIC_READ, | 963 GENERIC_READ, |
| 964 kFileShareAll, | 964 kFileShareAll, |
| 965 NULL, | 965 NULL, |
| 966 OPEN_EXISTING, | 966 OPEN_EXISTING, |
| 967 FILE_ATTRIBUTE_NORMAL, | 967 FILE_ATTRIBUTE_NORMAL, |
| 968 NULL)); | 968 NULL)); |
| 969 if (!file_handle) | 969 if (!file_handle) |
| 970 return false; | 970 return false; |
| 971 | 971 |
| 972 // Create a file mapping object. Can't easily use MemoryMappedFile, because | 972 // Create a file mapping object. Can't easily use MemoryMappedFile, because |
| 973 // we only map the first byte, and need direct access to the handle. You can | 973 // we only map the first byte, and need direct access to the handle. You can |
| 974 // not map an empty file, this call fails in that case. | 974 // not map an empty file, this call fails in that case. |
| 975 ScopedHandle file_map_handle( | 975 base::win::ScopedHandle file_map_handle( |
| 976 ::CreateFileMapping(file_handle.Get(), | 976 ::CreateFileMapping(file_handle.Get(), |
| 977 NULL, | 977 NULL, |
| 978 PAGE_READONLY, | 978 PAGE_READONLY, |
| 979 0, | 979 0, |
| 980 1, // Just one byte. No need to look at the data. | 980 1, // Just one byte. No need to look at the data. |
| 981 NULL)); | 981 NULL)); |
| 982 if (!file_map_handle) | 982 if (!file_map_handle) |
| 983 return false; | 983 return false; |
| 984 | 984 |
| 985 // Use a view of the file to get the path to the file. | 985 // Use a view of the file to get the path to the file. |
| (...skipping 19 matching lines...) Expand all Loading... |
| 1005 ::UnmapViewOfFile(file_view); | 1005 ::UnmapViewOfFile(file_view); |
| 1006 return success; | 1006 return success; |
| 1007 } | 1007 } |
| 1008 | 1008 |
| 1009 bool PreReadImage(const wchar_t* file_path, size_t size_to_read, | 1009 bool PreReadImage(const wchar_t* file_path, size_t size_to_read, |
| 1010 size_t step_size) { | 1010 size_t step_size) { |
| 1011 if (base::win::GetVersion() > base::win::VERSION_XP) { | 1011 if (base::win::GetVersion() > base::win::VERSION_XP) { |
| 1012 // Vista+ branch. On these OSes, the forced reads through the DLL actually | 1012 // Vista+ branch. On these OSes, the forced reads through the DLL actually |
| 1013 // slows warm starts. The solution is to sequentially read file contents | 1013 // slows warm starts. The solution is to sequentially read file contents |
| 1014 // with an optional cap on total amount to read. | 1014 // with an optional cap on total amount to read. |
| 1015 ScopedHandle file( | 1015 base::win::ScopedHandle file( |
| 1016 CreateFile(file_path, | 1016 CreateFile(file_path, |
| 1017 GENERIC_READ, | 1017 GENERIC_READ, |
| 1018 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, | 1018 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, |
| 1019 NULL, | 1019 NULL, |
| 1020 OPEN_EXISTING, | 1020 OPEN_EXISTING, |
| 1021 FILE_FLAG_SEQUENTIAL_SCAN, | 1021 FILE_FLAG_SEQUENTIAL_SCAN, |
| 1022 NULL)); | 1022 NULL)); |
| 1023 | 1023 |
| 1024 if (!file.IsValid()) | 1024 if (!file.IsValid()) |
| 1025 return false; | 1025 return false; |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1065 uint8 unused = *(touch + offset); | 1065 uint8 unused = *(touch + offset); |
| 1066 offset += step_size; | 1066 offset += step_size; |
| 1067 } | 1067 } |
| 1068 FreeLibrary(dll_module); | 1068 FreeLibrary(dll_module); |
| 1069 } | 1069 } |
| 1070 | 1070 |
| 1071 return true; | 1071 return true; |
| 1072 } | 1072 } |
| 1073 | 1073 |
| 1074 } // namespace file_util | 1074 } // namespace file_util |
| OLD | NEW |