diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/base/directory_lister.cc | 99 | ||||
-rw-r--r-- | net/base/directory_lister.h | 38 | ||||
-rw-r--r-- | net/base/directory_lister_unittest.cc | 49 | ||||
-rw-r--r-- | net/url_request/url_request_file_dir_job.cc | 22 | ||||
-rw-r--r-- | net/url_request/url_request_file_dir_job.h | 3 |
5 files changed, 151 insertions, 60 deletions
diff --git a/net/base/directory_lister.cc b/net/base/directory_lister.cc index 05f70b8..bcf9ca5 100644 --- a/net/base/directory_lister.cc +++ b/net/base/directory_lister.cc @@ -17,8 +17,9 @@ namespace net { static const int kFilesPerEvent = 8; +// A task which is used to signal the delegate asynchronously. class DirectoryDataEvent : public Task { - public: +public: explicit DirectoryDataEvent(DirectoryLister* d) : lister(d), error(0) { // Allocations of the FindInfo aren't super cheap, so reserve space. data.reserve(64); @@ -33,70 +34,85 @@ class DirectoryDataEvent : public Task { } scoped_refptr<DirectoryLister> lister; - std::vector<file_util::FileEnumerator::FindInfo> data; + std::vector<DirectoryLister::DirectoryListerData> data; int error; }; -// Comparator for sorting FindInfo's. This uses the locale aware filename +// Comparator for sorting lister results. This uses the locale aware filename // comparison function on the filenames for sorting in the user's locale. -static bool CompareFindInfoAlpha(const file_util::FileEnumerator::FindInfo& a, - const file_util::FileEnumerator::FindInfo& b) { +// Static. +bool DirectoryLister::CompareAlphaDirsFirst(const DirectoryListerData& a, + const DirectoryListerData& b) { // Parent directory before all else. - if (file_util::IsDotDot(file_util::FileEnumerator::GetFilename(a))) + if (file_util::IsDotDot(file_util::FileEnumerator::GetFilename(a.info))) return true; - if (file_util::IsDotDot(file_util::FileEnumerator::GetFilename(b))) + if (file_util::IsDotDot(file_util::FileEnumerator::GetFilename(b.info))) return false; // Directories before regular files. - bool a_is_directory = file_util::FileEnumerator::IsDirectory(a); - bool b_is_directory = file_util::FileEnumerator::IsDirectory(b); + bool a_is_directory = file_util::FileEnumerator::IsDirectory(a.info); + bool b_is_directory = file_util::FileEnumerator::IsDirectory(b.info); if (a_is_directory != b_is_directory) return a_is_directory; return file_util::LocaleAwareCompareFilenames( - file_util::FileEnumerator::GetFilename(a), - file_util::FileEnumerator::GetFilename(b)); + file_util::FileEnumerator::GetFilename(a.info), + file_util::FileEnumerator::GetFilename(b.info)); } -static bool CompareFindInfoDate(const file_util::FileEnumerator::FindInfo& a, - const file_util::FileEnumerator::FindInfo& b) { +// Static. +bool DirectoryLister::CompareDate(const DirectoryListerData& a, + const DirectoryListerData& b) { // Parent directory before all else. - if (file_util::IsDotDot(file_util::FileEnumerator::GetFilename(a))) + if (file_util::IsDotDot(file_util::FileEnumerator::GetFilename(a.info))) return true; - if (file_util::IsDotDot(file_util::FileEnumerator::GetFilename(b))) + if (file_util::IsDotDot(file_util::FileEnumerator::GetFilename(b.info))) return false; // Directories before regular files. - bool a_is_directory = file_util::FileEnumerator::IsDirectory(a); - bool b_is_directory = file_util::FileEnumerator::IsDirectory(b); + bool a_is_directory = file_util::FileEnumerator::IsDirectory(a.info); + bool b_is_directory = file_util::FileEnumerator::IsDirectory(b.info); if (a_is_directory != b_is_directory) return a_is_directory; #if defined(OS_POSIX) - return a.stat.st_mtime > b.stat.st_mtime; + return a.info.stat.st_mtime > b.info.stat.st_mtime; #elif defined(OS_WIN) - if (a.ftLastWriteTime.dwHighDateTime == b.ftLastWriteTime.dwHighDateTime) { - return a.ftLastWriteTime.dwLowDateTime > b.ftLastWriteTime.dwLowDateTime; + if (a.info.ftLastWriteTime.dwHighDateTime == + b.info.ftLastWriteTime.dwHighDateTime) { + return a.info.ftLastWriteTime.dwLowDateTime > + b.info.ftLastWriteTime.dwLowDateTime; } else { - return a.ftLastWriteTime.dwHighDateTime > b.ftLastWriteTime.dwHighDateTime; + return a.info.ftLastWriteTime.dwHighDateTime > + b.info.ftLastWriteTime.dwHighDateTime; } #endif } +// Comparator for sorting find result by paths. This uses the locale-aware +// comparison function on the filenames for sorting in the user's locale. +// Static. +bool DirectoryLister::CompareFullPath(const DirectoryListerData& a, + const DirectoryListerData& b) { + return file_util::LocaleAwareCompareFilenames(a.path, b.path); +} DirectoryLister::DirectoryLister(const FilePath& dir, DirectoryListerDelegate* delegate) : dir_(dir), + recursive_(false), delegate_(delegate), - sort_(DEFAULT), + sort_(ALPHA_DIRS_FIRST), message_loop_(NULL), thread_(kNullThreadHandle) { DCHECK(!dir.value().empty()); } DirectoryLister::DirectoryLister(const FilePath& dir, + bool recursive, SORT_TYPE sort, DirectoryListerDelegate* delegate) : dir_(dir), + recursive_(false), delegate_(delegate), sort_(sort), message_loop_(NULL), @@ -145,15 +161,21 @@ void DirectoryLister::ThreadMain() { Release(); return; } - file_util::FileEnumerator file_enum(dir_, false, - static_cast<file_util::FileEnumerator::FILE_TYPE>( - file_util::FileEnumerator::FILES | - file_util::FileEnumerator::DIRECTORIES | - file_util::FileEnumerator::INCLUDE_DOT_DOT)); - while (!canceled_.IsSet() && !(file_enum.Next().value().empty())) { - e->data.push_back(file_util::FileEnumerator::FindInfo()); - file_enum.GetFindInfo(&e->data[e->data.size() - 1]); + int types = file_util::FileEnumerator::FILES | + file_util::FileEnumerator::DIRECTORIES; + if (!recursive_) + types |= file_util::FileEnumerator::INCLUDE_DOT_DOT; + + file_util::FileEnumerator file_enum(dir_, recursive_, + static_cast<file_util::FileEnumerator::FILE_TYPE>(types)); + + FilePath path; + while (!canceled_.IsSet() && !(path = file_enum.Next()).empty()) { + DirectoryListerData data; + file_enum.GetFindInfo(&data.info); + data.path = path; + e->data.push_back(data); /* TODO(brettw) bug 24107: It would be nice to send incremental updates. We gather them all so they can be sorted, but eventually the sorting @@ -169,11 +191,14 @@ void DirectoryLister::ThreadMain() { if (!e->data.empty()) { // Sort the results. See the TODO above (this sort should be removed and we // should do it from JS). - if (sort_ == DATE) { - std::sort(e->data.begin(), e->data.end(), CompareFindInfoDate); - } else { - std::sort(e->data.begin(), e->data.end(), CompareFindInfoAlpha); - } + if (sort_ == DATE) + std::sort(e->data.begin(), e->data.end(), CompareDate); + else if (sort_ == FULL_PATH) + std::sort(e->data.begin(), e->data.end(), CompareFullPath); + else if (sort_ == ALPHA_DIRS_FIRST) + std::sort(e->data.begin(), e->data.end(), CompareAlphaDirsFirst); + else + DCHECK_EQ(NO_SORT, sort_); message_loop_->PostTask(FROM_HERE, e); e = new DirectoryDataEvent(this); @@ -184,8 +209,8 @@ void DirectoryLister::ThreadMain() { message_loop_->PostTask(FROM_HERE, e); } -void DirectoryLister::OnReceivedData( - const file_util::FileEnumerator::FindInfo* data, int count) { +void DirectoryLister::OnReceivedData(const DirectoryListerData* data, + int count) { // Since the delegate can clear itself during the OnListFile callback, we // need to null check it during each iteration of the loop. Similarly, it is // necessary to check the canceled_ flag to avoid sending data to a delegate diff --git a/net/base/directory_lister.h b/net/base/directory_lister.h index cbb1a17..8623088 100644 --- a/net/base/directory_lister.h +++ b/net/base/directory_lister.h @@ -6,11 +6,14 @@ #define NET_BASE_DIRECTORY_LISTER_H_ #pragma once +#include <vector> + #include "base/cancellation_flag.h" #include "base/file_path.h" #include "base/file_util.h" #include "base/platform_thread.h" #include "base/ref_counted.h" +#include "base/task.h" class MessageLoop; @@ -26,27 +29,42 @@ namespace net { class DirectoryLister : public base::RefCountedThreadSafe<DirectoryLister>, public PlatformThread::Delegate { public: + // Represents one file found. + struct DirectoryListerData { + file_util::FileEnumerator::FindInfo info; + FilePath path; + }; + // Implement this class to receive directory entries. class DirectoryListerDelegate { public: - virtual void OnListFile( - const file_util::FileEnumerator::FindInfo& data) = 0; + // Called for each file found by the lister. + virtual void OnListFile(const DirectoryListerData& data) = 0; + + // Called when the listing is complete. virtual void OnListDone(int error) = 0; protected: virtual ~DirectoryListerDelegate() {} }; + // Sort options + // ALPHA_DIRS_FIRST is the default sort : + // directories first in name order, then files by name order + // FULL_PATH sorts by paths as strings, ignoring files v. directories + // DATE sorts by last modified date enum SORT_TYPE { - DEFAULT, + NO_SORT, DATE, - ALPHA + ALPHA_DIRS_FIRST, + FULL_PATH }; DirectoryLister(const FilePath& dir, DirectoryListerDelegate* delegate); DirectoryLister(const FilePath& dir, + bool recursive, SORT_TYPE sort, DirectoryListerDelegate* delegate); @@ -70,13 +88,21 @@ class DirectoryLister : public base::RefCountedThreadSafe<DirectoryLister>, friend class base::RefCountedThreadSafe<DirectoryLister>; friend class DirectoryDataEvent; + // Comparison methods for sorting, chosen based on |sort_|. + static bool CompareAlphaDirsFirst(const DirectoryListerData& a, + const DirectoryListerData& b); + static bool CompareDate(const DirectoryListerData& a, + const DirectoryListerData& b); + static bool CompareFullPath(const DirectoryListerData& a, + const DirectoryListerData& b); + ~DirectoryLister(); - void OnReceivedData(const file_util::FileEnumerator::FindInfo* data, - int count); + void OnReceivedData(const DirectoryListerData* data, int count); void OnDone(int error); FilePath dir_; + bool recursive_; DirectoryListerDelegate* delegate_; SORT_TYPE sort_; MessageLoop* message_loop_; diff --git a/net/base/directory_lister_unittest.cc b/net/base/directory_lister_unittest.cc index f3cd33b..f75d8d8 100644 --- a/net/base/directory_lister_unittest.cc +++ b/net/base/directory_lister_unittest.cc @@ -5,6 +5,7 @@ #include "base/file_path.h" #include "base/file_util.h" #include "base/i18n/file_util_icu.h" +#include "base/logging.h" #include "base/message_loop.h" #include "base/path_service.h" #include "net/base/directory_lister.h" @@ -17,14 +18,32 @@ class DirectoryListerTest : public testing::Test {}; class ListerDelegate : public net::DirectoryLister::DirectoryListerDelegate { public: - ListerDelegate() : error_(-1) { + explicit ListerDelegate(bool recursive) : error_(-1), recursive_(recursive) { } - void OnListFile(const file_util::FileEnumerator::FindInfo& data) { - file_list_.push_back(data); + void OnListFile(const net::DirectoryLister::DirectoryListerData& data) { + file_list_.push_back(data.info); + paths_.push_back(data.path); } void OnListDone(int error) { error_ = error; MessageLoop::current()->Quit(); + if (recursive_) + CheckRecursiveSort(); + else + CheckSort(); + } + void CheckRecursiveSort() { + // Check that we got files in the right order. + if (!file_list_.empty()) { + for (size_t previous = 0, current = 1; + current < file_list_.size(); + previous++, current++) { + EXPECT_TRUE(file_util::LocaleAwareCompareFilenames( + paths_[previous], paths_[current])); + } + } + } + void CheckSort() { // Check that we got files in the right order. if (!file_list_.empty()) { for (size_t previous = 0, current = 1; @@ -48,14 +67,16 @@ class ListerDelegate : public net::DirectoryLister::DirectoryListerDelegate { int error() const { return error_; } private: int error_; + bool recursive_; std::vector<file_util::FileEnumerator::FindInfo> file_list_; + std::vector<FilePath> paths_; }; TEST(DirectoryListerTest, BigDirTest) { FilePath path; ASSERT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &path)); - ListerDelegate delegate; + ListerDelegate delegate(false); scoped_refptr<net::DirectoryLister> lister = new net::DirectoryLister(path, &delegate); @@ -66,11 +87,29 @@ TEST(DirectoryListerTest, BigDirTest) { EXPECT_EQ(delegate.error(), net::OK); } +TEST(DirectoryListerTest, BigDirRecursiveTest) { + FilePath path; + ASSERT_TRUE(PathService::Get(base::DIR_EXE, &path)); + + ListerDelegate delegate(true); + scoped_refptr<net::DirectoryLister> lister = + new net::DirectoryLister(path, + true, + net::DirectoryLister::FULL_PATH, + &delegate); + + lister->Start(); + + MessageLoop::current()->Run(); + + EXPECT_EQ(delegate.error(), net::OK); +} + TEST(DirectoryListerTest, CancelTest) { FilePath path; ASSERT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &path)); - ListerDelegate delegate; + ListerDelegate delegate(false); scoped_refptr<net::DirectoryLister> lister = new net::DirectoryLister(path, &delegate); diff --git a/net/url_request/url_request_file_dir_job.cc b/net/url_request/url_request_file_dir_job.cc index 19a1aaf..23ff6ff 100644 --- a/net/url_request/url_request_file_dir_job.cc +++ b/net/url_request/url_request_file_dir_job.cc @@ -102,7 +102,7 @@ bool URLRequestFileDirJob::GetCharset(string* charset) { } void URLRequestFileDirJob::OnListFile( - const file_util::FileEnumerator::FindInfo& data) { + const net::DirectoryLister::DirectoryListerData& data) { // We wait to write out the header until we get the first file, so that we // can catch errors from DirectoryLister and show an error page. if (!wrote_header_) { @@ -122,26 +122,26 @@ void URLRequestFileDirJob::OnListFile( } #if defined(OS_WIN) - int64 size = (static_cast<unsigned __int64>(data.nFileSizeHigh) << 32) | - data.nFileSizeLow; + int64 size = (static_cast<unsigned __int64>(data.info.nFileSizeHigh) << 32) | + data.info.nFileSizeLow; // Note that we should not convert ftLastWriteTime to the local time because // ICU's datetime formatting APIs expect time in UTC and take into account // the timezone before formatting. data_.append(net::GetDirectoryListingEntry( - data.cFileName, std::string(), - (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? true : false, + data.info.cFileName, std::string(), + (data.info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? true : false, size, - base::Time::FromFileTime(data.ftLastWriteTime))); + base::Time::FromFileTime(data.info.ftLastWriteTime))); #elif defined(OS_POSIX) // TOOD(jungshik): The same issue as for the directory name. data_.append(net::GetDirectoryListingEntry( - WideToUTF16(base::SysNativeMBToWide(data.filename)), - data.filename, - S_ISDIR(data.stat.st_mode), - data.stat.st_size, - base::Time::FromTimeT(data.stat.st_mtime))); + WideToUTF16(base::SysNativeMBToWide(data.info.filename)), + data.info.filename, + S_ISDIR(data.info.stat.st_mode), + data.info.stat.st_size, + base::Time::FromTimeT(data.info.stat.st_mtime))); #endif // TODO(darin): coalesce more? diff --git a/net/url_request/url_request_file_dir_job.h b/net/url_request/url_request_file_dir_job.h index 863d5a9..c78de97 100644 --- a/net/url_request/url_request_file_dir_job.h +++ b/net/url_request/url_request_file_dir_job.h @@ -28,7 +28,8 @@ class URLRequestFileDirJob virtual bool GetCharset(std::string* charset); // DirectoryLister::DirectoryListerDelegate methods: - virtual void OnListFile(const file_util::FileEnumerator::FindInfo& data); + virtual void OnListFile( + const net::DirectoryLister::DirectoryListerData& data); virtual void OnListDone(int error); bool list_complete() const { return list_complete_; } |