file_util_win.cc revision 5821806d5e7f356e8fa4b058a389a808ea183019
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/file_util.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <windows.h>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <psapi.h>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <shellapi.h>
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <shlobj.h>
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <time.h>
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <limits>
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string>
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/file_path.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/metrics/histogram.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/process_util.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/string_number_conversions.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/string_util.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/threading/thread_restrictions.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/time.h"
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/utf_string_conversions.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/scoped_handle.h"
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/windows_version.h"
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace file_util {
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const DWORD kFileShareAll =
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool AbsolutePath(FilePath* path) {
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::ThreadRestrictions::AssertIOAllowed();
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  wchar_t file_path_buf[MAX_PATH];
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!_wfullpath(file_path_buf, path->value().c_str(), MAX_PATH))
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *path = FilePath(file_path_buf);
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int CountFilesCreatedAfter(const FilePath& path,
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           const base::Time& comparison_time) {
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::ThreadRestrictions::AssertIOAllowed();
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int file_count = 0;
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FILETIME comparison_filetime(comparison_time.ToFileTime());
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WIN32_FIND_DATA find_file_data;
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // All files in given dir
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::wstring filename_spec = path.Append(L"*").value();
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HANDLE find_handle = FindFirstFile(filename_spec.c_str(), &find_file_data);
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (find_handle != INVALID_HANDLE_VALUE) {
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    do {
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Don't count current or parent directories.
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if ((wcscmp(find_file_data.cFileName, L"..") == 0) ||
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          (wcscmp(find_file_data.cFileName, L".") == 0))
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        continue;
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      long result = CompareFileTime(&find_file_data.ftCreationTime,  // NOLINT
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    &comparison_filetime);
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // File was created after or on comparison time
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if ((result == 1) || (result == 0))
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ++file_count;
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } while (FindNextFile(find_handle,  &find_file_data));
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FindClose(find_handle);
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return file_count;
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Delete(const FilePath& path, bool recursive) {
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::ThreadRestrictions::AssertIOAllowed();
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (path.value().length() >= MAX_PATH)
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!recursive) {
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If not recursing, then first check to see if |path| is a directory.
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If it is, then remove it with RemoveDirectory.
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::PlatformFileInfo file_info;
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (GetFileInfo(path, &file_info) && file_info.is_directory)
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return RemoveDirectory(path.value().c_str()) != 0;
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Otherwise, it's a file, wildcard or non-existant. Try DeleteFile first
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // because it should be faster. If DeleteFile fails, then we fall through
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // to SHFileOperation, which will do the right thing.
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (DeleteFile(path.value().c_str()) != 0)
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return true;
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // SHFILEOPSTRUCT wants the path to be terminated with two NULLs,
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // so we have to use wcscpy because wcscpy_s writes non-NULLs
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // into the rest of the buffer.
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  wchar_t double_terminated_path[MAX_PATH + 1] = {0};
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#pragma warning(suppress:4996)  // don't complain about wcscpy deprecation
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (g_bug108724_debug)
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(WARNING) << "copying ";
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  wcscpy(double_terminated_path, path.value().c_str());
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SHFILEOPSTRUCT file_operation = {0};
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  file_operation.wFunc = FO_DELETE;
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  file_operation.pFrom = double_terminated_path;
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  file_operation.fFlags = FOF_NOERRORUI | FOF_SILENT | FOF_NOCONFIRMATION;
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!recursive)
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    file_operation.fFlags |= FOF_NORECURSION | FOF_FILESONLY;
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (g_bug108724_debug)
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(WARNING) << "Performing shell operation";
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int err = SHFileOperation(&file_operation);
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (g_bug108724_debug)
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(WARNING) << "Done: " << err;
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Since we're passing flags to the operation telling it to be silent,
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // it's possible for the operation to be aborted/cancelled without err
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // being set (although MSDN doesn't give any scenarios for how this can
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // happen).  See MSDN for SHFileOperation and SHFILEOPTSTRUCT.
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (file_operation.fAnyOperationsAborted)
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Some versions of Windows return ERROR_FILE_NOT_FOUND (0x2) when deleting
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // an empty directory and some return 0x402 when they should be returning
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // ERROR_FILE_NOT_FOUND. MSDN says Vista and up won't return 0x402.
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (err == 0 || err == ERROR_FILE_NOT_FOUND || err == 0x402);
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DeleteAfterReboot(const FilePath& path) {
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::ThreadRestrictions::AssertIOAllowed();
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (path.value().length() >= MAX_PATH)
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return MoveFileEx(path.value().c_str(), NULL,
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    MOVEFILE_DELAY_UNTIL_REBOOT |
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        MOVEFILE_REPLACE_EXISTING) != FALSE;
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Move(const FilePath& from_path, const FilePath& to_path) {
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::ThreadRestrictions::AssertIOAllowed();
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // NOTE: I suspect we could support longer paths, but that would involve
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // analyzing all our usage of files.
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (from_path.value().length() >= MAX_PATH ||
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      to_path.value().length() >= MAX_PATH) {
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (MoveFileEx(from_path.value().c_str(), to_path.value().c_str(),
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING) != 0)
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Keep the last error value from MoveFileEx around in case the below
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // fails.
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool ret = false;
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DWORD last_error = ::GetLastError();
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (DirectoryExists(from_path)) {
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // MoveFileEx fails if moving directory across volumes. We will simulate
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // the move by using Copy and Delete. Ideally we could check whether
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // from_path and to_path are indeed in different volumes.
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ret = CopyAndDeleteDirectory(from_path, to_path);
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!ret) {
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Leave a clue about what went wrong so that it can be (at least) picked
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // up by a PLOG entry.
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ::SetLastError(last_error);
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ret;
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ReplaceFile(const FilePath& from_path, const FilePath& to_path) {
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::ThreadRestrictions::AssertIOAllowed();
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Try a simple move first.  It will only succeed when |to_path| doesn't
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // already exist.
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (::MoveFile(from_path.value().c_str(), to_path.value().c_str()))
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Try the full-blown replace if the move fails, as ReplaceFile will only
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // succeed when |to_path| does exist. When writing to a network share, we may
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // not be able to change the ACLs. Ignore ACL errors then
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // (REPLACEFILE_IGNORE_MERGE_ERRORS).
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (::ReplaceFile(to_path.value().c_str(), from_path.value().c_str(), NULL,
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    REPLACEFILE_IGNORE_MERGE_ERRORS, NULL, NULL)) {
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool CopyFile(const FilePath& from_path, const FilePath& to_path) {
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::ThreadRestrictions::AssertIOAllowed();
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // NOTE: I suspect we could support longer paths, but that would involve
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // analyzing all our usage of files.
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (from_path.value().length() >= MAX_PATH ||
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      to_path.value().length() >= MAX_PATH) {
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (::CopyFile(from_path.value().c_str(), to_path.value().c_str(),
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     false) != 0);
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ShellCopy(const FilePath& from_path, const FilePath& to_path,
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               bool recursive) {
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::ThreadRestrictions::AssertIOAllowed();
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // NOTE: I suspect we could support longer paths, but that would involve
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // analyzing all our usage of files.
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (from_path.value().length() >= MAX_PATH ||
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      to_path.value().length() >= MAX_PATH) {
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // SHFILEOPSTRUCT wants the path to be terminated with two NULLs,
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // so we have to use wcscpy because wcscpy_s writes non-NULLs
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // into the rest of the buffer.
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  wchar_t double_terminated_path_from[MAX_PATH + 1] = {0};
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  wchar_t double_terminated_path_to[MAX_PATH + 1] = {0};
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#pragma warning(suppress:4996)  // don't complain about wcscpy deprecation
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  wcscpy(double_terminated_path_from, from_path.value().c_str());
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#pragma warning(suppress:4996)  // don't complain about wcscpy deprecation
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  wcscpy(double_terminated_path_to, to_path.value().c_str());
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SHFILEOPSTRUCT file_operation = {0};
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  file_operation.wFunc = FO_COPY;
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  file_operation.pFrom = double_terminated_path_from;
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  file_operation.pTo = double_terminated_path_to;
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  file_operation.fFlags = FOF_NOERRORUI | FOF_SILENT | FOF_NOCONFIRMATION |
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          FOF_NOCONFIRMMKDIR;
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!recursive)
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    file_operation.fFlags |= FOF_NORECURSION | FOF_FILESONLY;
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (SHFileOperation(&file_operation) == 0);
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool CopyDirectory(const FilePath& from_path, const FilePath& to_path,
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   bool recursive) {
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::ThreadRestrictions::AssertIOAllowed();
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (recursive)
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ShellCopy(from_path, to_path, true);
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The following code assumes that from path is a directory.
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(DirectoryExists(from_path));
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Instead of creating a new directory, we copy the old one to include the
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // security information of the folder as part of the copy.
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!PathExists(to_path)) {
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Except that Vista fails to do that, and instead do a recursive copy if
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // the target directory doesn't exist.
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (base::win::GetVersion() >= base::win::VERSION_VISTA)
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      CreateDirectory(to_path);
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ShellCopy(from_path, to_path, false);
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FilePath directory = from_path.Append(L"*.*");
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ShellCopy(directory, to_path, false);
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool CopyAndDeleteDirectory(const FilePath& from_path,
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            const FilePath& to_path) {
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::ThreadRestrictions::AssertIOAllowed();
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (CopyDirectory(from_path, to_path, true)) {
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (Delete(from_path, true)) {
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return true;
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Like Move, this function is not transactional, so we just
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // leave the copied bits behind if deleting from_path fails.
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If to_path exists previously then we have already overwritten
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // it by now, we don't get better off by deleting the new bits.
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool PathExists(const FilePath& path) {
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::ThreadRestrictions::AssertIOAllowed();
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (GetFileAttributes(path.value().c_str()) != INVALID_FILE_ATTRIBUTES);
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool PathIsWritable(const FilePath& path) {
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::ThreadRestrictions::AssertIOAllowed();
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HANDLE dir =
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      CreateFile(path.value().c_str(), FILE_ADD_FILE, kFileShareAll,
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (dir == INVALID_HANDLE_VALUE)
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CloseHandle(dir);
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DirectoryExists(const FilePath& path) {
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::ThreadRestrictions::AssertIOAllowed();
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DWORD fileattr = GetFileAttributes(path.value().c_str());
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (fileattr != INVALID_FILE_ATTRIBUTES)
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return (fileattr & FILE_ATTRIBUTE_DIRECTORY) != 0;
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool GetFileCreationLocalTimeFromHandle(HANDLE file_handle,
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                        LPSYSTEMTIME creation_time) {
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::ThreadRestrictions::AssertIOAllowed();
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!file_handle)
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FILETIME utc_filetime;
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!GetFileTime(file_handle, &utc_filetime, NULL, NULL))
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FILETIME local_filetime;
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!FileTimeToLocalFileTime(&utc_filetime, &local_filetime))
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return !!FileTimeToSystemTime(&local_filetime, creation_time);
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool GetFileCreationLocalTime(const std::wstring& filename,
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              LPSYSTEMTIME creation_time) {
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::ThreadRestrictions::AssertIOAllowed();
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::win::ScopedHandle file_handle(
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      CreateFile(filename.c_str(), GENERIC_READ, kFileShareAll, NULL,
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL));
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return GetFileCreationLocalTimeFromHandle(file_handle.Get(), creation_time);
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool GetTempDir(FilePath* path) {
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::ThreadRestrictions::AssertIOAllowed();
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  wchar_t temp_path[MAX_PATH + 1];
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DWORD path_len = ::GetTempPath(MAX_PATH, temp_path);
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (path_len >= MAX_PATH || path_len <= 0)
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(evanm): the old behavior of this function was to always strip the
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // trailing slash.  We duplicate this here, but it shouldn't be necessary
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // when everyone is using the appropriate FilePath APIs.
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *path = FilePath(temp_path).StripTrailingSeparators();
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool GetShmemTempDir(FilePath* path, bool executable) {
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return GetTempDir(path);
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool CreateTemporaryFile(FilePath* path) {
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::ThreadRestrictions::AssertIOAllowed();
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FilePath temp_file;
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!GetTempDir(path))
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (CreateTemporaryFileInDir(*path, &temp_file)) {
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *path = temp_file;
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)FILE* CreateAndOpenTemporaryShmemFile(FilePath* path, bool executable) {
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::ThreadRestrictions::AssertIOAllowed();
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return CreateAndOpenTemporaryFile(path);
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// On POSIX we have semantics to create and open a temporary file
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// atomically.
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(jrg): is there equivalent call to use on Windows instead of
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// going 2-step?
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)FILE* CreateAndOpenTemporaryFileInDir(const FilePath& dir, FilePath* path) {
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::ThreadRestrictions::AssertIOAllowed();
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!CreateTemporaryFileInDir(dir, path)) {
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Open file in binary mode, to avoid problems with fwrite. On Windows
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // it replaces \n's with \r\n's, which may surprise you.
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Reference: http://msdn.microsoft.com/en-us/library/h9t88zwz(VS.71).aspx
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return OpenFile(*path, "wb+");
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool CreateTemporaryFileInDir(const FilePath& dir,
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              FilePath* temp_file) {
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::ThreadRestrictions::AssertIOAllowed();
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  wchar_t temp_name[MAX_PATH + 1];
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!GetTempFileName(dir.value().c_str(), L"", 0, temp_name)) {
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DPLOG(WARNING) << "Failed to get temporary file name in " << dir.value();
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DWORD path_len = GetLongPathName(temp_name, temp_name, MAX_PATH);
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (path_len > MAX_PATH + 1 || path_len == 0) {
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DPLOG(WARNING) << "Failed to get long path name for " << temp_name;
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::wstring temp_file_str;
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  temp_file_str.assign(temp_name, path_len);
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *temp_file = FilePath(temp_file_str);
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool CreateTemporaryDirInDir(const FilePath& base_dir,
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             const FilePath::StringType& prefix,
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             FilePath* new_dir) {
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::ThreadRestrictions::AssertIOAllowed();
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FilePath path_to_create;
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  srand(static_cast<uint32>(time(NULL)));
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int count = 0; count < 50; ++count) {
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Try create a new temporary directory with random generated name. If
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // the one exists, keep trying another path name until we reach some limit.
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    string16 new_dir_name;
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    new_dir_name.assign(prefix);
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    new_dir_name.append(base::IntToString16(::base::GetCurrentProcId()));
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    new_dir_name.push_back('_');
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    new_dir_name.append(base::IntToString16(rand() % kint16max));
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    path_to_create = base_dir.Append(new_dir_name);
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (::CreateDirectory(path_to_create.value().c_str(), NULL)) {
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      *new_dir = path_to_create;
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return true;
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool CreateNewTempDirectory(const FilePath::StringType& prefix,
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            FilePath* new_temp_path) {
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::ThreadRestrictions::AssertIOAllowed();
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FilePath system_temp_dir;
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!GetTempDir(&system_temp_dir))
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return CreateTemporaryDirInDir(system_temp_dir, prefix, new_temp_path);
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool CreateDirectory(const FilePath& full_path) {
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::ThreadRestrictions::AssertIOAllowed();
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the path exists, we've succeeded if it's a directory, failed otherwise.
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const wchar_t* full_path_str = full_path.value().c_str();
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DWORD fileattr = ::GetFileAttributes(full_path_str);
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (fileattr != INVALID_FILE_ATTRIBUTES) {
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if ((fileattr & FILE_ATTRIBUTE_DIRECTORY) != 0) {
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DVLOG(1) << "CreateDirectory(" << full_path_str << "), "
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               << "directory already exists.";
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return true;
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DLOG(WARNING) << "CreateDirectory(" << full_path_str << "), "
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  << "conflicts with existing file.";
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Invariant:  Path does not exist as file or directory.
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Attempt to create the parent recursively.  This will immediately return
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // true if it already exists, otherwise will create all required parent
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // directories starting with the highest-level missing parent.
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FilePath parent_path(full_path.DirName());
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (parent_path.value() == full_path.value()) {
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!CreateDirectory(parent_path)) {
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DLOG(WARNING) << "Failed to create one of the parent directories.";
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!::CreateDirectory(full_path_str, NULL)) {
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DWORD error_code = ::GetLastError();
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (error_code == ERROR_ALREADY_EXISTS && DirectoryExists(full_path)) {
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // This error code ERROR_ALREADY_EXISTS doesn't indicate whether we
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // were racing with someone creating the same directory, or a file
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // with the same path.  If DirectoryExists() returns true, we lost the
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // race to create the same directory.
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return true;
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DLOG(WARNING) << "Failed to create directory " << full_path_str
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    << ", last error is " << error_code << ".";
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(rkc): Work out if we want to handle NTFS junctions here or not, handle
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// them if we do decide to.
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool IsLink(const FilePath& file_path) {
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool GetFileInfo(const FilePath& file_path, base::PlatformFileInfo* results) {
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::ThreadRestrictions::AssertIOAllowed();
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WIN32_FILE_ATTRIBUTE_DATA attr;
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!GetFileAttributesEx(file_path.value().c_str(),
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           GetFileExInfoStandard, &attr)) {
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ULARGE_INTEGER size;
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size.HighPart = attr.nFileSizeHigh;
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size.LowPart = attr.nFileSizeLow;
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  results->size = size.QuadPart;
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  results->is_directory =
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (attr.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  results->last_modified = base::Time::FromFileTime(attr.ftLastWriteTime);
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  results->last_accessed = base::Time::FromFileTime(attr.ftLastAccessTime);
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  results->creation_time = base::Time::FromFileTime(attr.ftCreationTime);
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)FILE* OpenFile(const FilePath& filename, const char* mode) {
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::ThreadRestrictions::AssertIOAllowed();
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::wstring w_mode = ASCIIToWide(std::string(mode));
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return _wfsopen(filename.value().c_str(), w_mode.c_str(), _SH_DENYNO);
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)FILE* OpenFile(const std::string& filename, const char* mode) {
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::ThreadRestrictions::AssertIOAllowed();
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return _fsopen(filename.c_str(), mode, _SH_DENYNO);
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int ReadFile(const FilePath& filename, char* data, int size) {
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::ThreadRestrictions::AssertIOAllowed();
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::win::ScopedHandle file(CreateFile(filename.value().c_str(),
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          GENERIC_READ,
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          FILE_SHARE_READ | FILE_SHARE_WRITE,
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          NULL,
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          OPEN_EXISTING,
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          FILE_FLAG_SEQUENTIAL_SCAN,
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          NULL));
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!file)
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return -1;
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DWORD read;
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (::ReadFile(file, data, size, &read, NULL) &&
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      static_cast<int>(read) == size)
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return read;
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return -1;
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int WriteFile(const FilePath& filename, const char* data, int size) {
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::ThreadRestrictions::AssertIOAllowed();
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::win::ScopedHandle file(CreateFile(filename.value().c_str(),
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          GENERIC_WRITE,
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          0,
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          NULL,
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          CREATE_ALWAYS,
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          0,
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          NULL));
5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!file) {
5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DLOG(WARNING) << "CreateFile failed for path " << filename.value()
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  << " error code=" << GetLastError();
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return -1;
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DWORD written;
5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BOOL result = ::WriteFile(file, data, size, &written, NULL);
5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (result && static_cast<int>(written) == size)
5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return written;
5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!result) {
5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // WriteFile failed.
5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DLOG(WARNING) << "writing file " << filename.value()
5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  << " failed, error code=" << GetLastError();
5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Didn't write all the bytes.
5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DLOG(WARNING) << "wrote" << written << " bytes to "
5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  << filename.value() << " expected " << size;
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return -1;
5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int AppendToFile(const FilePath& filename, const char* data, int size) {
5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::ThreadRestrictions::AssertIOAllowed();
5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::win::ScopedHandle file(CreateFile(filename.value().c_str(),
5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          FILE_APPEND_DATA,
5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          0,
5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          NULL,
5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          OPEN_EXISTING,
5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          0,
5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          NULL));
5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!file) {
5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DLOG(WARNING) << "CreateFile failed for path " << filename.value()
5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  << " error code=" << GetLastError();
5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return -1;
5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DWORD written;
6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BOOL result = ::WriteFile(file, data, size, &written, NULL);
6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (result && static_cast<int>(written) == size)
6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return written;
6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!result) {
6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // WriteFile failed.
6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DLOG(WARNING) << "writing file " << filename.value()
6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  << " failed, error code=" << GetLastError();
6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Didn't write all the bytes.
6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DLOG(WARNING) << "wrote" << written << " bytes to "
6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  << filename.value() << " expected " << size;
6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return -1;
6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Gets the current working directory for the process.
6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool GetCurrentDirectory(FilePath* dir) {
6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::ThreadRestrictions::AssertIOAllowed();
6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  wchar_t system_buffer[MAX_PATH];
6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  system_buffer[0] = 0;
6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DWORD len = ::GetCurrentDirectory(MAX_PATH, system_buffer);
6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (len == 0 || len > MAX_PATH)
6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(evanm): the old behavior of this function was to always strip the
6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // trailing slash.  We duplicate this here, but it shouldn't be necessary
6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // when everyone is using the appropriate FilePath APIs.
6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::wstring dir_str(system_buffer);
6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *dir = FilePath(dir_str).StripTrailingSeparators();
6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Sets the current working directory for the process.
6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SetCurrentDirectory(const FilePath& directory) {
6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::ThreadRestrictions::AssertIOAllowed();
6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BOOL ret = ::SetCurrentDirectory(directory.value().c_str());
6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ret != 0;
6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)///////////////////////////////////////////////
6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// FileEnumerator
6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)FileEnumerator::FileEnumerator(const FilePath& root_path,
6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               bool recursive,
6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               int file_type)
6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : recursive_(recursive),
6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      file_type_(file_type),
6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      has_find_data_(false),
6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      find_handle_(INVALID_HANDLE_VALUE) {
6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // INCLUDE_DOT_DOT must not be specified if recursive.
6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!(recursive && (INCLUDE_DOT_DOT & file_type_)));
6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  memset(&find_data_, 0, sizeof(find_data_));
6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pending_paths_.push(root_path);
6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)FileEnumerator::FileEnumerator(const FilePath& root_path,
6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               bool recursive,
6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               int file_type,
6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               const FilePath::StringType& pattern)
6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : recursive_(recursive),
6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      file_type_(file_type),
6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      has_find_data_(false),
6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pattern_(pattern),
6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      find_handle_(INVALID_HANDLE_VALUE) {
6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // INCLUDE_DOT_DOT must not be specified if recursive.
6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!(recursive && (INCLUDE_DOT_DOT & file_type_)));
6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  memset(&find_data_, 0, sizeof(find_data_));
6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pending_paths_.push(root_path);
6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)FileEnumerator::~FileEnumerator() {
6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (find_handle_ != INVALID_HANDLE_VALUE)
6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FindClose(find_handle_);
6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FileEnumerator::GetFindInfo(FindInfo* info) {
6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(info);
6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!has_find_data_)
6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  memcpy(info, &find_data_, sizeof(*info));
6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool FileEnumerator::IsDirectory(const FindInfo& info) {
6895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
6905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
6935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)FilePath FileEnumerator::GetFilename(const FindInfo& find_info) {
6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return FilePath(find_info.cFileName);
6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int64 FileEnumerator::GetFilesize(const FindInfo& find_info) {
6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ULARGE_INTEGER size;
7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size.HighPart = find_info.nFileSizeHigh;
7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size.LowPart = find_info.nFileSizeLow;
7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_LE(size.QuadPart, std::numeric_limits<int64>::max());
7035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return static_cast<int64>(size.QuadPart);
7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
7075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)base::Time FileEnumerator::GetLastModifiedTime(const FindInfo& find_info) {
7085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return base::Time::FromFileTime(find_info.ftLastWriteTime);
7095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)FilePath FileEnumerator::Next() {
7125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::ThreadRestrictions::AssertIOAllowed();
7135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (has_find_data_ || !pending_paths_.empty()) {
7155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!has_find_data_) {
7165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // The last find FindFirstFile operation is done, prepare a new one.
7175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      root_path_ = pending_paths_.top();
7185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pending_paths_.pop();
7195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Start a new find operation.
7215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FilePath src = root_path_;
7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (pattern_.empty())
7245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        src = src.Append(L"*");  // No pattern = match everything.
7255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      else
7265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        src = src.Append(pattern_);
7275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      find_handle_ = FindFirstFile(src.value().c_str(), &find_data_);
7295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      has_find_data_ = true;
7305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
7315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Search for the next file/directory.
7325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!FindNextFile(find_handle_, &find_data_)) {
7335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        FindClose(find_handle_);
7345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        find_handle_ = INVALID_HANDLE_VALUE;
7355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
7365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
7375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (INVALID_HANDLE_VALUE == find_handle_) {
7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      has_find_data_ = false;
7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // This is reached when we have finished a directory and are advancing to
7425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // the next one in the queue. We applied the pattern (if any) to the files
7435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // in the root search directory, but for those directories which were
7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // matched, we want to enumerate all files inside them. This will happen
7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // when the handle is empty.
7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pattern_ = FilePath::StringType();
7475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
7495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
7505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FilePath cur_file(find_data_.cFileName);
7525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (ShouldSkip(cur_file))
7535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
7545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Construct the absolute filename.
7565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cur_file = root_path_.Append(find_data_.cFileName);
7575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (find_data_.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
7595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (recursive_) {
7605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // If |cur_file| is a directory, and we are doing recursive searching,
7615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // add it to pending_paths_ so we scan it after we finish scanning this
7625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // directory.
7635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        pending_paths_.push(cur_file);
7645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
7655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (file_type_ & FileEnumerator::DIRECTORIES)
7665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return cur_file;
7675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else if (file_type_ & FileEnumerator::FILES) {
7685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return cur_file;
7695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
7705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return FilePath();
7735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)///////////////////////////////////////////////
7765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// MemoryMappedFile
7775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MemoryMappedFile::MemoryMappedFile()
7795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : file_(INVALID_HANDLE_VALUE),
7805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      file_mapping_(INVALID_HANDLE_VALUE),
7815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      data_(NULL),
7825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      length_(INVALID_FILE_SIZE) {
7835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool MemoryMappedFile::InitializeAsImageSection(const FilePath& file_name) {
7865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (IsValid())
7875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
7885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  file_ = base::CreatePlatformFile(
7895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      file_name, base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ,
7905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NULL, NULL);
7915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (file_ == base::kInvalidPlatformFileValue) {
7935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DLOG(ERROR) << "Couldn't open " << file_name.value();
7945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
7955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!MapFileToMemoryInternalEx(SEC_IMAGE)) {
7985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CloseHandles();
7995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
8005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
8035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool MemoryMappedFile::MapFileToMemoryInternal() {
8065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return MapFileToMemoryInternalEx(0);
8075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool MemoryMappedFile::MapFileToMemoryInternalEx(int flags) {
8105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::ThreadRestrictions::AssertIOAllowed();
8115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (file_ == INVALID_HANDLE_VALUE)
8135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
8145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  length_ = ::GetFileSize(file_, NULL);
8165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (length_ == INVALID_FILE_SIZE)
8175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
8185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  file_mapping_ = ::CreateFileMapping(file_, NULL, PAGE_READONLY | flags,
8205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      0, 0, NULL);
8215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!file_mapping_) {
8225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // According to msdn, system error codes are only reserved up to 15999.
8235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // http://msdn.microsoft.com/en-us/library/ms681381(v=VS.85).aspx.
8245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UMA_HISTOGRAM_ENUMERATION("MemoryMappedFile.CreateFileMapping",
8255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              logging::GetLastSystemErrorCode(), 16000);
8265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
8275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  data_ = static_cast<uint8*>(
8305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ::MapViewOfFile(file_mapping_, FILE_MAP_READ, 0, 0, 0));
8315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!data_) {
8325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UMA_HISTOGRAM_ENUMERATION("MemoryMappedFile.MapViewOfFile",
8335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              logging::GetLastSystemErrorCode(), 16000);
8345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return data_ != NULL;
8365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void MemoryMappedFile::CloseHandles() {
8395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (data_)
8405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ::UnmapViewOfFile(data_);
8415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (file_mapping_ != INVALID_HANDLE_VALUE)
8425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ::CloseHandle(file_mapping_);
8435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (file_ != INVALID_HANDLE_VALUE)
8445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ::CloseHandle(file_);
8455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  data_ = NULL;
8475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  file_mapping_ = file_ = INVALID_HANDLE_VALUE;
8485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  length_ = INVALID_FILE_SIZE;
8495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HasFileBeenModifiedSince(const FileEnumerator::FindInfo& find_info,
8525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              const base::Time& cutoff_time) {
8535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::ThreadRestrictions::AssertIOAllowed();
8545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FILETIME file_time = cutoff_time.ToFileTime();
8555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  long result = CompareFileTime(&find_info.ftLastWriteTime,  // NOLINT
8565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                &file_time);
8575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return result == 1 || result == 0;
8585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool NormalizeFilePath(const FilePath& path, FilePath* real_path) {
8615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::ThreadRestrictions::AssertIOAllowed();
8625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FilePath mapped_file;
8635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!NormalizeToNativeFilePath(path, &mapped_file))
8645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
8655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // NormalizeToNativeFilePath() will return a path that starts with
8665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // "\Device\Harddisk...".  Helper DevicePathToDriveLetterPath()
8675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // will find a drive letter which maps to the path's device, so
8685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // that we return a path starting with a drive letter.
8695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return DevicePathToDriveLetterPath(mapped_file, real_path);
8705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DevicePathToDriveLetterPath(const FilePath& nt_device_path,
8735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 FilePath* out_drive_letter_path) {
8745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::ThreadRestrictions::AssertIOAllowed();
8755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get the mapping of drive letters to device paths.
8775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int kDriveMappingSize = 1024;
8785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  wchar_t drive_mapping[kDriveMappingSize] = {'\0'};
8795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!::GetLogicalDriveStrings(kDriveMappingSize - 1, drive_mapping)) {
8805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DLOG(ERROR) << "Failed to get drive mapping.";
8815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
8825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The drive mapping is a sequence of null terminated strings.
8855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The last string is empty.
8865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  wchar_t* drive_map_ptr = drive_mapping;
8875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  wchar_t device_path_as_string[MAX_PATH];
8885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  wchar_t drive[] = L" :";
8895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // For each string in the drive mapping, get the junction that links
8915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // to it.  If that junction is a prefix of |device_path|, then we
8925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // know that |drive| is the real path prefix.
8935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (*drive_map_ptr) {
8945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    drive[0] = drive_map_ptr[0];  // Copy the drive letter.
8955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (QueryDosDevice(drive, device_path_as_string, MAX_PATH)) {
8975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FilePath device_path(device_path_as_string);
8985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (device_path == nt_device_path ||
8995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          device_path.IsParent(nt_device_path)) {
9005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        *out_drive_letter_path = FilePath(drive +
9015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            nt_device_path.value().substr(wcslen(device_path_as_string)));
9025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return true;
9035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
9045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
9055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Move to the next drive letter string, which starts one
9065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // increment after the '\0' that terminates the current string.
9075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    while (*drive_map_ptr++);
9085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // No drive matched.  The path does not start with a device junction
9115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // that is mounted as a drive letter.  This means there is no drive
9125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // letter path to the volume that holds |device_path|, so fail.
9135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
9145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool NormalizeToNativeFilePath(const FilePath& path, FilePath* nt_path) {
9175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::ThreadRestrictions::AssertIOAllowed();
9185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // In Vista, GetFinalPathNameByHandle() would give us the real path
9195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // from a file handle.  If we ever deprecate XP, consider changing the
9205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // code below to a call to GetFinalPathNameByHandle().  The method this
9215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // function uses is explained in the following msdn article:
9225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // http://msdn.microsoft.com/en-us/library/aa366789(VS.85).aspx
9235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::win::ScopedHandle file_handle(
9245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ::CreateFile(path.value().c_str(),
9255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   GENERIC_READ,
9265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   kFileShareAll,
9275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   NULL,
9285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   OPEN_EXISTING,
9295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   FILE_ATTRIBUTE_NORMAL,
9305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   NULL));
9315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!file_handle)
9325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
9335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Create a file mapping object.  Can't easily use MemoryMappedFile, because
9355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // we only map the first byte, and need direct access to the handle. You can
9365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // not map an empty file, this call fails in that case.
9375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::win::ScopedHandle file_map_handle(
9385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ::CreateFileMapping(file_handle.Get(),
9395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          NULL,
9405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          PAGE_READONLY,
9415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          0,
9425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          1,  // Just one byte.  No need to look at the data.
9435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          NULL));
9445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!file_map_handle)
9455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
9465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Use a view of the file to get the path to the file.
9485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void* file_view = MapViewOfFile(file_map_handle.Get(),
9495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  FILE_MAP_READ, 0, 0, 1);
9505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!file_view)
9515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
9525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The expansion of |path| into a full path may make it longer.
9545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // GetMappedFileName() will fail if the result is longer than MAX_PATH.
9555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Pad a bit to be safe.  If kMaxPathLength is ever changed to be less
9565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // than MAX_PATH, it would be nessisary to test that GetMappedFileName()
9575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // not return kMaxPathLength.  This would mean that only part of the
9585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // path fit in |mapped_file_path|.
9595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int kMaxPathLength = MAX_PATH + 10;
9605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  wchar_t mapped_file_path[kMaxPathLength];
9615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool success = false;
9625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HANDLE cp = GetCurrentProcess();
9635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (::GetMappedFileNameW(cp, file_view, mapped_file_path, kMaxPathLength)) {
9645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *nt_path = FilePath(mapped_file_path);
9655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    success = true;
9665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ::UnmapViewOfFile(file_view);
9685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return success;
9695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace file_util
972