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.
4 
5 #ifndef NET_BASE_DIRECTORY_LISTER_H_
6 #define NET_BASE_DIRECTORY_LISTER_H_
7 
8 #include <memory>
9 #include <vector>
10 
11 #include "base/atomicops.h"
12 #include "base/files/file_enumerator.h"
13 #include "base/files/file_path.h"
14 #include "base/macros.h"
15 #include "base/memory/ref_counted.h"
16 #include "net/base/net_export.h"
17 
18 namespace base {
19 class SequencedTaskRunner;
20 }
21 
22 namespace net {
23 
24 // This class provides an API for asynchronously listing the contents of a
25 // directory on the filesystem.  It runs a task on a background thread, and
26 // enumerates all files in the specified directory on that thread.  Destroying
27 // the lister cancels the list operation.  The DirectoryLister must only be
28 // used on a thread with a MessageLoop.
29 class NET_EXPORT DirectoryLister  {
30  public:
31   // Represents one file found.
32   struct DirectoryListerData {
33     base::FileEnumerator::FileInfo info;
34     base::FilePath path;
35     base::FilePath absolute_path;
36   };
37 
38   // Implement this class to receive directory entries.
39   class DirectoryListerDelegate {
40    public:
41     // Called for each file found by the lister.
42     virtual void OnListFile(const DirectoryListerData& data) = 0;
43 
44     // Called when the listing is complete.
45     virtual void OnListDone(int error) = 0;
46 
47    protected:
~DirectoryListerDelegate()48     virtual ~DirectoryListerDelegate() {}
49   };
50 
51   // Listing options
52   // ALPHA_DIRS_FIRST is the default listing type:
53   //   directories first in name order, then files by name order
54   // Listing is recursive only if listing type is NO_SORT_RECURSIVE.
55   // TODO(mmenke): Improve testing.
56   enum ListingType {
57     NO_SORT,
58     NO_SORT_RECURSIVE,
59     ALPHA_DIRS_FIRST,
60   };
61 
62   DirectoryLister(const base::FilePath& dir,
63                   DirectoryListerDelegate* delegate);
64 
65   DirectoryLister(const base::FilePath& dir,
66                   ListingType type,
67                   DirectoryListerDelegate* delegate);
68 
69   // Will invoke Cancel().
70   ~DirectoryLister();
71 
72   // Call this method to start the asynchronous directory enumeration.
73   void Start();
74 
75   // Call this method to asynchronously stop directory enumeration.  The
76   // delegate will not be called back.
77   void Cancel();
78 
79  private:
80   typedef std::vector<DirectoryListerData> DirectoryList;
81 
82   // Class responsible for retrieving and sorting the actual directory list on
83   // a worker pool thread. Created on the DirectoryLister's thread. As it's
84   // refcounted, it's destroyed when the final reference is released, which may
85   // happen on either thread.
86   //
87   // It's kept alive during the calls to Start() and DoneOnOriginSequence() by
88   // the reference owned by the callback itself.
89   class Core : public base::RefCountedThreadSafe<Core> {
90    public:
91     Core(const base::FilePath& dir, ListingType type, DirectoryLister* lister);
92 
93     // May only be called on a worker pool thread.
94     void Start();
95 
96     // Must be called on the origin thread.
97     void CancelOnOriginSequence();
98 
99    private:
100     friend class base::RefCountedThreadSafe<Core>;
101     class DataEvent;
102 
103     ~Core();
104 
105     // Called on both threads.
106     bool IsCancelled() const;
107 
108     // Called on origin thread.
109     void DoneOnOriginSequence(std::unique_ptr<DirectoryList> directory_list,
110                               int error) const;
111 
112     const base::FilePath dir_;
113     const ListingType type_;
114     const scoped_refptr<base::SequencedTaskRunner> origin_task_runner_;
115 
116     // Only used on the origin thread.
117     DirectoryLister* lister_;
118 
119     // Set to 1 on cancellation. Used both to abort listing files early on the
120     // worker pool thread for performance reasons and to ensure |lister_| isn't
121     // called after cancellation on the origin thread.
122     base::subtle::Atomic32 cancelled_;
123 
124     DISALLOW_COPY_AND_ASSIGN(Core);
125   };
126 
127   // Call into the corresponding DirectoryListerDelegate. Must not be called
128   // after cancellation.
129   void OnListFile(const DirectoryListerData& data);
130   void OnListDone(int error);
131 
132   scoped_refptr<Core> core_;
133   DirectoryListerDelegate* const delegate_;
134 
135   DISALLOW_COPY_AND_ASSIGN(DirectoryLister);
136 };
137 
138 }  // namespace net
139 
140 #endif  // NET_BASE_DIRECTORY_LISTER_H_
141