blob: 9d775f0bb452fe7d42c545f0efb4da4c5f84a5b7 [file] [log] [blame]
license.botbf09a502008-08-24 00:55:551// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
[email protected]1010f7d2008-08-06 16:29:444
5#include "base/file_util.h"
6
7#include <windows.h>
8#include <shellapi.h>
9#include <shlobj.h>
10#include <time.h>
11#include <string>
12
13#include "base/logging.h"
14#include "base/scoped_handle.h"
15#include "base/string_util.h"
16#include "base/win_util.h"
17
18namespace file_util {
19
[email protected]4c0040c2008-08-15 01:04:1120const wchar_t kPathSeparator = L'\\';
21
[email protected]5af2edb92008-08-08 20:16:0822std::wstring GetDirectoryFromPath(const std::wstring& path) {
23 wchar_t path_buffer[MAX_PATH];
24 wchar_t* file_ptr = NULL;
25 if (GetFullPathName(path.c_str(), MAX_PATH, path_buffer, &file_ptr) == 0)
26 return L"";
27
28 std::wstring::size_type length =
29 file_ptr ? file_ptr - path_buffer : path.length();
30 std::wstring directory(path, 0, length);
31 TrimTrailingSeparator(&directory);
32 return directory;
33}
[email protected]1265917f2008-08-12 17:33:5234
35bool AbsolutePath(std::wstring* path) {
36 wchar_t file_path_buf[MAX_PATH];
37 if (!_wfullpath(file_path_buf, path->c_str(), MAX_PATH))
38 return false;
39 *path = file_path_buf;
40 return true;
41}
[email protected]5af2edb92008-08-08 20:16:0842
[email protected]1010f7d2008-08-06 16:29:4443int CountFilesCreatedAfter(const std::wstring& path,
44 const FILETIME& comparison_time) {
45 int file_count = 0;
46
47 WIN32_FIND_DATA find_file_data;
48 std::wstring filename_spec = path + L"\\*"; // All files in given dir
49 HANDLE find_handle = FindFirstFile(filename_spec.c_str(), &find_file_data);
50 if (find_handle != INVALID_HANDLE_VALUE) {
51 do {
52 // Don't count current or parent directories.
53 if ((wcscmp(find_file_data.cFileName, L"..") == 0) ||
54 (wcscmp(find_file_data.cFileName, L".") == 0))
55 continue;
56
57 long result = CompareFileTime(&find_file_data.ftCreationTime,
58 &comparison_time);
59 // File was created after or on comparison time
60 if ((result == 1) || (result == 0))
61 ++file_count;
62 } while (FindNextFile(find_handle, &find_file_data));
63 FindClose(find_handle);
64 }
65
66 return file_count;
67}
68
69bool Delete(const std::wstring& path, bool recursive) {
70 if (path.length() >= MAX_PATH)
71 return false;
72
73 // If we're not recursing use DeleteFile; it should be faster. DeleteFile
74 // fails if passed a directory though, which is why we fall through on
75 // failure to the SHFileOperation.
76 if (!recursive && DeleteFile(path.c_str()) != 0)
77 return true;
78
79 // SHFILEOPSTRUCT wants the path to be terminated with two NULLs,
80 // so we have to use wcscpy because wcscpy_s writes non-NULLs
81 // into the rest of the buffer.
82 wchar_t double_terminated_path[MAX_PATH + 1] = {0};
83#pragma warning(suppress:4996) // don't complain about wcscpy deprecation
84 wcscpy(double_terminated_path, path.c_str());
85
86 SHFILEOPSTRUCT file_operation = {0};
87 file_operation.wFunc = FO_DELETE;
88 file_operation.pFrom = double_terminated_path;
89 file_operation.fFlags = FOF_NOERRORUI | FOF_SILENT | FOF_NOCONFIRMATION;
90 if (!recursive)
91 file_operation.fFlags |= FOF_NORECURSION | FOF_FILESONLY;
92 return (SHFileOperation(&file_operation) == 0);
93}
94
95bool Move(const std::wstring& from_path, const std::wstring& to_path) {
96 // NOTE: I suspect we could support longer paths, but that would involve
97 // analyzing all our usage of files.
98 if (from_path.length() >= MAX_PATH || to_path.length() >= MAX_PATH)
99 return false;
100 return (MoveFileEx(from_path.c_str(), to_path.c_str(),
101 MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING) != 0);
102}
103
104bool CopyFile(const std::wstring& from_path, const std::wstring& to_path) {
105 // NOTE: I suspect we could support longer paths, but that would involve
106 // analyzing all our usage of files.
107 if (from_path.length() >= MAX_PATH || to_path.length() >= MAX_PATH)
108 return false;
109 return (::CopyFile(from_path.c_str(), to_path.c_str(), false) != 0);
110}
111
112bool ShellCopy(const std::wstring& from_path, const std::wstring& to_path,
113 bool recursive) {
114 // NOTE: I suspect we could support longer paths, but that would involve
115 // analyzing all our usage of files.
116 if (from_path.length() >= MAX_PATH || to_path.length() >= MAX_PATH)
117 return false;
118
119 // SHFILEOPSTRUCT wants the path to be terminated with two NULLs,
120 // so we have to use wcscpy because wcscpy_s writes non-NULLs
121 // into the rest of the buffer.
122 wchar_t double_terminated_path_from[MAX_PATH + 1] = {0};
123 wchar_t double_terminated_path_to[MAX_PATH + 1] = {0};
124#pragma warning(suppress:4996) // don't complain about wcscpy deprecation
125 wcscpy(double_terminated_path_from, from_path.c_str());
126#pragma warning(suppress:4996) // don't complain about wcscpy deprecation
127 wcscpy(double_terminated_path_to, to_path.c_str());
128
129 SHFILEOPSTRUCT file_operation = {0};
130 file_operation.wFunc = FO_COPY;
131 file_operation.pFrom = double_terminated_path_from;
132 file_operation.pTo = double_terminated_path_to;
133 file_operation.fFlags = FOF_NOERRORUI | FOF_SILENT | FOF_NOCONFIRMATION |
134 FOF_NOCONFIRMMKDIR;
135 if (!recursive)
136 file_operation.fFlags |= FOF_NORECURSION | FOF_FILESONLY;
137
138 return (SHFileOperation(&file_operation) == 0);
139}
140
141bool CopyDirectory(const std::wstring& from_path, const std::wstring& to_path,
142 bool recursive) {
143 if (recursive)
144 return ShellCopy(from_path, to_path, true);
145
146 // Instead of creating a new directory, we copy the old one to include the
147 // security information of the folder as part of the copy.
148 if (!PathExists(to_path)) {
149 // Except that Vista fails to do that, and instead do a recursive copy if
150 // the target directory doesn't exist.
151 if (win_util::GetWinVersion() >= win_util::WINVERSION_VISTA)
152 CreateDirectory(to_path);
153 else
154 ShellCopy(from_path, to_path, false);
155 }
156
157 std::wstring directory(from_path);
158 AppendToPath(&directory, L"*.*");
159 return ShellCopy(directory, to_path, false);
160}
161
162bool PathExists(const std::wstring& path) {
163 return (GetFileAttributes(path.c_str()) != INVALID_FILE_ATTRIBUTES);
164}
165
166bool PathIsWritable(const std::wstring& path) {
167 HANDLE dir =
168 CreateFile(path.c_str(), FILE_ADD_FILE,
169 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
170 NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
171
172 if (dir == INVALID_HANDLE_VALUE)
173 return false;
174
175 CloseHandle(dir);
176 return true;
177}
178
[email protected]806b9c62008-09-11 16:09:11179bool DirectoryExists(const std::wstring& path) {
180 DWORD fileattr = GetFileAttributes(path.c_str());
181 if (fileattr != INVALID_FILE_ATTRIBUTES)
182 return (fileattr & FILE_ATTRIBUTE_DIRECTORY) != 0;
183 return false;
184}
185
[email protected]1010f7d2008-08-06 16:29:44186bool GetFileCreationLocalTimeFromHandle(HANDLE file_handle,
187 LPSYSTEMTIME creation_time) {
188 if (!file_handle)
189 return false;
190
191 FILETIME utc_filetime;
192 if (!GetFileTime(file_handle, &utc_filetime, NULL, NULL))
193 return false;
194
195 FILETIME local_filetime;
196 if (!FileTimeToLocalFileTime(&utc_filetime, &local_filetime))
197 return false;
198
199 return !!FileTimeToSystemTime(&local_filetime, creation_time);
200}
201
202bool GetFileCreationLocalTime(const std::wstring& filename,
203 LPSYSTEMTIME creation_time) {
204 ScopedHandle file_handle(
205 CreateFile(filename.c_str(), GENERIC_READ,
206 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
207 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL));
208 return GetFileCreationLocalTimeFromHandle(file_handle.Get(), creation_time);
209}
210
211bool ResolveShortcut(std::wstring* path) {
212 HRESULT result;
213 IShellLink *shell = NULL;
214 bool is_resolved = false;
215
216 // Get pointer to the IShellLink interface
217 result = CoCreateInstance(CLSID_ShellLink, NULL,
218 CLSCTX_INPROC_SERVER, IID_IShellLink,
219 reinterpret_cast<LPVOID*>(&shell));
220 if (SUCCEEDED(result)) {
221 IPersistFile *persist = NULL;
222 // Query IShellLink for the IPersistFile interface
223 result = shell->QueryInterface(IID_IPersistFile,
224 reinterpret_cast<LPVOID*>(&persist));
225 if (SUCCEEDED(result)) {
226 WCHAR temp_path[MAX_PATH];
227 // Load the shell link
228 result = persist->Load(path->c_str(), STGM_READ);
229 if (SUCCEEDED(result)) {
230 // Try to find the target of a shortcut
231 result = shell->Resolve(0, SLR_NO_UI);
232 if (SUCCEEDED(result)) {
233 result = shell->GetPath(temp_path, MAX_PATH,
234 NULL, SLGP_UNCPRIORITY);
235 *path = temp_path;
236 is_resolved = true;
237 }
238 }
239 }
240 if (persist)
241 persist->Release();
242 }
243 if (shell)
244 shell->Release();
245
246 return is_resolved;
247}
248
249bool CreateShortcutLink(const wchar_t *source, const wchar_t *destination,
250 const wchar_t *working_dir, const wchar_t *arguments,
251 const wchar_t *description, const wchar_t *icon,
252 int icon_index) {
253 IShellLink *i_shell_link = NULL;
254 IPersistFile *i_persist_file = NULL;
255
256 // Get pointer to the IShellLink interface
257 HRESULT result = CoCreateInstance(CLSID_ShellLink, NULL,
258 CLSCTX_INPROC_SERVER, IID_IShellLink,
259 reinterpret_cast<LPVOID*>(&i_shell_link));
260 if (FAILED(result))
261 return false;
262
263 // Query IShellLink for the IPersistFile interface
264 result = i_shell_link->QueryInterface(IID_IPersistFile,
265 reinterpret_cast<LPVOID*>(&i_persist_file));
266 if (FAILED(result)) {
267 i_shell_link->Release();
268 return false;
269 }
270
271 if (FAILED(i_shell_link->SetPath(source))) {
272 i_persist_file->Release();
273 i_shell_link->Release();
274 return false;
275 }
276
277 if (working_dir && FAILED(i_shell_link->SetWorkingDirectory(working_dir))) {
278 i_persist_file->Release();
279 i_shell_link->Release();
280 return false;
281 }
282
283 if (arguments && FAILED(i_shell_link->SetArguments(arguments))) {
284 i_persist_file->Release();
285 i_shell_link->Release();
286 return false;
287 }
288
289 if (description && FAILED(i_shell_link->SetDescription(description))) {
290 i_persist_file->Release();
291 i_shell_link->Release();
292 return false;
293 }
294
295 if (icon && FAILED(i_shell_link->SetIconLocation(icon, icon_index))) {
296 i_persist_file->Release();
297 i_shell_link->Release();
298 return false;
299 }
300
301 result = i_persist_file->Save(destination, TRUE);
302 i_persist_file->Release();
303 i_shell_link->Release();
304 return SUCCEEDED(result);
305}
306
307
308bool UpdateShortcutLink(const wchar_t *source, const wchar_t *destination,
309 const wchar_t *working_dir, const wchar_t *arguments,
310 const wchar_t *description, const wchar_t *icon,
311 int icon_index) {
312 // Get pointer to the IPersistFile interface and load existing link
313 IShellLink *i_shell_link = NULL;
314 if (FAILED(CoCreateInstance(CLSID_ShellLink, NULL,
315 CLSCTX_INPROC_SERVER, IID_IShellLink,
316 reinterpret_cast<LPVOID*>(&i_shell_link))))
317 return false;
318
319 IPersistFile *i_persist_file = NULL;
320 if (FAILED(i_shell_link->QueryInterface(
321 IID_IPersistFile, reinterpret_cast<LPVOID*>(&i_persist_file)))) {
322 i_shell_link->Release();
323 return false;
324 }
325
326 if (FAILED(i_persist_file->Load(destination, 0))) {
327 i_persist_file->Release();
328 i_shell_link->Release();
329 return false;
330 }
331
332 if (source && FAILED(i_shell_link->SetPath(source))) {
333 i_persist_file->Release();
334 i_shell_link->Release();
335 return false;
336 }
337
338 if (working_dir && FAILED(i_shell_link->SetWorkingDirectory(working_dir))) {
339 i_persist_file->Release();
340 i_shell_link->Release();
341 return false;
342 }
343
344 if (arguments && FAILED(i_shell_link->SetArguments(arguments))) {
345 i_persist_file->Release();
346 i_shell_link->Release();
347 return false;
348 }
349
350 if (description && FAILED(i_shell_link->SetDescription(description))) {
351 i_persist_file->Release();
352 i_shell_link->Release();
353 return false;
354 }
355
356 if (icon && FAILED(i_shell_link->SetIconLocation(icon, icon_index))) {
357 i_persist_file->Release();
358 i_shell_link->Release();
359 return false;
360 }
361
362 HRESULT result = i_persist_file->Save(destination, TRUE);
363 i_persist_file->Release();
364 i_shell_link->Release();
365 return SUCCEEDED(result);
366}
367
[email protected]4b636fa72008-10-08 17:15:52368bool IsDirectoryEmpty(const std::wstring& dir_path) {
369 FileEnumerator files(dir_path, false, FileEnumerator::FILES_AND_DIRECTORIES);
370 if (files.Next().empty())
371 return true;
372 return false;
373}
374
[email protected]1010f7d2008-08-06 16:29:44375bool GetTempDir(std::wstring* path) {
376 wchar_t temp_path[MAX_PATH + 1];
377 DWORD path_len = ::GetTempPath(MAX_PATH, temp_path);
378 if (path_len >= MAX_PATH || path_len <= 0)
379 return false;
380 path->assign(temp_path);
381 TrimTrailingSeparator(path);
382 return true;
383}
384
385bool CreateTemporaryFileName(std::wstring* temp_file) {
[email protected]1010f7d2008-08-06 16:29:44386 std::wstring temp_path;
387
388 if (!GetTempDir(&temp_path))
389 return false;
390
[email protected]9ccbb372008-10-10 18:50:32391 return CreateTemporaryFileNameInDir(temp_path, temp_file);
392}
393
394bool CreateTemporaryFileNameInDir(const std::wstring& dir,
395 std::wstring* temp_file) {
396 wchar_t temp_name[MAX_PATH + 1];
397
398 if (!GetTempFileName(dir.c_str(), L"", 0, temp_name))
[email protected]1010f7d2008-08-06 16:29:44399 return false; // fail!
400
401 DWORD path_len = GetLongPathName(temp_name, temp_name, MAX_PATH);
402 if (path_len > MAX_PATH + 1 || path_len == 0)
403 return false; // fail!
404
405 temp_file->assign(temp_name, path_len);
406 return true;
407}
408
409bool CreateNewTempDirectory(const std::wstring& prefix,
410 std::wstring* new_temp_path) {
411 std::wstring system_temp_dir;
412 if (!GetTempDir(&system_temp_dir))
413 return false;
414
415 std::wstring path_to_create;
416 srand(static_cast<uint32>(time(NULL)));
417
418 int count = 0;
419 while (count < 50) {
420 // Try create a new temporary directory with random generated name. If
421 // the one exists, keep trying another path name until we reach some limit.
422 path_to_create.assign(system_temp_dir);
423 std::wstring new_dir_name;
424 new_dir_name.assign(prefix);
425 new_dir_name.append(IntToWString(rand() % kint16max));
426 file_util::AppendToPath(&path_to_create, new_dir_name);
427
428 if (::CreateDirectory(path_to_create.c_str(), NULL))
429 break;
430 count++;
431 }
432
433 if (count == 50) {
434 return false;
435 }
436
437 new_temp_path->assign(path_to_create);
438 return true;
439}
440
441bool CreateDirectory(const std::wstring& full_path) {
[email protected]806b9c62008-09-11 16:09:11442 if (DirectoryExists(full_path))
[email protected]81569622008-09-09 22:35:16443 return true;
[email protected]1010f7d2008-08-06 16:29:44444 int err = SHCreateDirectoryEx(NULL, full_path.c_str(), NULL);
445 return err == ERROR_SUCCESS;
446}
447
[email protected]f5e3da4d2008-09-26 01:04:08448bool GetFileInfo(const std::wstring& file_path, FileInfo* results) {
449 WIN32_FILE_ATTRIBUTE_DATA attr;
450 if (!GetFileAttributesEx(file_path.c_str(), GetFileExInfoStandard, &attr))
[email protected]1010f7d2008-08-06 16:29:44451 return false;
[email protected]1010f7d2008-08-06 16:29:44452
[email protected]f5e3da4d2008-09-26 01:04:08453 ULARGE_INTEGER size;
454 size.HighPart = attr.nFileSizeHigh;
455 size.LowPart = attr.nFileSizeLow;
456 results->size = size.QuadPart;
457
458 results->is_directory =
459 (attr.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
[email protected]1010f7d2008-08-06 16:29:44460 return true;
461}
462
[email protected]836f1342008-10-01 17:40:13463FILE* OpenFile(const std::string& filename, const char* mode) {
464 FILE* file;
465 if (fopen_s(&file, filename.c_str(), mode) != 0) {
466 return NULL;
467 }
468 return file;
469}
470
471FILE* OpenFile(const std::wstring& filename, const char* mode) {
472 std::wstring w_mode = ASCIIToWide(std::string(mode));
473 FILE* file;
474 if (_wfopen_s(&file, filename.c_str(), w_mode.c_str()) != 0) {
475 return NULL;
476 }
477 return file;
478}
479
[email protected]1010f7d2008-08-06 16:29:44480int ReadFile(const std::wstring& filename, char* data, int size) {
481 ScopedHandle file(CreateFile(filename.c_str(),
482 GENERIC_READ,
483 FILE_SHARE_READ | FILE_SHARE_WRITE,
484 NULL,
485 OPEN_EXISTING,
486 FILE_FLAG_SEQUENTIAL_SCAN,
487 NULL));
488 if (file == INVALID_HANDLE_VALUE)
489 return -1;
490
491 int ret_value;
492 DWORD read;
493 if (::ReadFile(file, data, size, &read, NULL) && read == size) {
494 ret_value = static_cast<int>(read);
495 } else {
496 ret_value = -1;
497 }
498
499 return ret_value;
500}
501
502int WriteFile(const std::wstring& filename, const char* data, int size) {
503 ScopedHandle file(CreateFile(filename.c_str(),
504 GENERIC_WRITE,
505 0,
506 NULL,
507 CREATE_ALWAYS,
508 0,
509 NULL));
[email protected]3b95b862008-09-17 17:00:04510 if (file == INVALID_HANDLE_VALUE) {
511 LOG(WARNING) << "CreateFile failed for path " << filename <<
512 " error code=" << GetLastError() <<
513 " error text=" << win_util::FormatLastWin32Error();
[email protected]1010f7d2008-08-06 16:29:44514 return -1;
[email protected]1010f7d2008-08-06 16:29:44515 }
516
[email protected]3b95b862008-09-17 17:00:04517 DWORD written;
518 BOOL result = ::WriteFile(file, data, size, &written, NULL);
519 if (result && written == size)
520 return static_cast<int>(written);
521
522 if (!result) {
523 // WriteFile failed.
524 LOG(WARNING) << "writing file " << filename <<
525 " failed, error code=" << GetLastError() <<
526 " description=" << win_util::FormatLastWin32Error();
527 } else {
528 // Didn't write all the bytes.
529 LOG(WARNING) << "wrote" << written << " bytes to " << filename <<
530 " expected " << size;
531 }
532 return -1;
[email protected]1010f7d2008-08-06 16:29:44533}
534
535bool RenameFileAndResetSecurityDescriptor(
536 const std::wstring& source_file_path,
537 const std::wstring& target_file_path) {
[email protected]ce16adb52008-10-27 14:41:51538 // The parameters to SHFileOperation must be terminated with 2 NULL chars.
539 std::wstring source = source_file_path;
540 std::wstring target = target_file_path;
[email protected]1010f7d2008-08-06 16:29:44541
[email protected]ce16adb52008-10-27 14:41:51542 source.append(1, L'\0');
543 target.append(1, L'\0');
[email protected]1010f7d2008-08-06 16:29:44544
[email protected]ce16adb52008-10-27 14:41:51545 SHFILEOPSTRUCT move_info = {0};
546 move_info.wFunc = FO_MOVE;
547 move_info.pFrom = source.c_str();
548 move_info.pTo = target.c_str();
549 move_info.fFlags = FOF_SILENT | FOF_NOCONFIRMATION | FOF_NOERRORUI |
550 FOF_NOCONFIRMMKDIR | FOF_NOCOPYSECURITYATTRIBS;
[email protected]1010f7d2008-08-06 16:29:44551
[email protected]ce16adb52008-10-27 14:41:51552 if (0 != SHFileOperation(&move_info))
553 return false;
554
555 return true;
[email protected]1010f7d2008-08-06 16:29:44556}
557
558// Gets the current working directory for the process.
559bool GetCurrentDirectory(std::wstring* dir) {
560 wchar_t system_buffer[MAX_PATH];
561 system_buffer[0] = 0;
562 DWORD len = ::GetCurrentDirectory(MAX_PATH, system_buffer);
563 if (len == 0 || len > MAX_PATH)
564 return false;
565 *dir = system_buffer;
566 file_util::TrimTrailingSeparator(dir);
567 return true;
568}
569
570// Sets the current working directory for the process.
571bool SetCurrentDirectory(const std::wstring& current_directory) {
572 BOOL ret = ::SetCurrentDirectory(current_directory.c_str());
573 return (ret ? true : false);
574}
575
576///////////////////////////////////////////////
577
578
579FileEnumerator::FileEnumerator(const std::wstring& root_path,
580 bool recursive,
581 FileEnumerator::FILE_TYPE file_type)
582 : recursive_(recursive),
583 file_type_(file_type),
584 is_in_find_op_(false),
585 find_handle_(INVALID_HANDLE_VALUE) {
586 pending_paths_.push(root_path);
587}
588
589FileEnumerator::FileEnumerator(const std::wstring& root_path,
590 bool recursive,
591 FileEnumerator::FILE_TYPE file_type,
592 const std::wstring& pattern)
593 : recursive_(recursive),
594 file_type_(file_type),
595 is_in_find_op_(false),
596 pattern_(pattern),
597 find_handle_(INVALID_HANDLE_VALUE) {
598 pending_paths_.push(root_path);
599}
600
601FileEnumerator::~FileEnumerator() {
602 if (find_handle_ != INVALID_HANDLE_VALUE)
603 FindClose(find_handle_);
604}
605
606std::wstring FileEnumerator::Next() {
607 if (!is_in_find_op_) {
608 if (pending_paths_.empty())
609 return std::wstring();
610
611 // The last find FindFirstFile operation is done, prepare a new one.
612 // root_path_ must have the trailing directory character.
613 root_path_ = pending_paths_.top();
614 file_util::AppendToPath(&root_path_, std::wstring());
615 pending_paths_.pop();
616
617 // Start a new find operation.
618 std::wstring src(root_path_);
619
620 if (pattern_.empty())
621 file_util::AppendToPath(&src, L"*"); // No pattern = match everything.
622 else
623 file_util::AppendToPath(&src, pattern_);
624
625 find_handle_ = FindFirstFile(src.c_str(), &find_data_);
626 is_in_find_op_ = true;
627
628 } else {
629 // Search for the next file/directory.
630 if (!FindNextFile(find_handle_, &find_data_)) {
631 FindClose(find_handle_);
632 find_handle_ = INVALID_HANDLE_VALUE;
633 }
634 }
635
636 if (INVALID_HANDLE_VALUE == find_handle_) {
637 is_in_find_op_ = false;
638
639 // This is reached when we have finished a directory and are advancing to
640 // the next one in the queue. We applied the pattern (if any) to the files
641 // in the root search directory, but for those directories which were
642 // matched, we want to enumerate all files inside them. This will happen
643 // when the handle is empty.
644 pattern_.clear();
645
646 return Next();
647 }
648
649 std::wstring cur_file(find_data_.cFileName);
650 // Skip over . and ..
651 if (L"." == cur_file || L".." == cur_file)
652 return Next();
653
654 // Construct the absolute filename.
655 cur_file.insert(0, root_path_);
656
657 if (find_data_.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
658 if (recursive_) {
659 // If |cur_file| is a directory, and we are doing recursive searching, add
660 // it to pending_paths_ so we scan it after we finish scanning this
661 // directory.
662 pending_paths_.push(cur_file);
[email protected]1010f7d2008-08-06 16:29:44663 }
[email protected]3bc9ffaf2008-10-16 02:42:45664 return (file_type_ & FileEnumerator::DIRECTORIES) ? cur_file : Next();
[email protected]1010f7d2008-08-06 16:29:44665 }
666 return (file_type_ & FileEnumerator::FILES) ? cur_file : Next();
667}
668
[email protected]5af2edb92008-08-08 20:16:08669} // namespace file_util