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

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

Issue 3175023: Allow net::DirectoryLister to be used to recursively list the directory, and ... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 10 years, 4 months 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 | Annotate | Revision Log
« 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) 2009 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2009 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> 8 #include <vector>
9 9
10 #include "base/file_util.h" 10 #include "base/file_util.h"
11 #include "base/i18n/file_util_icu.h" 11 #include "base/i18n/file_util_icu.h"
12 #include "base/message_loop.h" 12 #include "base/message_loop.h"
13 #include "base/platform_thread.h" 13 #include "base/platform_thread.h"
14 #include "net/base/net_errors.h" 14 #include "net/base/net_errors.h"
15 15
16 namespace net { 16 namespace net {
17 17
18 static const int kFilesPerEvent = 8; 18 static const int kFilesPerEvent = 8;
19 19
20 // A task which is used to signal the delegate asynchronously.
20 class DirectoryDataEvent : public Task { 21 class DirectoryDataEvent : public Task {
21 public: 22 public:
22 explicit DirectoryDataEvent(DirectoryLister* d) : lister(d), error(0) { 23 explicit DirectoryDataEvent(DirectoryLister* d) : lister(d), error(0) {
23 // Allocations of the FindInfo aren't super cheap, so reserve space. 24 // Allocations of the FindInfo aren't super cheap, so reserve space.
24 data.reserve(64); 25 data.reserve(64);
25 } 26 }
26 27
27 void Run() { 28 void Run() {
28 if (data.empty()) { 29 if (data.empty()) {
29 lister->OnDone(error); 30 lister->OnDone(error);
30 return; 31 return;
31 } 32 }
32 lister->OnReceivedData(&data[0], static_cast<int>(data.size())); 33 lister->OnReceivedData(&data[0], static_cast<int>(data.size()));
33 } 34 }
34 35
35 scoped_refptr<DirectoryLister> lister; 36 scoped_refptr<DirectoryLister> lister;
36 std::vector<file_util::FileEnumerator::FindInfo> data; 37 std::vector<DirectoryLister::DirectoryListerData> data;
37 int error; 38 int error;
38 }; 39 };
39 40
40 // Comparator for sorting FindInfo's. This uses the locale aware filename 41 // Comparator for sorting lister results. This uses the locale aware filename
41 // comparison function on the filenames for sorting in the user's locale. 42 // comparison function on the filenames for sorting in the user's locale.
42 static bool CompareFindInfoAlpha(const file_util::FileEnumerator::FindInfo& a, 43 // Static.
43 const file_util::FileEnumerator::FindInfo& b) { 44 bool DirectoryLister::CompareAlphaDirsFirst(const DirectoryListerData& a,
45 const DirectoryListerData& b) {
44 // Parent directory before all else. 46 // Parent directory before all else.
45 if (file_util::IsDotDot(file_util::FileEnumerator::GetFilename(a))) 47 if (file_util::IsDotDot(file_util::FileEnumerator::GetFilename(a.info)))
46 return true; 48 return true;
47 if (file_util::IsDotDot(file_util::FileEnumerator::GetFilename(b))) 49 if (file_util::IsDotDot(file_util::FileEnumerator::GetFilename(b.info)))
48 return false; 50 return false;
49 51
50 // Directories before regular files. 52 // Directories before regular files.
51 bool a_is_directory = file_util::FileEnumerator::IsDirectory(a); 53 bool a_is_directory = file_util::FileEnumerator::IsDirectory(a.info);
52 bool b_is_directory = file_util::FileEnumerator::IsDirectory(b); 54 bool b_is_directory = file_util::FileEnumerator::IsDirectory(b.info);
53 if (a_is_directory != b_is_directory) 55 if (a_is_directory != b_is_directory)
54 return a_is_directory; 56 return a_is_directory;
55 57
56 return file_util::LocaleAwareCompareFilenames( 58 return file_util::LocaleAwareCompareFilenames(
57 file_util::FileEnumerator::GetFilename(a), 59 file_util::FileEnumerator::GetFilename(a.info),
58 file_util::FileEnumerator::GetFilename(b)); 60 file_util::FileEnumerator::GetFilename(b.info));
59 } 61 }
60 62
61 static bool CompareFindInfoDate(const file_util::FileEnumerator::FindInfo& a, 63 // Static.
62 const file_util::FileEnumerator::FindInfo& b) { 64 bool DirectoryLister::CompareDate(const DirectoryListerData& a,
65 const DirectoryListerData& b) {
63 // Parent directory before all else. 66 // Parent directory before all else.
64 if (file_util::IsDotDot(file_util::FileEnumerator::GetFilename(a))) 67 if (file_util::IsDotDot(file_util::FileEnumerator::GetFilename(a.info)))
65 return true; 68 return true;
66 if (file_util::IsDotDot(file_util::FileEnumerator::GetFilename(b))) 69 if (file_util::IsDotDot(file_util::FileEnumerator::GetFilename(b.info)))
67 return false; 70 return false;
68 71
69 // Directories before regular files. 72 // Directories before regular files.
70 bool a_is_directory = file_util::FileEnumerator::IsDirectory(a); 73 bool a_is_directory = file_util::FileEnumerator::IsDirectory(a.info);
71 bool b_is_directory = file_util::FileEnumerator::IsDirectory(b); 74 bool b_is_directory = file_util::FileEnumerator::IsDirectory(b.info);
72 if (a_is_directory != b_is_directory) 75 if (a_is_directory != b_is_directory)
73 return a_is_directory; 76 return a_is_directory;
74 #if defined(OS_POSIX) 77 #if defined(OS_POSIX)
75 return a.stat.st_mtime > b.stat.st_mtime; 78 return a.info.stat.st_mtime > b.info.stat.st_mtime;
76 #elif defined(OS_WIN) 79 #elif defined(OS_WIN)
77 if (a.ftLastWriteTime.dwHighDateTime == b.ftLastWriteTime.dwHighDateTime) { 80 if (a.info.ftLastWriteTime.dwHighDateTime ==
78 return a.ftLastWriteTime.dwLowDateTime > b.ftLastWriteTime.dwLowDateTime; 81 b.info.ftLastWriteTime.dwHighDateTime) {
82 return a.info.ftLastWriteTime.dwLowDateTime >
83 b.info.ftLastWriteTime.dwLowDateTime;
79 } else { 84 } else {
80 return a.ftLastWriteTime.dwHighDateTime > b.ftLastWriteTime.dwHighDateTime; 85 return a.info.ftLastWriteTime.dwHighDateTime >
86 b.info.ftLastWriteTime.dwHighDateTime;
81 } 87 }
82 #endif 88 #endif
83 } 89 }
84 90
91 // Comparator for sorting find result by paths. This uses the locale-aware
92 // comparison function on the filenames for sorting in the user's locale.
93 // Static.
94 bool DirectoryLister::CompareFullPath(const DirectoryListerData& a,
95 const DirectoryListerData& b) {
96 return file_util::LocaleAwareCompareFilenames(a.path, b.path);
97 }
85 98
86 DirectoryLister::DirectoryLister(const FilePath& dir, 99 DirectoryLister::DirectoryLister(const FilePath& dir,
87 DirectoryListerDelegate* delegate) 100 DirectoryListerDelegate* delegate)
88 : dir_(dir), 101 : dir_(dir),
102 recursive_(false),
89 delegate_(delegate), 103 delegate_(delegate),
90 sort_(DEFAULT), 104 sort_(ALPHA_DIRS_FIRST),
91 message_loop_(NULL), 105 message_loop_(NULL),
92 thread_(kNullThreadHandle) { 106 thread_(kNullThreadHandle) {
93 DCHECK(!dir.value().empty()); 107 DCHECK(!dir.value().empty());
94 } 108 }
95 109
96 DirectoryLister::DirectoryLister(const FilePath& dir, 110 DirectoryLister::DirectoryLister(const FilePath& dir,
111 bool recursive,
97 SORT_TYPE sort, 112 SORT_TYPE sort,
98 DirectoryListerDelegate* delegate) 113 DirectoryListerDelegate* delegate)
99 : dir_(dir), 114 : dir_(dir),
115 recursive_(false),
100 delegate_(delegate), 116 delegate_(delegate),
101 sort_(sort), 117 sort_(sort),
102 message_loop_(NULL), 118 message_loop_(NULL),
103 thread_(kNullThreadHandle) { 119 thread_(kNullThreadHandle) {
104 DCHECK(!dir.value().empty()); 120 DCHECK(!dir.value().empty());
105 } 121 }
106 122
107 DirectoryLister::~DirectoryLister() { 123 DirectoryLister::~DirectoryLister() {
108 if (thread_) { 124 if (thread_) {
109 PlatformThread::Join(thread_); 125 PlatformThread::Join(thread_);
(...skipping 28 matching lines...) Expand all
138 154
139 void DirectoryLister::ThreadMain() { 155 void DirectoryLister::ThreadMain() {
140 DirectoryDataEvent* e = new DirectoryDataEvent(this); 156 DirectoryDataEvent* e = new DirectoryDataEvent(this);
141 157
142 if (!file_util::DirectoryExists(dir_)) { 158 if (!file_util::DirectoryExists(dir_)) {
143 e->error = net::ERR_FILE_NOT_FOUND; 159 e->error = net::ERR_FILE_NOT_FOUND;
144 message_loop_->PostTask(FROM_HERE, e); 160 message_loop_->PostTask(FROM_HERE, e);
145 Release(); 161 Release();
146 return; 162 return;
147 } 163 }
148 file_util::FileEnumerator file_enum(dir_, false,
149 static_cast<file_util::FileEnumerator::FILE_TYPE>(
150 file_util::FileEnumerator::FILES |
151 file_util::FileEnumerator::DIRECTORIES |
152 file_util::FileEnumerator::INCLUDE_DOT_DOT));
153 164
154 while (!canceled_.IsSet() && !(file_enum.Next().value().empty())) { 165 int types = file_util::FileEnumerator::FILES |
155 e->data.push_back(file_util::FileEnumerator::FindInfo()); 166 file_util::FileEnumerator::DIRECTORIES;
156 file_enum.GetFindInfo(&e->data[e->data.size() - 1]); 167 if (!recursive_)
168 types |= file_util::FileEnumerator::INCLUDE_DOT_DOT;
169
170 file_util::FileEnumerator file_enum(dir_, recursive_,
171 static_cast<file_util::FileEnumerator::FILE_TYPE>(types));
172
173 FilePath path;
174 while (!canceled_.IsSet() && !(path = file_enum.Next()).empty()) {
175 DirectoryListerData data;
176 file_enum.GetFindInfo(&data.info);
177 data.path = path;
178 e->data.push_back(data);
157 179
158 /* TODO(brettw) bug 24107: It would be nice to send incremental updates. 180 /* TODO(brettw) bug 24107: It would be nice to send incremental updates.
159 We gather them all so they can be sorted, but eventually the sorting 181 We gather them all so they can be sorted, but eventually the sorting
160 should be done from JS to give more flexibility in the page. When we do 182 should be done from JS to give more flexibility in the page. When we do
161 that, we can uncomment this to send incremental updates to the page. 183 that, we can uncomment this to send incremental updates to the page.
162 if (++e->count == kFilesPerEvent) { 184 if (++e->count == kFilesPerEvent) {
163 message_loop_->PostTask(FROM_HERE, e); 185 message_loop_->PostTask(FROM_HERE, e);
164 e = new DirectoryDataEvent(this); 186 e = new DirectoryDataEvent(this);
165 } 187 }
166 */ 188 */
167 } 189 }
168 190
169 if (!e->data.empty()) { 191 if (!e->data.empty()) {
170 // Sort the results. See the TODO above (this sort should be removed and we 192 // Sort the results. See the TODO above (this sort should be removed and we
171 // should do it from JS). 193 // should do it from JS).
172 if (sort_ == DATE) { 194 if (sort_ == DATE)
173 std::sort(e->data.begin(), e->data.end(), CompareFindInfoDate); 195 std::sort(e->data.begin(), e->data.end(), CompareDate);
174 } else { 196 else if (sort_ == FULL_PATH)
175 std::sort(e->data.begin(), e->data.end(), CompareFindInfoAlpha); 197 std::sort(e->data.begin(), e->data.end(), CompareFullPath);
176 } 198 else if (sort_ == ALPHA_DIRS_FIRST)
199 std::sort(e->data.begin(), e->data.end(), CompareAlphaDirsFirst);
200 else
201 DCHECK_EQ(NO_SORT, sort_);
177 202
178 message_loop_->PostTask(FROM_HERE, e); 203 message_loop_->PostTask(FROM_HERE, e);
179 e = new DirectoryDataEvent(this); 204 e = new DirectoryDataEvent(this);
180 } 205 }
181 206
182 // Notify done 207 // Notify done
183 Release(); 208 Release();
184 message_loop_->PostTask(FROM_HERE, e); 209 message_loop_->PostTask(FROM_HERE, e);
185 } 210 }
186 211
187 void DirectoryLister::OnReceivedData( 212 void DirectoryLister::OnReceivedData(const DirectoryListerData* data,
188 const file_util::FileEnumerator::FindInfo* data, int count) { 213 int count) {
189 // Since the delegate can clear itself during the OnListFile callback, we 214 // Since the delegate can clear itself during the OnListFile callback, we
190 // need to null check it during each iteration of the loop. Similarly, it is 215 // need to null check it during each iteration of the loop. Similarly, it is
191 // necessary to check the canceled_ flag to avoid sending data to a delegate 216 // necessary to check the canceled_ flag to avoid sending data to a delegate
192 // who doesn't want anymore. 217 // who doesn't want anymore.
193 for (int i = 0; !canceled_.IsSet() && delegate_ && i < count; ++i) 218 for (int i = 0; !canceled_.IsSet() && delegate_ && i < count; ++i)
194 delegate_->OnListFile(data[i]); 219 delegate_->OnListFile(data[i]);
195 } 220 }
196 221
197 void DirectoryLister::OnDone(int error) { 222 void DirectoryLister::OnDone(int error) {
198 // If canceled is set, we need to report some kind of error, 223 // If canceled is set, we need to report some kind of error,
199 // but don't overwrite the error condition if it is already set. 224 // but don't overwrite the error condition if it is already set.
200 if (!error && canceled_.IsSet()) 225 if (!error && canceled_.IsSet())
201 error = net::ERR_ABORTED; 226 error = net::ERR_ABORTED;
202 227
203 if (delegate_) 228 if (delegate_)
204 delegate_->OnListDone(error); 229 delegate_->OnListDone(error);
205 } 230 }
206 231
207 } // namespace net 232 } // 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