Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(828)

Side by Side Diff: net/base/directory_lister.cc

Issue 786123002: Update from https://crrev.com/307330 (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Created 6 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « net/base/directory_lister.h ('k') | net/base/directory_lister_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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 "net/base/directory_lister.h" 5 #include "net/base/directory_lister.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <vector>
9 8
10 #include "base/bind.h" 9 #include "base/bind.h"
11 #include "base/files/file_enumerator.h" 10 #include "base/files/file_enumerator.h"
12 #include "base/files/file_util.h" 11 #include "base/files/file_util.h"
13 #include "base/i18n/file_util_icu.h" 12 #include "base/i18n/file_util_icu.h"
13 #include "base/logging.h"
14 #include "base/message_loop/message_loop.h" 14 #include "base/message_loop/message_loop.h"
15 #include "base/threading/thread_restrictions.h" 15 #include "base/threading/thread_restrictions.h"
16 #include "base/threading/worker_pool.h" 16 #include "base/threading/worker_pool.h"
17 #include "net/base/net_errors.h" 17 #include "net/base/net_errors.h"
18 18
19 namespace net { 19 namespace net {
20 20
21 namespace { 21 namespace {
22 22
23 bool IsDotDot(const base::FilePath& path) { 23 bool IsDotDot(const base::FilePath& path) {
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
66 // Static. 66 // Static.
67 bool CompareFullPath(const DirectoryLister::DirectoryListerData& a, 67 bool CompareFullPath(const DirectoryLister::DirectoryListerData& a,
68 const DirectoryLister::DirectoryListerData& b) { 68 const DirectoryLister::DirectoryListerData& b) {
69 return base::i18n::LocaleAwareCompareFilenames(a.path, b.path); 69 return base::i18n::LocaleAwareCompareFilenames(a.path, b.path);
70 } 70 }
71 71
72 void SortData(std::vector<DirectoryLister::DirectoryListerData>* data, 72 void SortData(std::vector<DirectoryLister::DirectoryListerData>* data,
73 DirectoryLister::SortType sort_type) { 73 DirectoryLister::SortType sort_type) {
74 // Sort the results. See the TODO below (this sort should be removed and we 74 // Sort the results. See the TODO below (this sort should be removed and we
75 // should do it from JS). 75 // should do it from JS).
76 if (sort_type == DirectoryLister::DATE) 76 if (sort_type == DirectoryLister::DATE) {
77 std::sort(data->begin(), data->end(), CompareDate); 77 std::sort(data->begin(), data->end(), CompareDate);
78 else if (sort_type == DirectoryLister::FULL_PATH) 78 } else if (sort_type == DirectoryLister::FULL_PATH) {
79 std::sort(data->begin(), data->end(), CompareFullPath); 79 std::sort(data->begin(), data->end(), CompareFullPath);
80 else if (sort_type == DirectoryLister::ALPHA_DIRS_FIRST) 80 } else if (sort_type == DirectoryLister::ALPHA_DIRS_FIRST) {
81 std::sort(data->begin(), data->end(), CompareAlphaDirsFirst); 81 std::sort(data->begin(), data->end(), CompareAlphaDirsFirst);
82 else 82 } else {
83 DCHECK_EQ(DirectoryLister::NO_SORT, sort_type); 83 DCHECK_EQ(DirectoryLister::NO_SORT, sort_type);
84 }
84 } 85 }
85 86
86 } // namespace 87 } // namespace
87 88
88 DirectoryLister::DirectoryLister(const base::FilePath& dir, 89 DirectoryLister::DirectoryLister(const base::FilePath& dir,
89 DirectoryListerDelegate* delegate) 90 DirectoryListerDelegate* delegate)
90 : core_(new Core(dir, false, ALPHA_DIRS_FIRST, this)), 91 : delegate_(delegate) {
91 delegate_(delegate) { 92 core_ = new Core(dir, false, ALPHA_DIRS_FIRST, this);
92 DCHECK(delegate_); 93 DCHECK(delegate_);
93 DCHECK(!dir.value().empty()); 94 DCHECK(!dir.value().empty());
94 } 95 }
95 96
96 DirectoryLister::DirectoryLister(const base::FilePath& dir, 97 DirectoryLister::DirectoryLister(const base::FilePath& dir,
97 bool recursive, 98 bool recursive,
98 SortType sort, 99 SortType sort,
99 DirectoryListerDelegate* delegate) 100 DirectoryListerDelegate* delegate)
100 : core_(new Core(dir, recursive, sort, this)), 101 : delegate_(delegate) {
101 delegate_(delegate) { 102 core_ = new Core(dir, recursive, sort, this);
102 DCHECK(delegate_); 103 DCHECK(delegate_);
103 DCHECK(!dir.value().empty()); 104 DCHECK(!dir.value().empty());
104 } 105 }
105 106
106 DirectoryLister::~DirectoryLister() { 107 DirectoryLister::~DirectoryLister() {
107 Cancel(); 108 Cancel();
108 } 109 }
109 110
110 bool DirectoryLister::Start() { 111 bool DirectoryLister::Start() {
111 return core_->Start(); 112 return base::WorkerPool::PostTask(
113 FROM_HERE,
114 base::Bind(&Core::Start, core_),
115 true);
112 } 116 }
113 117
114 void DirectoryLister::Cancel() { 118 void DirectoryLister::Cancel() {
115 return core_->Cancel(); 119 core_->CancelOnOriginThread();
116 } 120 }
117 121
118 DirectoryLister::Core::Core(const base::FilePath& dir, 122 DirectoryLister::Core::Core(const base::FilePath& dir,
119 bool recursive, 123 bool recursive,
120 SortType sort, 124 SortType sort,
121 DirectoryLister* lister) 125 DirectoryLister* lister)
122 : dir_(dir), 126 : dir_(dir),
123 recursive_(recursive), 127 recursive_(recursive),
124 sort_(sort), 128 sort_(sort),
125 lister_(lister) { 129 origin_loop_(base::MessageLoopProxy::current()),
130 lister_(lister),
131 cancelled_(0) {
126 DCHECK(lister_); 132 DCHECK(lister_);
127 } 133 }
128 134
129 DirectoryLister::Core::~Core() {} 135 DirectoryLister::Core::~Core() {}
130 136
131 bool DirectoryLister::Core::Start() { 137 void DirectoryLister::Core::CancelOnOriginThread() {
132 origin_loop_ = base::MessageLoopProxy::current(); 138 DCHECK(origin_loop_->BelongsToCurrentThread());
133 139
134 return base::WorkerPool::PostTask( 140 base::subtle::NoBarrier_Store(&cancelled_, 1);
135 FROM_HERE, base::Bind(&Core::StartInternal, this), true); 141 // Core must not call into |lister_| after cancellation, as the |lister_| may
142 // have been destroyed. Setting |lister_| to NULL ensures any such access will
143 // cause a crash.
144 lister_ = nullptr;
136 } 145 }
137 146
138 void DirectoryLister::Core::Cancel() { 147 void DirectoryLister::Core::Start() {
139 lister_ = NULL; 148 scoped_ptr<DirectoryList> directory_list(new DirectoryList());
140 }
141
142 void DirectoryLister::Core::StartInternal() {
143 149
144 if (!base::DirectoryExists(dir_)) { 150 if (!base::DirectoryExists(dir_)) {
145 origin_loop_->PostTask( 151 origin_loop_->PostTask(
146 FROM_HERE, 152 FROM_HERE,
147 base::Bind(&DirectoryLister::Core::OnDone, this, ERR_FILE_NOT_FOUND)); 153 base::Bind(&Core::DoneOnOriginThread, this,
154 base::Passed(directory_list.Pass()), ERR_FILE_NOT_FOUND));
148 return; 155 return;
149 } 156 }
150 157
151 int types = base::FileEnumerator::FILES | base::FileEnumerator::DIRECTORIES; 158 int types = base::FileEnumerator::FILES | base::FileEnumerator::DIRECTORIES;
152 if (!recursive_) 159 if (!recursive_)
153 types |= base::FileEnumerator::INCLUDE_DOT_DOT; 160 types |= base::FileEnumerator::INCLUDE_DOT_DOT;
154 161
155 base::FileEnumerator file_enum(dir_, recursive_, types); 162 base::FileEnumerator file_enum(dir_, recursive_, types);
156 163
157 base::FilePath path; 164 base::FilePath path;
158 std::vector<DirectoryListerData> file_data; 165 while (!(path = file_enum.Next()).empty()) {
159 while (lister_ && !(path = file_enum.Next()).empty()) { 166 // Abort on cancellation. This is purely for performance reasons.
167 // Correctness guarantees are made by checks in DoneOnOriginThread.
168 if (IsCancelled())
169 return;
170
160 DirectoryListerData data; 171 DirectoryListerData data;
161 data.info = file_enum.GetInfo(); 172 data.info = file_enum.GetInfo();
162 data.path = path; 173 data.path = path;
163 file_data.push_back(data); 174 directory_list->push_back(data);
164 175
165 /* TODO(brettw) bug 24107: It would be nice to send incremental updates. 176 /* TODO(brettw) bug 24107: It would be nice to send incremental updates.
166 We gather them all so they can be sorted, but eventually the sorting 177 We gather them all so they can be sorted, but eventually the sorting
167 should be done from JS to give more flexibility in the page. When we do 178 should be done from JS to give more flexibility in the page. When we do
168 that, we can uncomment this to send incremental updates to the page. 179 that, we can uncomment this to send incremental updates to the page.
169 180
170 const int kFilesPerEvent = 8; 181 const int kFilesPerEvent = 8;
171 if (file_data.size() < kFilesPerEvent) 182 if (file_data.size() < kFilesPerEvent)
172 continue; 183 continue;
173 184
174 origin_loop_->PostTask( 185 origin_loop_->PostTask(
175 FROM_HERE, 186 FROM_HERE,
176 base::Bind(&DirectoryLister::Core::SendData, file_data)); 187 base::Bind(&DirectoryLister::Core::SendData, file_data));
177 file_data.clear(); 188 file_data.clear();
178 */ 189 */
179 } 190 }
180 191
181 SortData(&file_data, sort_); 192 SortData(directory_list.get(), sort_);
182 origin_loop_->PostTask(
183 FROM_HERE,
184 base::Bind(&DirectoryLister::Core::SendData, this, file_data));
185 193
186 origin_loop_->PostTask( 194 origin_loop_->PostTask(
187 FROM_HERE, 195 FROM_HERE,
188 base::Bind(&DirectoryLister::Core::OnDone, this, OK)); 196 base::Bind(&Core::DoneOnOriginThread, this,
197 base::Passed(directory_list.Pass()), OK));
189 } 198 }
190 199
191 void DirectoryLister::Core::SendData( 200 bool DirectoryLister::Core::IsCancelled() const {
192 const std::vector<DirectoryLister::DirectoryListerData>& data) { 201 return !!base::subtle::NoBarrier_Load(&cancelled_);
193 DCHECK(origin_loop_->BelongsToCurrentThread());
194 // We need to check for cancellation (indicated by NULL'ing of |lister_|)
195 // which can happen during each callback.
196 for (size_t i = 0; lister_ && i < data.size(); ++i)
197 lister_->OnReceivedData(data[i]);
198 } 202 }
199 203
200 void DirectoryLister::Core::OnDone(int error) { 204 void DirectoryLister::Core::DoneOnOriginThread(
205 scoped_ptr<DirectoryList> directory_list, int error) const {
201 DCHECK(origin_loop_->BelongsToCurrentThread()); 206 DCHECK(origin_loop_->BelongsToCurrentThread());
202 if (lister_) 207
203 lister_->OnDone(error); 208 // Need to check if the operation was before first callback.
209 if (IsCancelled())
210 return;
211
212 for (const auto& lister_data : *directory_list) {
213 lister_->OnListFile(lister_data);
214 // Need to check if the operation was cancelled during the callback.
215 if (IsCancelled())
216 return;
217 }
218 lister_->OnListDone(error);
204 } 219 }
205 220
206 void DirectoryLister::OnReceivedData(const DirectoryListerData& data) { 221 void DirectoryLister::OnListFile(const DirectoryListerData& data) {
207 delegate_->OnListFile(data); 222 delegate_->OnListFile(data);
208 } 223 }
209 224
210 void DirectoryLister::OnDone(int error) { 225 void DirectoryLister::OnListDone(int error) {
211 delegate_->OnListDone(error); 226 delegate_->OnListDone(error);
212 } 227 }
213 228
214 } // namespace net 229 } // namespace net
OLDNEW
« no previous file with comments | « net/base/directory_lister.h ('k') | net/base/directory_lister_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698