blob: 168e26ee03b658704df3fdb4319b6f14f58d8e90 [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
368bool GetTempDir(std::wstring* path) {
369 wchar_t temp_path[MAX_PATH + 1];
370 DWORD path_len = ::GetTempPath(MAX_PATH, temp_path);
371 if (path_len >= MAX_PATH || path_len <= 0)
372 return false;
373 path->assign(temp_path);
374 TrimTrailingSeparator(path);
375 return true;
376}
377
378bool CreateTemporaryFileName(std::wstring* temp_file) {
379 wchar_t temp_name[MAX_PATH + 1];
380 std::wstring temp_path;
381
382 if (!GetTempDir(&temp_path))
383 return false;
384
385 if (!GetTempFileName(temp_path.c_str(), L"", 0, temp_name))
386 return false; // fail!
387
388 DWORD path_len = GetLongPathName(temp_name, temp_name, MAX_PATH);
389 if (path_len > MAX_PATH + 1 || path_len == 0)
390 return false; // fail!
391
392 temp_file->assign(temp_name, path_len);
393 return true;
394}
395
396bool CreateNewTempDirectory(const std::wstring& prefix,
397 std::wstring* new_temp_path) {
398 std::wstring system_temp_dir;
399 if (!GetTempDir(&system_temp_dir))
400 return false;
401
402 std::wstring path_to_create;
403 srand(static_cast<uint32>(time(NULL)));
404
405 int count = 0;
406 while (count < 50) {
407 // Try create a new temporary directory with random generated name. If
408 // the one exists, keep trying another path name until we reach some limit.
409 path_to_create.assign(system_temp_dir);
410 std::wstring new_dir_name;
411 new_dir_name.assign(prefix);
412 new_dir_name.append(IntToWString(rand() % kint16max));
413 file_util::AppendToPath(&path_to_create, new_dir_name);
414
415 if (::CreateDirectory(path_to_create.c_str(), NULL))
416 break;
417 count++;
418 }
419
420 if (count == 50) {
421 return false;
422 }
423
424 new_temp_path->assign(path_to_create);
425 return true;
426}
427
428bool CreateDirectory(const std::wstring& full_path) {
[email protected]806b9c62008-09-11 16:09:11429 if (DirectoryExists(full_path))
[email protected]81569622008-09-09 22:35:16430 return true;
[email protected]1010f7d2008-08-06 16:29:44431 int err = SHCreateDirectoryEx(NULL, full_path.c_str(), NULL);
432 return err == ERROR_SUCCESS;
433}
434
435bool GetFileSize(const std::wstring& file_path, int64* file_size) {
436 ScopedHandle file_handle(
437 CreateFile(file_path.c_str(), GENERIC_READ,
438 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
439 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL));
440
441 LARGE_INTEGER win32_file_size = {0};
442 if (!GetFileSizeEx(file_handle, &win32_file_size)) {
443 return false;
444 }
445
446 *file_size = win32_file_size.QuadPart;
447 return true;
448}
449
450int ReadFile(const std::wstring& filename, char* data, int size) {
451 ScopedHandle file(CreateFile(filename.c_str(),
452 GENERIC_READ,
453 FILE_SHARE_READ | FILE_SHARE_WRITE,
454 NULL,
455 OPEN_EXISTING,
456 FILE_FLAG_SEQUENTIAL_SCAN,
457 NULL));
458 if (file == INVALID_HANDLE_VALUE)
459 return -1;
460
461 int ret_value;
462 DWORD read;
463 if (::ReadFile(file, data, size, &read, NULL) && read == size) {
464 ret_value = static_cast<int>(read);
465 } else {
466 ret_value = -1;
467 }
468
469 return ret_value;
470}
471
472int WriteFile(const std::wstring& filename, const char* data, int size) {
473 ScopedHandle file(CreateFile(filename.c_str(),
474 GENERIC_WRITE,
475 0,
476 NULL,
477 CREATE_ALWAYS,
478 0,
479 NULL));
[email protected]3b95b862008-09-17 17:00:04480 if (file == INVALID_HANDLE_VALUE) {
481 LOG(WARNING) << "CreateFile failed for path " << filename <<
482 " error code=" << GetLastError() <<
483 " error text=" << win_util::FormatLastWin32Error();
[email protected]1010f7d2008-08-06 16:29:44484 return -1;
[email protected]1010f7d2008-08-06 16:29:44485 }
486
[email protected]3b95b862008-09-17 17:00:04487 DWORD written;
488 BOOL result = ::WriteFile(file, data, size, &written, NULL);
489 if (result && written == size)
490 return static_cast<int>(written);
491
492 if (!result) {
493 // WriteFile failed.
494 LOG(WARNING) << "writing file " << filename <<
495 " failed, error code=" << GetLastError() <<
496 " description=" << win_util::FormatLastWin32Error();
497 } else {
498 // Didn't write all the bytes.
499 LOG(WARNING) << "wrote" << written << " bytes to " << filename <<
500 " expected " << size;
501 }
502 return -1;
[email protected]1010f7d2008-08-06 16:29:44503}
504
505bool RenameFileAndResetSecurityDescriptor(
506 const std::wstring& source_file_path,
507 const std::wstring& target_file_path) {
508 // The MoveFile API does not reset the security descriptor on the target
509 // file. To ensure that the target file gets the correct security descriptor
510 // we create the target file initially in the target path, read its security
511 // descriptor and stamp this descriptor on the target file after the MoveFile
512 // API completes.
513 ScopedHandle temp_file_handle_for_security_desc(
514 CreateFileW(target_file_path.c_str(), GENERIC_READ | GENERIC_WRITE,
515 FILE_SHARE_READ, NULL, OPEN_ALWAYS,
516 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE,
517 NULL));
518 if (!temp_file_handle_for_security_desc.IsValid())
519 return false;
520
521 // Check how much we should allocate for the security descriptor.
522 unsigned long security_descriptor_size_in_bytes = 0;
523 GetFileSecurity(target_file_path.c_str(), DACL_SECURITY_INFORMATION, NULL, 0,
524 &security_descriptor_size_in_bytes);
525 if (ERROR_INSUFFICIENT_BUFFER != GetLastError() ||
526 security_descriptor_size_in_bytes == 0)
527 return false;
528
529 scoped_array<char> security_descriptor(
530 new char[security_descriptor_size_in_bytes]);
531
532 if (!GetFileSecurity(target_file_path.c_str(), DACL_SECURITY_INFORMATION,
533 security_descriptor.get(),
534 security_descriptor_size_in_bytes,
535 &security_descriptor_size_in_bytes)) {
536 return false;
537 }
538
539 temp_file_handle_for_security_desc.Set(INVALID_HANDLE_VALUE);
540
541 if (!MoveFileEx(source_file_path.c_str(), target_file_path.c_str(),
542 MOVEFILE_COPY_ALLOWED)) {
543 return false;
544 }
545
546 return !!SetFileSecurity(target_file_path.c_str(),
547 DACL_SECURITY_INFORMATION,
548 security_descriptor.get());
549}
550
551// Gets the current working directory for the process.
552bool GetCurrentDirectory(std::wstring* dir) {
553 wchar_t system_buffer[MAX_PATH];
554 system_buffer[0] = 0;
555 DWORD len = ::GetCurrentDirectory(MAX_PATH, system_buffer);
556 if (len == 0 || len > MAX_PATH)
557 return false;
558 *dir = system_buffer;
559 file_util::TrimTrailingSeparator(dir);
560 return true;
561}
562
563// Sets the current working directory for the process.
564bool SetCurrentDirectory(const std::wstring& current_directory) {
565 BOOL ret = ::SetCurrentDirectory(current_directory.c_str());
566 return (ret ? true : false);
567}
568
569///////////////////////////////////////////////
570
571
572FileEnumerator::FileEnumerator(const std::wstring& root_path,
573 bool recursive,
574 FileEnumerator::FILE_TYPE file_type)
575 : recursive_(recursive),
576 file_type_(file_type),
577 is_in_find_op_(false),
578 find_handle_(INVALID_HANDLE_VALUE) {
579 pending_paths_.push(root_path);
580}
581
582FileEnumerator::FileEnumerator(const std::wstring& root_path,
583 bool recursive,
584 FileEnumerator::FILE_TYPE file_type,
585 const std::wstring& pattern)
586 : recursive_(recursive),
587 file_type_(file_type),
588 is_in_find_op_(false),
589 pattern_(pattern),
590 find_handle_(INVALID_HANDLE_VALUE) {
591 pending_paths_.push(root_path);
592}
593
594FileEnumerator::~FileEnumerator() {
595 if (find_handle_ != INVALID_HANDLE_VALUE)
596 FindClose(find_handle_);
597}
598
599std::wstring FileEnumerator::Next() {
600 if (!is_in_find_op_) {
601 if (pending_paths_.empty())
602 return std::wstring();
603
604 // The last find FindFirstFile operation is done, prepare a new one.
605 // root_path_ must have the trailing directory character.
606 root_path_ = pending_paths_.top();
607 file_util::AppendToPath(&root_path_, std::wstring());
608 pending_paths_.pop();
609
610 // Start a new find operation.
611 std::wstring src(root_path_);
612
613 if (pattern_.empty())
614 file_util::AppendToPath(&src, L"*"); // No pattern = match everything.
615 else
616 file_util::AppendToPath(&src, pattern_);
617
618 find_handle_ = FindFirstFile(src.c_str(), &find_data_);
619 is_in_find_op_ = true;
620
621 } else {
622 // Search for the next file/directory.
623 if (!FindNextFile(find_handle_, &find_data_)) {
624 FindClose(find_handle_);
625 find_handle_ = INVALID_HANDLE_VALUE;
626 }
627 }
628
629 if (INVALID_HANDLE_VALUE == find_handle_) {
630 is_in_find_op_ = false;
631
632 // This is reached when we have finished a directory and are advancing to
633 // the next one in the queue. We applied the pattern (if any) to the files
634 // in the root search directory, but for those directories which were
635 // matched, we want to enumerate all files inside them. This will happen
636 // when the handle is empty.
637 pattern_.clear();
638
639 return Next();
640 }
641
642 std::wstring cur_file(find_data_.cFileName);
643 // Skip over . and ..
644 if (L"." == cur_file || L".." == cur_file)
645 return Next();
646
647 // Construct the absolute filename.
648 cur_file.insert(0, root_path_);
649
650 if (find_data_.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
651 if (recursive_) {
652 // If |cur_file| is a directory, and we are doing recursive searching, add
653 // it to pending_paths_ so we scan it after we finish scanning this
654 // directory.
655 pending_paths_.push(cur_file);
656 return (file_type_ & FileEnumerator::DIRECTORIES) ? cur_file : Next();
657 }
658
659 if ((file_type_ & FileEnumerator::DIRECTORIES) == 0)
660 return Next();
661 }
662 return (file_type_ & FileEnumerator::FILES) ? cur_file : Next();
663}
664
[email protected]5af2edb92008-08-08 20:16:08665} // namespace file_util