OLD | NEW |
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include <process.h> | |
6 | |
7 #include "net/base/directory_lister.h" | 5 #include "net/base/directory_lister.h" |
8 | 6 |
| 7 #include "base/file_util.h" |
9 #include "base/message_loop.h" | 8 #include "base/message_loop.h" |
| 9 #include "base/platform_thread.h" |
| 10 #include "net/base/net_errors.h" |
10 | 11 |
11 namespace net { | 12 namespace net { |
12 | 13 |
13 static const int kFilesPerEvent = 8; | 14 static const int kFilesPerEvent = 8; |
14 | 15 |
15 class DirectoryDataEvent : public Task { | 16 class DirectoryDataEvent : public Task { |
16 public: | 17 public: |
17 explicit DirectoryDataEvent(DirectoryLister* d) | 18 explicit DirectoryDataEvent(DirectoryLister* d) |
18 : lister(d), count(0), error(0) { | 19 : lister(d), count(0), error(0) { |
19 } | 20 } |
20 | 21 |
21 void Run() { | 22 void Run() { |
22 if (count) { | 23 if (count) { |
23 lister->OnReceivedData(data, count); | 24 lister->OnReceivedData(data, count); |
24 } else { | 25 } else { |
25 lister->OnDone(error); | 26 lister->OnDone(error); |
26 } | 27 } |
27 } | 28 } |
28 | 29 |
29 scoped_refptr<DirectoryLister> lister; | 30 scoped_refptr<DirectoryLister> lister; |
30 WIN32_FIND_DATA data[kFilesPerEvent]; | 31 file_util::FileEnumerator::FindInfo data[kFilesPerEvent]; |
31 int count; | 32 int count, error; |
32 DWORD error; | |
33 }; | 33 }; |
34 | 34 |
35 /*static*/ | 35 DirectoryLister::DirectoryLister(const std::wstring& dir, |
36 unsigned __stdcall DirectoryLister::ThreadFunc(void* param) { | 36 DirectoryListerDelegate* delegate) |
37 DirectoryLister* self = reinterpret_cast<DirectoryLister*>(param); | |
38 | |
39 std::wstring pattern = self->directory(); | |
40 if (pattern[pattern.size()-1] != '\\') { | |
41 pattern.append(L"\\*"); | |
42 } else { | |
43 pattern.append(L"*"); | |
44 } | |
45 | |
46 DirectoryDataEvent* e = new DirectoryDataEvent(self); | |
47 | |
48 HANDLE handle = FindFirstFile(pattern.c_str(), &e->data[e->count]); | |
49 if (handle == INVALID_HANDLE_VALUE) { | |
50 e->error = GetLastError(); | |
51 self->message_loop_->PostTask(FROM_HERE, e); | |
52 e = NULL; | |
53 } else { | |
54 do { | |
55 if (++e->count == kFilesPerEvent) { | |
56 self->message_loop_->PostTask(FROM_HERE, e); | |
57 e = new DirectoryDataEvent(self); | |
58 } | |
59 } while (!self->was_canceled() && FindNextFile(handle, &e->data[e->count])); | |
60 | |
61 FindClose(handle); | |
62 | |
63 if (e->count > 0) { | |
64 self->message_loop_->PostTask(FROM_HERE, e); | |
65 e = NULL; | |
66 } | |
67 | |
68 // Notify done | |
69 e = new DirectoryDataEvent(self); | |
70 self->message_loop_->PostTask(FROM_HERE, e); | |
71 } | |
72 | |
73 self->Release(); | |
74 return 0; | |
75 } | |
76 | |
77 DirectoryLister::DirectoryLister(const std::wstring& dir, Delegate* delegate) | |
78 : dir_(dir), | 37 : dir_(dir), |
| 38 delegate_(delegate), |
79 message_loop_(NULL), | 39 message_loop_(NULL), |
80 delegate_(delegate), | |
81 thread_(NULL), | 40 thread_(NULL), |
82 canceled_(false) { | 41 canceled_(false) { |
83 DCHECK(!dir.empty()); | 42 DCHECK(!dir.empty()); |
84 } | 43 } |
85 | 44 |
86 DirectoryLister::~DirectoryLister() { | 45 DirectoryLister::~DirectoryLister() { |
87 if (thread_) | 46 if (thread_) { |
88 CloseHandle(thread_); | 47 PlatformThread::Join(thread_); |
| 48 } |
89 } | 49 } |
90 | 50 |
91 bool DirectoryLister::Start() { | 51 bool DirectoryLister::Start() { |
92 // spawn a thread to enumerate the specified directory | 52 // spawn a thread to enumerate the specified directory |
93 | 53 |
94 // pass events back to the current thread | 54 // pass events back to the current thread |
95 message_loop_ = MessageLoop::current(); | 55 message_loop_ = MessageLoop::current(); |
96 DCHECK(message_loop_) << "calling thread must have a message loop"; | 56 DCHECK(message_loop_) << "calling thread must have a message loop"; |
97 | 57 |
98 AddRef(); // the thread will release us when it is done | 58 AddRef(); // the thread will release us when it is done |
99 | 59 |
100 unsigned thread_id; | 60 if (!PlatformThread::Create(0, this, &thread_)) { |
101 thread_ = reinterpret_cast<HANDLE>( | |
102 _beginthreadex(NULL, 0, DirectoryLister::ThreadFunc, this, 0, | |
103 &thread_id)); | |
104 | |
105 if (!thread_) { | |
106 Release(); | 61 Release(); |
107 return false; | 62 return false; |
108 } | 63 } |
109 | 64 |
110 return true; | 65 return true; |
111 } | 66 } |
112 | 67 |
113 void DirectoryLister::Cancel() { | 68 void DirectoryLister::Cancel() { |
114 canceled_ = true; | 69 canceled_ = true; |
115 | 70 |
116 if (thread_) { | 71 if (thread_) { |
117 WaitForSingleObject(thread_, INFINITE); | 72 PlatformThread::Join(thread_); |
118 CloseHandle(thread_); | |
119 thread_ = NULL; | 73 thread_ = NULL; |
120 } | 74 } |
121 } | 75 } |
122 | 76 |
123 void DirectoryLister::OnReceivedData(const WIN32_FIND_DATA* data, int count) { | 77 void DirectoryLister::ThreadMain() { |
| 78 DirectoryDataEvent* e = new DirectoryDataEvent(this); |
| 79 |
| 80 if (!file_util::DirectoryExists(directory())) { |
| 81 e->error = net::ERR_FILE_NOT_FOUND; |
| 82 message_loop_->PostTask(FROM_HERE, e); |
| 83 Release(); |
| 84 return; |
| 85 } |
| 86 |
| 87 file_util::FileEnumerator file_enum(directory(), false, |
| 88 file_util::FileEnumerator::FILES_AND_DIRECTORIES); |
| 89 |
| 90 std::wstring filename; |
| 91 while (!was_canceled() && !(filename = file_enum.Next()).empty()) { |
| 92 file_enum.GetFindInfo(&e->data[e->count]); |
| 93 |
| 94 if (++e->count == kFilesPerEvent) { |
| 95 message_loop_->PostTask(FROM_HERE, e); |
| 96 e = new DirectoryDataEvent(this); |
| 97 } |
| 98 } |
| 99 |
| 100 if (e->count > 0) { |
| 101 message_loop_->PostTask(FROM_HERE, e); |
| 102 e = NULL; |
| 103 } |
| 104 |
| 105 // Notify done |
| 106 e = new DirectoryDataEvent(this); |
| 107 message_loop_->PostTask(FROM_HERE, e); |
| 108 |
| 109 Release(); |
| 110 } |
| 111 |
| 112 void DirectoryLister::OnReceivedData( |
| 113 const file_util::FileEnumerator::FindInfo* data, int count) { |
124 // Since the delegate can clear itself during the OnListFile callback, we | 114 // Since the delegate can clear itself during the OnListFile callback, we |
125 // need to null check it during each iteration of the loop. Similarly, it is | 115 // need to null check it during each iteration of the loop. Similarly, it is |
126 // necessary to check the canceled_ flag to avoid sending data to a delegate | 116 // necessary to check the canceled_ flag to avoid sending data to a delegate |
127 // who doesn't want anymore. | 117 // who doesn't want anymore. |
128 for (int i = 0; !canceled_ && delegate_ && i < count; ++i) | 118 for (int i = 0; !canceled_ && delegate_ && i < count; ++i) |
129 delegate_->OnListFile(data[i]); | 119 delegate_->OnListFile(data[i]); |
130 } | 120 } |
131 | 121 |
132 void DirectoryLister::OnDone(int error) { | 122 void DirectoryLister::OnDone(int error) { |
133 // If canceled, we need to report some kind of error, but don't overwrite the | 123 // If canceled, we need to report some kind of error, but don't overwrite the |
134 // error condition if it is already set. | 124 // error condition if it is already set. |
135 if (!error && canceled_) | 125 if (!error && canceled_) |
136 error = ERROR_OPERATION_ABORTED; | 126 error = net::ERR_ABORTED; |
137 | 127 |
138 if (delegate_) | 128 if (delegate_) |
139 delegate_->OnListDone(error); | 129 delegate_->OnListDone(error); |
140 } | 130 } |
141 | 131 |
142 } // namespace net | 132 } // namespace net |
143 | 133 |
OLD | NEW |