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
15namespace dart {
16namespace bin {
17
18enum ListType {
19 kListFile = 0,
20 kListDirectory = 1,
21 kListLink = 2,
22 kListError = 3,
23 kListDone = 4
24};
25
26class 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
51class DirectoryListing;
52
53struct 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.
63class 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
91class 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
156class 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
203class 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
240class 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