1 | // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
2 | // for details. All rights reserved. Use of this source code is governed by a |
3 | // BSD-style license that can be found in the LICENSE file. |
4 | |
5 | #ifndef RUNTIME_BIN_DIRECTORY_H_ |
6 | #define RUNTIME_BIN_DIRECTORY_H_ |
7 | |
8 | #include "bin/builtin.h" |
9 | #include "bin/dartutils.h" |
10 | #include "bin/namespace.h" |
11 | #include "bin/reference_counting.h" |
12 | #include "bin/thread.h" |
13 | #include "platform/globals.h" |
14 | |
15 | namespace dart { |
16 | namespace bin { |
17 | |
18 | enum ListType { |
19 | kListFile = 0, |
20 | kListDirectory = 1, |
21 | kListLink = 2, |
22 | kListError = 3, |
23 | kListDone = 4 |
24 | }; |
25 | |
26 | class PathBuffer { |
27 | public: |
28 | PathBuffer(); |
29 | ~PathBuffer(); |
30 | |
31 | bool Add(const char* name); |
32 | bool AddW(const wchar_t* name); |
33 | |
34 | char* AsString() const; |
35 | wchar_t* AsStringW() const; |
36 | |
37 | // Makes a scope allocated copy of the string. |
38 | const char* AsScopedString() const; |
39 | |
40 | void Reset(intptr_t new_length); |
41 | |
42 | intptr_t length() const { return length_; } |
43 | |
44 | private: |
45 | void* data_; |
46 | intptr_t length_; |
47 | |
48 | DISALLOW_COPY_AND_ASSIGN(PathBuffer); |
49 | }; |
50 | |
51 | class DirectoryListing; |
52 | |
53 | struct LinkList; |
54 | |
55 | // DirectoryListingEntry is used as a stack item, when performing recursive |
56 | // directory listing. By using DirectoryListingEntry as stack elements, a |
57 | // directory listing can be paused e.g. when a buffer is full, and resumed |
58 | // later on. |
59 | // |
60 | // The stack is managed by the DirectoryListing's PathBuffer. Each |
61 | // DirectoryListingEntry stored a entry-length, that it'll reset the PathBuffer |
62 | // to on each call to Next. |
63 | class DirectoryListingEntry { |
64 | public: |
65 | explicit DirectoryListingEntry(DirectoryListingEntry* parent) |
66 | : parent_(parent), fd_(-1), lister_(0), done_(false), link_(NULL) {} |
67 | |
68 | ~DirectoryListingEntry(); |
69 | |
70 | ListType Next(DirectoryListing* listing); |
71 | |
72 | DirectoryListingEntry* parent() const { return parent_; } |
73 | |
74 | LinkList* link() { return link_; } |
75 | |
76 | void set_link(LinkList* link) { link_ = link; } |
77 | |
78 | void ResetLink(); |
79 | |
80 | private: |
81 | DirectoryListingEntry* parent_; |
82 | intptr_t fd_; |
83 | intptr_t lister_; |
84 | bool done_; |
85 | int path_length_; |
86 | LinkList* link_; |
87 | |
88 | DISALLOW_COPY_AND_ASSIGN(DirectoryListingEntry); |
89 | }; |
90 | |
91 | class DirectoryListing { |
92 | public: |
93 | DirectoryListing(Namespace* namespc, |
94 | const char* dir_name, |
95 | bool recursive, |
96 | bool follow_links) |
97 | : namespc_(namespc), |
98 | top_(NULL), |
99 | error_(false), |
100 | recursive_(recursive), |
101 | follow_links_(follow_links) { |
102 | if (!path_buffer_.Add(dir_name)) { |
103 | error_ = true; |
104 | } |
105 | Push(new DirectoryListingEntry(NULL)); |
106 | } |
107 | |
108 | virtual ~DirectoryListing() { PopAll(); } |
109 | |
110 | virtual bool HandleDirectory(const char* dir_name) = 0; |
111 | virtual bool HandleFile(const char* file_name) = 0; |
112 | virtual bool HandleLink(const char* link_name) = 0; |
113 | virtual bool HandleError() = 0; |
114 | virtual void HandleDone() {} |
115 | |
116 | void Push(DirectoryListingEntry* directory) { top_ = directory; } |
117 | |
118 | void Pop() { |
119 | ASSERT(!IsEmpty()); |
120 | DirectoryListingEntry* current = top_; |
121 | top_ = top_->parent(); |
122 | delete current; |
123 | } |
124 | |
125 | bool IsEmpty() const { return top_ == NULL; } |
126 | |
127 | void PopAll() { |
128 | while (!IsEmpty()) { |
129 | Pop(); |
130 | } |
131 | } |
132 | |
133 | Namespace* namespc() const { return namespc_; } |
134 | |
135 | DirectoryListingEntry* top() const { return top_; } |
136 | |
137 | bool recursive() const { return recursive_; } |
138 | |
139 | bool follow_links() const { return follow_links_; } |
140 | |
141 | const char* CurrentPath() { return path_buffer_.AsScopedString(); } |
142 | |
143 | PathBuffer& path_buffer() { return path_buffer_; } |
144 | |
145 | bool error() const { return error_; } |
146 | |
147 | private: |
148 | PathBuffer path_buffer_; |
149 | Namespace* namespc_; |
150 | DirectoryListingEntry* top_; |
151 | bool error_; |
152 | bool recursive_; |
153 | bool follow_links_; |
154 | }; |
155 | |
156 | class AsyncDirectoryListing : public ReferenceCounted<AsyncDirectoryListing>, |
157 | public DirectoryListing { |
158 | public: |
159 | enum Response { |
160 | kListFile = 0, |
161 | kListDirectory = 1, |
162 | kListLink = 2, |
163 | kListError = 3, |
164 | kListDone = 4 |
165 | }; |
166 | |
167 | AsyncDirectoryListing(Namespace* namespc, |
168 | const char* dir_name, |
169 | bool recursive, |
170 | bool follow_links) |
171 | : ReferenceCounted(), |
172 | DirectoryListing(namespc, dir_name, recursive, follow_links), |
173 | array_(NULL), |
174 | index_(0), |
175 | length_(0) {} |
176 | |
177 | virtual bool HandleDirectory(const char* dir_name); |
178 | virtual bool HandleFile(const char* file_name); |
179 | virtual bool HandleLink(const char* file_name); |
180 | virtual bool HandleError(); |
181 | virtual void HandleDone(); |
182 | |
183 | void SetArray(CObjectArray* array, intptr_t length) { |
184 | ASSERT(length % 2 == 0); |
185 | array_ = array; |
186 | index_ = 0; |
187 | length_ = length; |
188 | } |
189 | |
190 | intptr_t index() const { return index_; } |
191 | |
192 | private: |
193 | virtual ~AsyncDirectoryListing() {} |
194 | bool AddFileSystemEntityToResponse(Response response, const char* arg); |
195 | CObjectArray* array_; |
196 | intptr_t index_; |
197 | intptr_t length_; |
198 | |
199 | friend class ReferenceCounted<AsyncDirectoryListing>; |
200 | DISALLOW_IMPLICIT_CONSTRUCTORS(AsyncDirectoryListing); |
201 | }; |
202 | |
203 | class SyncDirectoryListing : public DirectoryListing { |
204 | public: |
205 | SyncDirectoryListing(Dart_Handle results, |
206 | Namespace* namespc, |
207 | const char* dir_name, |
208 | bool recursive, |
209 | bool follow_links) |
210 | : DirectoryListing(namespc, dir_name, recursive, follow_links), |
211 | results_(results), |
212 | dart_error_(Dart_Null()) { |
213 | add_string_ = DartUtils::NewString("add" ); |
214 | from_raw_path_string_ = DartUtils::NewString("fromRawPath" ); |
215 | directory_type_ = DartUtils::GetDartType(DartUtils::kIOLibURL, "Directory" ); |
216 | file_type_ = DartUtils::GetDartType(DartUtils::kIOLibURL, "File" ); |
217 | link_type_ = DartUtils::GetDartType(DartUtils::kIOLibURL, "Link" ); |
218 | } |
219 | virtual ~SyncDirectoryListing() {} |
220 | virtual bool HandleDirectory(const char* dir_name); |
221 | virtual bool HandleFile(const char* file_name); |
222 | virtual bool HandleLink(const char* file_name); |
223 | virtual bool HandleError(); |
224 | |
225 | Dart_Handle dart_error() { return dart_error_; } |
226 | |
227 | private: |
228 | Dart_Handle results_; |
229 | Dart_Handle add_string_; |
230 | Dart_Handle from_raw_path_string_; |
231 | Dart_Handle directory_type_; |
232 | Dart_Handle file_type_; |
233 | Dart_Handle link_type_; |
234 | Dart_Handle dart_error_; |
235 | |
236 | DISALLOW_ALLOCATION() |
237 | DISALLOW_IMPLICIT_CONSTRUCTORS(SyncDirectoryListing); |
238 | }; |
239 | |
240 | class Directory { |
241 | public: |
242 | enum ExistsResult { UNKNOWN, EXISTS, DOES_NOT_EXIST }; |
243 | |
244 | static void List(DirectoryListing* listing); |
245 | static ExistsResult Exists(Namespace* namespc, const char* path); |
246 | |
247 | // Returns the current working directory. The caller must call |
248 | // free() on the result. |
249 | static char* CurrentNoScope(); |
250 | |
251 | // Returns the current working directory. The returned string is allocated |
252 | // with Dart_ScopeAllocate(). It lasts only as long as the current API scope. |
253 | static const char* Current(Namespace* namespc); |
254 | static const char* SystemTemp(Namespace* namespc); |
255 | static const char* CreateTemp(Namespace* namespc, const char* path); |
256 | // Set the system temporary directory. |
257 | static void SetSystemTemp(const char* path); |
258 | static bool SetCurrent(Namespace* namespc, const char* path); |
259 | static bool Create(Namespace* namespc, const char* path); |
260 | static bool Delete(Namespace* namespc, const char* path, bool recursive); |
261 | static bool Rename(Namespace* namespc, |
262 | const char* path, |
263 | const char* new_path); |
264 | |
265 | static CObject* CreateRequest(const CObjectArray& request); |
266 | static CObject* DeleteRequest(const CObjectArray& request); |
267 | static CObject* ExistsRequest(const CObjectArray& request); |
268 | static CObject* CreateTempRequest(const CObjectArray& request); |
269 | static CObject* CreateSystemTempRequest(const CObjectArray& request); |
270 | static CObject* ListStartRequest(const CObjectArray& request); |
271 | static CObject* ListNextRequest(const CObjectArray& request); |
272 | static CObject* ListStopRequest(const CObjectArray& request); |
273 | static CObject* RenameRequest(const CObjectArray& request); |
274 | |
275 | private: |
276 | static char* system_temp_path_override_; |
277 | DISALLOW_ALLOCATION(); |
278 | DISALLOW_IMPLICIT_CONSTRUCTORS(Directory); |
279 | }; |
280 | |
281 | } // namespace bin |
282 | } // namespace dart |
283 | |
284 | #endif // RUNTIME_BIN_DIRECTORY_H_ |
285 | |