summaryrefslogtreecommitdiffstats
path: root/base/file_util_win.cc
diff options
context:
space:
mode:
authorerikkay@google.com <erikkay@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2008-08-06 16:29:44 +0000
committererikkay@google.com <erikkay@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2008-08-06 16:29:44 +0000
commit1010f7d1107f4df30be4a6d97ddeead2d4f3e585 (patch)
treea8ded6f98184a8a817412f1589109c8d88c9326c /base/file_util_win.cc
parent355cc27400bd3d128314f7203232cbb04c501cf2 (diff)
downloadchromium_src-1010f7d1107f4df30be4a6d97ddeead2d4f3e585.zip
chromium_src-1010f7d1107f4df30be4a6d97ddeead2d4f3e585.tar.gz
chromium_src-1010f7d1107f4df30be4a6d97ddeead2d4f3e585.tar.bz2
Refactoring file_util into file_util and file_util_win. Also fix windows dependencies in path_service.cc.
One questionable decision here was to put GetCurrentDirectory and SetCurrentDirectory into file_util_win.cc. I could have kept the logic in path_service.cc with #ifdefs or I could have split up path_service.cc into path_service_win.cc, etc. git-svn-id: svn://svn.chromium.org/chrome/trunk/src@436 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base/file_util_win.cc')
-rw-r--r--base/file_util_win.cc647
1 files changed, 647 insertions, 0 deletions
diff --git a/base/file_util_win.cc b/base/file_util_win.cc
new file mode 100644
index 0000000..a9d0b0b
--- /dev/null
+++ b/base/file_util_win.cc
@@ -0,0 +1,647 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "base/file_util.h"
+
+#include <windows.h>
+#include <shellapi.h>
+#include <shlobj.h>
+#include <time.h>
+#include <string>
+
+#include "base/logging.h"
+#include "base/scoped_handle.h"
+#include "base/string_util.h"
+#include "base/win_util.h"
+
+namespace file_util {
+
+int CountFilesCreatedAfter(const std::wstring& path,
+ const FILETIME& comparison_time) {
+ int file_count = 0;
+
+ WIN32_FIND_DATA find_file_data;
+ std::wstring filename_spec = path + L"\\*"; // All files in given dir
+ HANDLE find_handle = FindFirstFile(filename_spec.c_str(), &find_file_data);
+ if (find_handle != INVALID_HANDLE_VALUE) {
+ do {
+ // Don't count current or parent directories.
+ if ((wcscmp(find_file_data.cFileName, L"..") == 0) ||
+ (wcscmp(find_file_data.cFileName, L".") == 0))
+ continue;
+
+ long result = CompareFileTime(&find_file_data.ftCreationTime,
+ &comparison_time);
+ // File was created after or on comparison time
+ if ((result == 1) || (result == 0))
+ ++file_count;
+ } while (FindNextFile(find_handle, &find_file_data));
+ FindClose(find_handle);
+ }
+
+ return file_count;
+}
+
+bool Delete(const std::wstring& path, bool recursive) {
+ if (path.length() >= MAX_PATH)
+ return false;
+
+ // If we're not recursing use DeleteFile; it should be faster. DeleteFile
+ // fails if passed a directory though, which is why we fall through on
+ // failure to the SHFileOperation.
+ if (!recursive && DeleteFile(path.c_str()) != 0)
+ return true;
+
+ // SHFILEOPSTRUCT wants the path to be terminated with two NULLs,
+ // so we have to use wcscpy because wcscpy_s writes non-NULLs
+ // into the rest of the buffer.
+ wchar_t double_terminated_path[MAX_PATH + 1] = {0};
+#pragma warning(suppress:4996) // don't complain about wcscpy deprecation
+ wcscpy(double_terminated_path, path.c_str());
+
+ SHFILEOPSTRUCT file_operation = {0};
+ file_operation.wFunc = FO_DELETE;
+ file_operation.pFrom = double_terminated_path;
+ file_operation.fFlags = FOF_NOERRORUI | FOF_SILENT | FOF_NOCONFIRMATION;
+ if (!recursive)
+ file_operation.fFlags |= FOF_NORECURSION | FOF_FILESONLY;
+ return (SHFileOperation(&file_operation) == 0);
+}
+
+bool Move(const std::wstring& from_path, const std::wstring& to_path) {
+ // NOTE: I suspect we could support longer paths, but that would involve
+ // analyzing all our usage of files.
+ if (from_path.length() >= MAX_PATH || to_path.length() >= MAX_PATH)
+ return false;
+ return (MoveFileEx(from_path.c_str(), to_path.c_str(),
+ MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING) != 0);
+}
+
+bool CopyFile(const std::wstring& from_path, const std::wstring& to_path) {
+ // NOTE: I suspect we could support longer paths, but that would involve
+ // analyzing all our usage of files.
+ if (from_path.length() >= MAX_PATH || to_path.length() >= MAX_PATH)
+ return false;
+ return (::CopyFile(from_path.c_str(), to_path.c_str(), false) != 0);
+}
+
+bool ShellCopy(const std::wstring& from_path, const std::wstring& to_path,
+ bool recursive) {
+ // NOTE: I suspect we could support longer paths, but that would involve
+ // analyzing all our usage of files.
+ if (from_path.length() >= MAX_PATH || to_path.length() >= MAX_PATH)
+ return false;
+
+ // SHFILEOPSTRUCT wants the path to be terminated with two NULLs,
+ // so we have to use wcscpy because wcscpy_s writes non-NULLs
+ // into the rest of the buffer.
+ wchar_t double_terminated_path_from[MAX_PATH + 1] = {0};
+ wchar_t double_terminated_path_to[MAX_PATH + 1] = {0};
+#pragma warning(suppress:4996) // don't complain about wcscpy deprecation
+ wcscpy(double_terminated_path_from, from_path.c_str());
+#pragma warning(suppress:4996) // don't complain about wcscpy deprecation
+ wcscpy(double_terminated_path_to, to_path.c_str());
+
+ SHFILEOPSTRUCT file_operation = {0};
+ file_operation.wFunc = FO_COPY;
+ file_operation.pFrom = double_terminated_path_from;
+ file_operation.pTo = double_terminated_path_to;
+ file_operation.fFlags = FOF_NOERRORUI | FOF_SILENT | FOF_NOCONFIRMATION |
+ FOF_NOCONFIRMMKDIR;
+ if (!recursive)
+ file_operation.fFlags |= FOF_NORECURSION | FOF_FILESONLY;
+
+ return (SHFileOperation(&file_operation) == 0);
+}
+
+bool CopyDirectory(const std::wstring& from_path, const std::wstring& to_path,
+ bool recursive) {
+ if (recursive)
+ return ShellCopy(from_path, to_path, true);
+
+ // Instead of creating a new directory, we copy the old one to include the
+ // security information of the folder as part of the copy.
+ if (!PathExists(to_path)) {
+ // Except that Vista fails to do that, and instead do a recursive copy if
+ // the target directory doesn't exist.
+ if (win_util::GetWinVersion() >= win_util::WINVERSION_VISTA)
+ CreateDirectory(to_path);
+ else
+ ShellCopy(from_path, to_path, false);
+ }
+
+ std::wstring directory(from_path);
+ AppendToPath(&directory, L"*.*");
+ return ShellCopy(directory, to_path, false);
+}
+
+bool PathExists(const std::wstring& path) {
+ return (GetFileAttributes(path.c_str()) != INVALID_FILE_ATTRIBUTES);
+}
+
+bool PathIsWritable(const std::wstring& path) {
+ HANDLE dir =
+ CreateFile(path.c_str(), FILE_ADD_FILE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+
+ if (dir == INVALID_HANDLE_VALUE)
+ return false;
+
+ CloseHandle(dir);
+ return true;
+}
+
+bool GetFileCreationLocalTimeFromHandle(HANDLE file_handle,
+ LPSYSTEMTIME creation_time) {
+ if (!file_handle)
+ return false;
+
+ FILETIME utc_filetime;
+ if (!GetFileTime(file_handle, &utc_filetime, NULL, NULL))
+ return false;
+
+ FILETIME local_filetime;
+ if (!FileTimeToLocalFileTime(&utc_filetime, &local_filetime))
+ return false;
+
+ return !!FileTimeToSystemTime(&local_filetime, creation_time);
+}
+
+bool GetFileCreationLocalTime(const std::wstring& filename,
+ LPSYSTEMTIME creation_time) {
+ ScopedHandle file_handle(
+ CreateFile(filename.c_str(), GENERIC_READ,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
+ OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL));
+ return GetFileCreationLocalTimeFromHandle(file_handle.Get(), creation_time);
+}
+
+bool ResolveShortcut(std::wstring* path) {
+ HRESULT result;
+ IShellLink *shell = NULL;
+ bool is_resolved = false;
+
+ // Get pointer to the IShellLink interface
+ result = CoCreateInstance(CLSID_ShellLink, NULL,
+ CLSCTX_INPROC_SERVER, IID_IShellLink,
+ reinterpret_cast<LPVOID*>(&shell));
+ if (SUCCEEDED(result)) {
+ IPersistFile *persist = NULL;
+ // Query IShellLink for the IPersistFile interface
+ result = shell->QueryInterface(IID_IPersistFile,
+ reinterpret_cast<LPVOID*>(&persist));
+ if (SUCCEEDED(result)) {
+ WCHAR temp_path[MAX_PATH];
+ // Load the shell link
+ result = persist->Load(path->c_str(), STGM_READ);
+ if (SUCCEEDED(result)) {
+ // Try to find the target of a shortcut
+ result = shell->Resolve(0, SLR_NO_UI);
+ if (SUCCEEDED(result)) {
+ result = shell->GetPath(temp_path, MAX_PATH,
+ NULL, SLGP_UNCPRIORITY);
+ *path = temp_path;
+ is_resolved = true;
+ }
+ }
+ }
+ if (persist)
+ persist->Release();
+ }
+ if (shell)
+ shell->Release();
+
+ return is_resolved;
+}
+
+bool CreateShortcutLink(const wchar_t *source, const wchar_t *destination,
+ const wchar_t *working_dir, const wchar_t *arguments,
+ const wchar_t *description, const wchar_t *icon,
+ int icon_index) {
+ IShellLink *i_shell_link = NULL;
+ IPersistFile *i_persist_file = NULL;
+
+ // Get pointer to the IShellLink interface
+ HRESULT result = CoCreateInstance(CLSID_ShellLink, NULL,
+ CLSCTX_INPROC_SERVER, IID_IShellLink,
+ reinterpret_cast<LPVOID*>(&i_shell_link));
+ if (FAILED(result))
+ return false;
+
+ // Query IShellLink for the IPersistFile interface
+ result = i_shell_link->QueryInterface(IID_IPersistFile,
+ reinterpret_cast<LPVOID*>(&i_persist_file));
+ if (FAILED(result)) {
+ i_shell_link->Release();
+ return false;
+ }
+
+ if (FAILED(i_shell_link->SetPath(source))) {
+ i_persist_file->Release();
+ i_shell_link->Release();
+ return false;
+ }
+
+ if (working_dir && FAILED(i_shell_link->SetWorkingDirectory(working_dir))) {
+ i_persist_file->Release();
+ i_shell_link->Release();
+ return false;
+ }
+
+ if (arguments && FAILED(i_shell_link->SetArguments(arguments))) {
+ i_persist_file->Release();
+ i_shell_link->Release();
+ return false;
+ }
+
+ if (description && FAILED(i_shell_link->SetDescription(description))) {
+ i_persist_file->Release();
+ i_shell_link->Release();
+ return false;
+ }
+
+ if (icon && FAILED(i_shell_link->SetIconLocation(icon, icon_index))) {
+ i_persist_file->Release();
+ i_shell_link->Release();
+ return false;
+ }
+
+ result = i_persist_file->Save(destination, TRUE);
+ i_persist_file->Release();
+ i_shell_link->Release();
+ return SUCCEEDED(result);
+}
+
+
+bool UpdateShortcutLink(const wchar_t *source, const wchar_t *destination,
+ const wchar_t *working_dir, const wchar_t *arguments,
+ const wchar_t *description, const wchar_t *icon,
+ int icon_index) {
+ // Get pointer to the IPersistFile interface and load existing link
+ IShellLink *i_shell_link = NULL;
+ if (FAILED(CoCreateInstance(CLSID_ShellLink, NULL,
+ CLSCTX_INPROC_SERVER, IID_IShellLink,
+ reinterpret_cast<LPVOID*>(&i_shell_link))))
+ return false;
+
+ IPersistFile *i_persist_file = NULL;
+ if (FAILED(i_shell_link->QueryInterface(
+ IID_IPersistFile, reinterpret_cast<LPVOID*>(&i_persist_file)))) {
+ i_shell_link->Release();
+ return false;
+ }
+
+ if (FAILED(i_persist_file->Load(destination, 0))) {
+ i_persist_file->Release();
+ i_shell_link->Release();
+ return false;
+ }
+
+ if (source && FAILED(i_shell_link->SetPath(source))) {
+ i_persist_file->Release();
+ i_shell_link->Release();
+ return false;
+ }
+
+ if (working_dir && FAILED(i_shell_link->SetWorkingDirectory(working_dir))) {
+ i_persist_file->Release();
+ i_shell_link->Release();
+ return false;
+ }
+
+ if (arguments && FAILED(i_shell_link->SetArguments(arguments))) {
+ i_persist_file->Release();
+ i_shell_link->Release();
+ return false;
+ }
+
+ if (description && FAILED(i_shell_link->SetDescription(description))) {
+ i_persist_file->Release();
+ i_shell_link->Release();
+ return false;
+ }
+
+ if (icon && FAILED(i_shell_link->SetIconLocation(icon, icon_index))) {
+ i_persist_file->Release();
+ i_shell_link->Release();
+ return false;
+ }
+
+ HRESULT result = i_persist_file->Save(destination, TRUE);
+ i_persist_file->Release();
+ i_shell_link->Release();
+ return SUCCEEDED(result);
+}
+
+bool GetTempDir(std::wstring* path) {
+ wchar_t temp_path[MAX_PATH + 1];
+ DWORD path_len = ::GetTempPath(MAX_PATH, temp_path);
+ if (path_len >= MAX_PATH || path_len <= 0)
+ return false;
+ path->assign(temp_path);
+ TrimTrailingSeparator(path);
+ return true;
+}
+
+bool CreateTemporaryFileName(std::wstring* temp_file) {
+ wchar_t temp_name[MAX_PATH + 1];
+ std::wstring temp_path;
+
+ if (!GetTempDir(&temp_path))
+ return false;
+
+ if (!GetTempFileName(temp_path.c_str(), L"", 0, temp_name))
+ return false; // fail!
+
+ DWORD path_len = GetLongPathName(temp_name, temp_name, MAX_PATH);
+ if (path_len > MAX_PATH + 1 || path_len == 0)
+ return false; // fail!
+
+ temp_file->assign(temp_name, path_len);
+ return true;
+}
+
+bool CreateNewTempDirectory(const std::wstring& prefix,
+ std::wstring* new_temp_path) {
+ std::wstring system_temp_dir;
+ if (!GetTempDir(&system_temp_dir))
+ return false;
+
+ std::wstring path_to_create;
+ srand(static_cast<uint32>(time(NULL)));
+
+ int count = 0;
+ while (count < 50) {
+ // Try create a new temporary directory with random generated name. If
+ // the one exists, keep trying another path name until we reach some limit.
+ path_to_create.assign(system_temp_dir);
+ std::wstring new_dir_name;
+ new_dir_name.assign(prefix);
+ new_dir_name.append(IntToWString(rand() % kint16max));
+ file_util::AppendToPath(&path_to_create, new_dir_name);
+
+ if (::CreateDirectory(path_to_create.c_str(), NULL))
+ break;
+ count++;
+ }
+
+ if (count == 50) {
+ return false;
+ }
+
+ new_temp_path->assign(path_to_create);
+ return true;
+}
+
+bool CreateDirectory(const std::wstring& full_path) {
+ int err = SHCreateDirectoryEx(NULL, full_path.c_str(), NULL);
+ return err == ERROR_SUCCESS;
+}
+
+bool GetFileSize(const std::wstring& file_path, int64* file_size) {
+ ScopedHandle file_handle(
+ CreateFile(file_path.c_str(), GENERIC_READ,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
+ OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL));
+
+ LARGE_INTEGER win32_file_size = {0};
+ if (!GetFileSizeEx(file_handle, &win32_file_size)) {
+ return false;
+ }
+
+ *file_size = win32_file_size.QuadPart;
+ return true;
+}
+
+int ReadFile(const std::wstring& filename, char* data, int size) {
+ ScopedHandle file(CreateFile(filename.c_str(),
+ GENERIC_READ,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_SEQUENTIAL_SCAN,
+ NULL));
+ if (file == INVALID_HANDLE_VALUE)
+ return -1;
+
+ int ret_value;
+ DWORD read;
+ if (::ReadFile(file, data, size, &read, NULL) && read == size) {
+ ret_value = static_cast<int>(read);
+ } else {
+ ret_value = -1;
+ }
+
+ return ret_value;
+}
+
+int WriteFile(const std::wstring& filename, const char* data, int size) {
+ ScopedHandle file(CreateFile(filename.c_str(),
+ GENERIC_WRITE,
+ 0,
+ NULL,
+ CREATE_ALWAYS,
+ 0,
+ NULL));
+ if (file == INVALID_HANDLE_VALUE)
+ return -1;
+
+ int ret_value;
+ DWORD written;
+ if (::WriteFile(file, data, size, &written, NULL) && written == size) {
+ ret_value = static_cast<int>(written);
+ } else {
+ ret_value = -1;
+ }
+
+ return ret_value;
+}
+
+bool RenameFileAndResetSecurityDescriptor(
+ const std::wstring& source_file_path,
+ const std::wstring& target_file_path) {
+ // The MoveFile API does not reset the security descriptor on the target
+ // file. To ensure that the target file gets the correct security descriptor
+ // we create the target file initially in the target path, read its security
+ // descriptor and stamp this descriptor on the target file after the MoveFile
+ // API completes.
+ ScopedHandle temp_file_handle_for_security_desc(
+ CreateFileW(target_file_path.c_str(), GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ, NULL, OPEN_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE,
+ NULL));
+ if (!temp_file_handle_for_security_desc.IsValid())
+ return false;
+
+ // Check how much we should allocate for the security descriptor.
+ unsigned long security_descriptor_size_in_bytes = 0;
+ GetFileSecurity(target_file_path.c_str(), DACL_SECURITY_INFORMATION, NULL, 0,
+ &security_descriptor_size_in_bytes);
+ if (ERROR_INSUFFICIENT_BUFFER != GetLastError() ||
+ security_descriptor_size_in_bytes == 0)
+ return false;
+
+ scoped_array<char> security_descriptor(
+ new char[security_descriptor_size_in_bytes]);
+
+ if (!GetFileSecurity(target_file_path.c_str(), DACL_SECURITY_INFORMATION,
+ security_descriptor.get(),
+ security_descriptor_size_in_bytes,
+ &security_descriptor_size_in_bytes)) {
+ return false;
+ }
+
+ temp_file_handle_for_security_desc.Set(INVALID_HANDLE_VALUE);
+
+ if (!MoveFileEx(source_file_path.c_str(), target_file_path.c_str(),
+ MOVEFILE_COPY_ALLOWED)) {
+ return false;
+ }
+
+ return !!SetFileSecurity(target_file_path.c_str(),
+ DACL_SECURITY_INFORMATION,
+ security_descriptor.get());
+}
+
+// Gets the current working directory for the process.
+bool GetCurrentDirectory(std::wstring* dir) {
+ wchar_t system_buffer[MAX_PATH];
+ system_buffer[0] = 0;
+ DWORD len = ::GetCurrentDirectory(MAX_PATH, system_buffer);
+ if (len == 0 || len > MAX_PATH)
+ return false;
+ *dir = system_buffer;
+ file_util::TrimTrailingSeparator(dir);
+ return true;
+}
+
+// Sets the current working directory for the process.
+bool SetCurrentDirectory(const std::wstring& current_directory) {
+ BOOL ret = ::SetCurrentDirectory(current_directory.c_str());
+ return (ret ? true : false);
+}
+
+///////////////////////////////////////////////
+
+
+FileEnumerator::FileEnumerator(const std::wstring& root_path,
+ bool recursive,
+ FileEnumerator::FILE_TYPE file_type)
+ : recursive_(recursive),
+ file_type_(file_type),
+ is_in_find_op_(false),
+ find_handle_(INVALID_HANDLE_VALUE) {
+ pending_paths_.push(root_path);
+}
+
+FileEnumerator::FileEnumerator(const std::wstring& root_path,
+ bool recursive,
+ FileEnumerator::FILE_TYPE file_type,
+ const std::wstring& pattern)
+ : recursive_(recursive),
+ file_type_(file_type),
+ is_in_find_op_(false),
+ pattern_(pattern),
+ find_handle_(INVALID_HANDLE_VALUE) {
+ pending_paths_.push(root_path);
+}
+
+FileEnumerator::~FileEnumerator() {
+ if (find_handle_ != INVALID_HANDLE_VALUE)
+ FindClose(find_handle_);
+}
+
+std::wstring FileEnumerator::Next() {
+ if (!is_in_find_op_) {
+ if (pending_paths_.empty())
+ return std::wstring();
+
+ // The last find FindFirstFile operation is done, prepare a new one.
+ // root_path_ must have the trailing directory character.
+ root_path_ = pending_paths_.top();
+ file_util::AppendToPath(&root_path_, std::wstring());
+ pending_paths_.pop();
+
+ // Start a new find operation.
+ std::wstring src(root_path_);
+
+ if (pattern_.empty())
+ file_util::AppendToPath(&src, L"*"); // No pattern = match everything.
+ else
+ file_util::AppendToPath(&src, pattern_);
+
+ find_handle_ = FindFirstFile(src.c_str(), &find_data_);
+ is_in_find_op_ = true;
+
+ } else {
+ // Search for the next file/directory.
+ if (!FindNextFile(find_handle_, &find_data_)) {
+ FindClose(find_handle_);
+ find_handle_ = INVALID_HANDLE_VALUE;
+ }
+ }
+
+ if (INVALID_HANDLE_VALUE == find_handle_) {
+ is_in_find_op_ = false;
+
+ // This is reached when we have finished a directory and are advancing to
+ // the next one in the queue. We applied the pattern (if any) to the files
+ // in the root search directory, but for those directories which were
+ // matched, we want to enumerate all files inside them. This will happen
+ // when the handle is empty.
+ pattern_.clear();
+
+ return Next();
+ }
+
+ std::wstring cur_file(find_data_.cFileName);
+ // Skip over . and ..
+ if (L"." == cur_file || L".." == cur_file)
+ return Next();
+
+ // Construct the absolute filename.
+ cur_file.insert(0, root_path_);
+
+ if (find_data_.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
+ if (recursive_) {
+ // If |cur_file| is a directory, and we are doing recursive searching, add
+ // it to pending_paths_ so we scan it after we finish scanning this
+ // directory.
+ pending_paths_.push(cur_file);
+ return (file_type_ & FileEnumerator::DIRECTORIES) ? cur_file : Next();
+ }
+
+ if ((file_type_ & FileEnumerator::DIRECTORIES) == 0)
+ return Next();
+ }
+ return (file_type_ & FileEnumerator::FILES) ? cur_file : Next();
+}
+
+} // namespace