isolate_driver: Enable ninja parsing code all the time.
[chromium-blink-merge.git] / net / base / directory_lister.cc
blobe75e9f808dc87e828a2cd2adee5dfb87b0e8bcbb
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
3 // found in the LICENSE file.
5 #include "net/base/directory_lister.h"
7 #include <algorithm>
8 #include <vector>
10 #include "base/bind.h"
11 #include "base/file_util.h"
12 #include "base/files/file_enumerator.h"
13 #include "base/i18n/file_util_icu.h"
14 #include "base/message_loop/message_loop.h"
15 #include "base/threading/thread_restrictions.h"
16 #include "base/threading/worker_pool.h"
17 #include "net/base/net_errors.h"
19 namespace net {
21 namespace {
23 bool IsDotDot(const base::FilePath& path) {
24 return FILE_PATH_LITERAL("..") == path.BaseName().value();
27 // Comparator for sorting lister results. This uses the locale aware filename
28 // comparison function on the filenames for sorting in the user's locale.
29 // Static.
30 bool CompareAlphaDirsFirst(const DirectoryLister::DirectoryListerData& a,
31 const DirectoryLister::DirectoryListerData& b) {
32 // Parent directory before all else.
33 if (IsDotDot(a.info.GetName()))
34 return true;
35 if (IsDotDot(b.info.GetName()))
36 return false;
38 // Directories before regular files.
39 bool a_is_directory = a.info.IsDirectory();
40 bool b_is_directory = b.info.IsDirectory();
41 if (a_is_directory != b_is_directory)
42 return a_is_directory;
44 return file_util::LocaleAwareCompareFilenames(a.info.GetName(),
45 b.info.GetName());
48 bool CompareDate(const DirectoryLister::DirectoryListerData& a,
49 const DirectoryLister::DirectoryListerData& b) {
50 // Parent directory before all else.
51 if (IsDotDot(a.info.GetName()))
52 return true;
53 if (IsDotDot(b.info.GetName()))
54 return false;
56 // Directories before regular files.
57 bool a_is_directory = a.info.IsDirectory();
58 bool b_is_directory = b.info.IsDirectory();
59 if (a_is_directory != b_is_directory)
60 return a_is_directory;
61 return a.info.GetLastModifiedTime() > b.info.GetLastModifiedTime();
64 // Comparator for sorting find result by paths. This uses the locale-aware
65 // comparison function on the filenames for sorting in the user's locale.
66 // Static.
67 bool CompareFullPath(const DirectoryLister::DirectoryListerData& a,
68 const DirectoryLister::DirectoryListerData& b) {
69 return file_util::LocaleAwareCompareFilenames(a.path, b.path);
72 void SortData(std::vector<DirectoryLister::DirectoryListerData>* data,
73 DirectoryLister::SortType sort_type) {
74 // Sort the results. See the TODO below (this sort should be removed and we
75 // should do it from JS).
76 if (sort_type == DirectoryLister::DATE)
77 std::sort(data->begin(), data->end(), CompareDate);
78 else if (sort_type == DirectoryLister::FULL_PATH)
79 std::sort(data->begin(), data->end(), CompareFullPath);
80 else if (sort_type == DirectoryLister::ALPHA_DIRS_FIRST)
81 std::sort(data->begin(), data->end(), CompareAlphaDirsFirst);
82 else
83 DCHECK_EQ(DirectoryLister::NO_SORT, sort_type);
86 } // namespace
88 DirectoryLister::DirectoryLister(const base::FilePath& dir,
89 DirectoryListerDelegate* delegate)
90 : core_(new Core(dir, false, ALPHA_DIRS_FIRST, this)),
91 delegate_(delegate) {
92 DCHECK(delegate_);
93 DCHECK(!dir.value().empty());
96 DirectoryLister::DirectoryLister(const base::FilePath& dir,
97 bool recursive,
98 SortType sort,
99 DirectoryListerDelegate* delegate)
100 : core_(new Core(dir, recursive, sort, this)),
101 delegate_(delegate) {
102 DCHECK(delegate_);
103 DCHECK(!dir.value().empty());
106 DirectoryLister::~DirectoryLister() {
107 Cancel();
110 bool DirectoryLister::Start() {
111 return core_->Start();
114 void DirectoryLister::Cancel() {
115 return core_->Cancel();
118 DirectoryLister::Core::Core(const base::FilePath& dir,
119 bool recursive,
120 SortType sort,
121 DirectoryLister* lister)
122 : dir_(dir),
123 recursive_(recursive),
124 sort_(sort),
125 lister_(lister) {
126 DCHECK(lister_);
129 DirectoryLister::Core::~Core() {}
131 bool DirectoryLister::Core::Start() {
132 origin_loop_ = base::MessageLoopProxy::current();
134 return base::WorkerPool::PostTask(
135 FROM_HERE, base::Bind(&Core::StartInternal, this), true);
138 void DirectoryLister::Core::Cancel() {
139 lister_ = NULL;
142 void DirectoryLister::Core::StartInternal() {
144 if (!base::DirectoryExists(dir_)) {
145 origin_loop_->PostTask(
146 FROM_HERE,
147 base::Bind(&DirectoryLister::Core::OnDone, this, ERR_FILE_NOT_FOUND));
148 return;
151 int types = base::FileEnumerator::FILES | base::FileEnumerator::DIRECTORIES;
152 if (!recursive_)
153 types |= base::FileEnumerator::INCLUDE_DOT_DOT;
155 base::FileEnumerator file_enum(dir_, recursive_, types);
157 base::FilePath path;
158 std::vector<DirectoryListerData> file_data;
159 while (lister_ && !(path = file_enum.Next()).empty()) {
160 DirectoryListerData data;
161 data.info = file_enum.GetInfo();
162 data.path = path;
163 file_data.push_back(data);
165 /* 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
167 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.
170 const int kFilesPerEvent = 8;
171 if (file_data.size() < kFilesPerEvent)
172 continue;
174 origin_loop_->PostTask(
175 FROM_HERE,
176 base::Bind(&DirectoryLister::Core::SendData, file_data));
177 file_data.clear();
181 SortData(&file_data, sort_);
182 origin_loop_->PostTask(
183 FROM_HERE,
184 base::Bind(&DirectoryLister::Core::SendData, this, file_data));
186 origin_loop_->PostTask(
187 FROM_HERE,
188 base::Bind(&DirectoryLister::Core::OnDone, this, OK));
191 void DirectoryLister::Core::SendData(
192 const std::vector<DirectoryLister::DirectoryListerData>& data) {
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]);
200 void DirectoryLister::Core::OnDone(int error) {
201 DCHECK(origin_loop_->BelongsToCurrentThread());
202 if (lister_)
203 lister_->OnDone(error);
206 void DirectoryLister::OnReceivedData(const DirectoryListerData& data) {
207 delegate_->OnListFile(data);
210 void DirectoryLister::OnDone(int error) {
211 delegate_->OnListDone(error);
214 } // namespace net