OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 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 | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 | 5 |
6 // Used for holding error code and error message for failed OS system calls. | 6 // Used for holding error code and error message for failed OS system calls. |
7 class _OSStatus { | 7 class _OSStatus { |
8 int _errorCode; | 8 int _errorCode; |
9 String _errorMessage; | 9 String _errorMessage; |
10 } | 10 } |
11 | 11 |
12 | 12 |
13 class _DirectoryListingIsolate extends Isolate { | |
14 | |
15 _DirectoryListingIsolate() : super.heavy(); | |
16 | |
17 void main() { | |
18 port.receive((message, replyTo) { | |
19 bool started = _list(message['dir'], | |
20 message['recursive'], | |
21 message['dirPort'], | |
22 message['filePort'], | |
23 message['donePort'], | |
24 message['errorPort']); | |
25 replyTo.send(started); | |
26 port.close(); | |
27 }); | |
28 } | |
29 | |
30 bool _list(String dir, | |
31 bool recursive, | |
32 SendPort dirPort, | |
33 SendPort filePort, | |
34 SendPort donePort, | |
35 SendPort errorPort) native "Directory_List"; | |
36 } | |
37 | |
38 | |
39 class _DirectoryOperation { | |
40 abstract void execute(ReceivePort port); | |
41 | |
42 void set replyPort(SendPort port) { | |
43 _replyPort = port; | |
44 } | |
45 | |
46 SendPort _replyPort; | |
47 } | |
48 | |
49 | |
50 class _DirExitOperation extends _DirectoryOperation { | |
51 void execute(ReceivePort port) { | |
52 port.close(); | |
53 } | |
54 } | |
55 | |
56 | |
57 class _DirExistsOperation extends _DirectoryOperation { | |
58 _DirExistsOperation(String this._path); | |
59 | |
60 void execute(ReceivePort port) { | |
61 _replyPort.send(_Directory._exists(_path), port.toSendPort()); | |
62 } | |
63 | |
64 String _path; | |
65 } | |
66 | |
67 | |
68 class _DirCreateOperation extends _DirectoryOperation { | |
69 _DirCreateOperation(String this._path); | |
70 | |
71 void execute(ReceivePort port) { | |
72 _replyPort.send(_Directory._create(_path), port.toSendPort()); | |
73 } | |
74 | |
75 String _path; | |
76 } | |
77 | |
78 | |
79 class _DirCreateTempOperation extends _DirectoryOperation { | |
80 _DirCreateTempOperation(String this._path); | |
81 | |
82 void execute(ReceivePort port) { | |
83 var status = new _OSStatus(); | |
84 var result = _Directory._createTemp(_path, status); | |
85 if (result == null) { | |
86 _replyPort.send(status, port.toSendPort()); | |
87 } else { | |
88 _replyPort.send(result, port.toSendPort()); | |
89 } | |
90 } | |
91 | |
92 String _path; | |
93 } | |
94 | |
95 | |
96 class _DirDeleteOperation extends _DirectoryOperation { | |
97 _DirDeleteOperation(String this._path, bool this._recursive); | |
98 | |
99 void execute(ReceivePort port) { | |
100 _replyPort.send(_Directory._delete(_path, _recursive), port.toSendPort()); | |
101 } | |
102 | |
103 String _path; | |
104 bool _recursive; | |
105 } | |
106 | |
107 | |
108 class _DirectoryOperationIsolate extends Isolate { | |
109 _DirectoryOperationIsolate() : super.heavy(); | |
110 | |
111 void handleOperation(_DirectoryOperation message, SendPort ignored) { | |
112 message.execute(port); | |
113 port.receive(handleOperation); | |
114 } | |
115 | |
116 void main() { | |
117 port.receive(handleOperation); | |
118 } | |
119 } | |
120 | |
121 | |
122 class _DirectoryOperationScheduler { | |
123 _DirectoryOperationScheduler() : _queue = new Queue(); | |
124 | |
125 void schedule(SendPort port) { | |
126 assert(_isolate != null); | |
127 if (_queue.isEmpty()) { | |
128 port.send(new _DirExitOperation()); | |
129 _isolate = null; | |
130 } else { | |
131 port.send(_queue.removeFirst()); | |
132 } | |
133 } | |
134 | |
135 void scheduleWrap(void callback(result, ignored)) { | |
136 return (result, replyTo) { | |
137 callback(result, replyTo); | |
138 schedule(replyTo); | |
139 }; | |
140 } | |
141 | |
142 void enqueue(_DirectoryOperation operation, void callback(result, ignored)) { | |
143 ReceivePort replyPort = new ReceivePort.singleShot(); | |
144 replyPort.receive(scheduleWrap(callback)); | |
145 operation.replyPort = replyPort.toSendPort(); | |
146 _queue.addLast(operation); | |
147 if (_isolate == null) { | |
148 _isolate = new _DirectoryOperationIsolate(); | |
149 _isolate.spawn().then((port) { | |
150 schedule(port); | |
151 }); | |
152 } | |
153 } | |
154 | |
155 Queue<_DirectoryOperation> _queue; | |
156 _DirectoryOperationIsolate _isolate; | |
157 } | |
158 | |
159 | |
160 class _Directory implements Directory { | 13 class _Directory implements Directory { |
| 14 static final kCreateRequest = 0; |
| 15 static final kDeleteRequest = 1; |
| 16 static final kExistsRequest = 2; |
| 17 static final kCreateTempRequest = 3; |
| 18 static final kListRequest = 4; |
161 | 19 |
162 _Directory(String this._path) | 20 _Directory(String this._path); |
163 : _scheduler = new _DirectoryOperationScheduler(); | |
164 | 21 |
165 static String _createTemp(String template, | 22 static String _createTemp(String template, |
166 _OSStatus status) native "Directory_CreateTemp"; | 23 _OSStatus status) native "Directory_CreateTemp"; |
167 static int _exists(String path) native "Directory_Exists"; | 24 static int _exists(String path) native "Directory_Exists"; |
168 static bool _create(String path) native "Directory_Create"; | 25 static bool _create(String path) native "Directory_Create"; |
169 static bool _delete(String path, bool recursive) native "Directory_Delete"; | 26 static bool _delete(String path, bool recursive) native "Directory_Delete"; |
| 27 static SendPort _newServicePort() native "Directory_NewServicePort"; |
170 | 28 |
171 void exists() { | 29 void exists() { |
172 var operation = new _DirExistsOperation(_path); | 30 if (_directoryService == null) { |
173 _scheduler.enqueue(operation, (result, ignored) { | 31 _directoryService = _newServicePort(); |
| 32 } |
| 33 List request = new List(2); |
| 34 request[0] = kExistsRequest; |
| 35 request[1] = _path; |
| 36 _directoryService.call(request).receive((result, replyTo) { |
174 var handler = | 37 var handler = |
175 (_existsHandler != null) ? _existsHandler : (result) => null; | 38 (_existsHandler != null) ? _existsHandler : (result) => null; |
176 if (result < 0) { | 39 if (result < 0) { |
177 if (_errorHandler != null) { | 40 if (_errorHandler != null) { |
178 _errorHandler("Diretory exists test failed: $_path"); | 41 _errorHandler("Diretory exists test failed: $_path"); |
179 } | 42 } |
180 } else { | 43 } else { |
181 handler(result == 1); | 44 handler(result == 1); |
182 } | 45 } |
183 }); | 46 }); |
184 } | 47 } |
185 | 48 |
186 bool existsSync() { | 49 bool existsSync() { |
187 int exists = _exists(_path); | 50 int exists = _exists(_path); |
188 if (exists < 0) { | 51 if (exists < 0) { |
189 throw new DirectoryException("Diretory exists test failed: $_path"); | 52 throw new DirectoryException("Diretory exists test failed: $_path"); |
190 } | 53 } |
191 return (exists == 1); | 54 return (exists == 1); |
192 } | 55 } |
193 | 56 |
194 void create() { | 57 void create() { |
195 var operation = new _DirCreateOperation(_path); | 58 if (_directoryService == null) { |
196 _scheduler.enqueue(operation, (result, ignored) { | 59 _directoryService = _newServicePort(); |
197 var handler = (_createHandler != null) ? _createHandler : () => null; | 60 } |
| 61 List request = new List(2); |
| 62 request[0] = kCreateRequest; |
| 63 request[1] = _path; |
| 64 _directoryService.call(request).receive((result, replyTo) { |
198 if (result) { | 65 if (result) { |
199 handler(); | 66 if (_createHandler != null) _createHandler(); |
200 } else if (_errorHandler != null) { | 67 } else if (_errorHandler != null) { |
201 _errorHandler("Directory creation failed: $_path"); | 68 _errorHandler("Directory creation failed: $_path"); |
202 } | 69 } |
203 }); | 70 }); |
204 } | 71 } |
205 | 72 |
206 void createSync() { | 73 void createSync() { |
207 if (!_create(_path)) { | 74 if (!_create(_path)) { |
208 throw new DirectoryException("Directory creation failed: $_path"); | 75 throw new DirectoryException("Directory creation failed: $_path"); |
209 } | 76 } |
210 } | 77 } |
211 | 78 |
212 void createTemp() { | 79 void createTemp() { |
213 var operation = new _DirCreateTempOperation(_path); | 80 if (_directoryService == null) { |
214 _scheduler.enqueue(operation, (result, ignored) { | 81 _directoryService = _newServicePort(); |
215 var handler = | 82 } |
216 (_createTempHandler != null) ? _createTempHandler : () => null; | 83 List request = new List(2); |
217 if (result is !_OSStatus) { | 84 request[0] = kCreateTempRequest; |
| 85 request[1] = _path; |
| 86 _directoryService.call(request).receive((result, replyTo) { |
| 87 if (result is !List) { |
218 _path = result; | 88 _path = result; |
219 handler(); | 89 if (_createTempHandler != null) _createTempHandler(); |
220 } else if (_errorHandler !== null) { | 90 } else if (_errorHandler != null) { |
221 _errorHandler("Could not create temporary directory [$_path]: " + | 91 _errorHandler("Could not create temporary directory [$_path]: " + |
222 "${result._errorMessage}"); | 92 "${result[1]}"); |
223 } | 93 } |
224 }); | 94 }); |
225 } | 95 } |
226 | 96 |
227 void createTempSync() { | 97 void createTempSync() { |
228 var status = new _OSStatus(); | 98 var status = new _OSStatus(); |
229 var result = _createTemp(path, status); | 99 var result = _createTemp(path, status); |
230 if (result != null) { | 100 if (result != null) { |
231 _path = result; | 101 _path = result; |
232 } else { | 102 } else { |
233 throw new DirectoryException( | 103 throw new DirectoryException( |
234 "Could not create temporary directory [$_path]: " + | 104 "Could not create temporary directory [$_path]: " + |
235 "${status._errorMessage}", | 105 "${status._errorMessage}", |
236 status._errorCode); | 106 status._errorCode); |
237 } | 107 } |
238 } | 108 } |
239 | 109 |
240 void delete([bool recursive = false]) { | 110 void delete([bool recursive = false]) { |
241 var operation = new _DirDeleteOperation(_path, recursive); | 111 if (_directoryService == null) { |
242 _scheduler.enqueue(operation, (result, ignored) { | 112 _directoryService = _newServicePort(); |
243 var handler = (_deleteHandler != null) ? _deleteHandler : () => null; | 113 } |
| 114 List request = new List(3); |
| 115 request[0] = kDeleteRequest; |
| 116 request[1] = _path; |
| 117 request[2] = recursive; |
| 118 _directoryService.call(request).receive((result, replyTo) { |
244 if (result) { | 119 if (result) { |
245 handler(); | 120 if (_deleteHandler != null) _deleteHandler(); |
246 } else if (_errorHandler != null) { | 121 } else if (_errorHandler != null) { |
247 if (recursive) { | 122 if (recursive) { |
248 _errorHandler("Recursive directory deletion failed: $_path"); | 123 _errorHandler("Recursive directory deletion failed: $_path"); |
249 } else { | 124 } else { |
250 _errorHandler("Non-recursive directory deletion failed: $_path"); | 125 _errorHandler("Non-recursive directory deletion failed: $_path"); |
251 } | 126 } |
252 } | 127 } |
253 }); | 128 }); |
254 } | 129 } |
255 | 130 |
256 void deleteSync([bool recursive = false]) { | 131 void deleteSync([bool recursive = false]) { |
257 if (!_delete(_path, recursive)) { | 132 if (!_delete(_path, recursive)) { |
258 throw new DirectoryException("Directory deletion failed: $_path"); | 133 throw new DirectoryException("Directory deletion failed: $_path"); |
259 } | 134 } |
260 } | 135 } |
261 | 136 |
262 void list([bool recursive = false]) { | 137 void list([bool recursive = false]) { |
263 new _DirectoryListingIsolate().spawn().then((port) { | 138 final int kListDirectory = 0; |
264 // Build a map of parameters to the directory listing isolate. | 139 final int kListFile = 1; |
265 Map listingParameters = new Map(); | 140 final int kListError = 2; |
266 listingParameters['dir'] = _path; | 141 final int kListDone = 3; |
267 listingParameters['recursive'] = recursive; | |
268 | 142 |
269 // Setup ports to receive messages from listing. | 143 List request = new List(3); |
270 // TODO(ager): Do not explicitly transform to send ports when | 144 request[0] = kListRequest; |
271 // implicit conversions are implemented. | 145 request[1] = _path; |
272 ReceivePort dirPort; | 146 request[2] = recursive; |
273 ReceivePort filePort; | 147 ReceivePort responsePort = new ReceivePort(); |
274 ReceivePort donePort; | 148 // Use a separate directory service port for each listing as |
275 ReceivePort errorPort; | 149 // listing operations on the same directory can run in parallel. |
276 if (_dirHandler !== null) { | 150 _newServicePort().send(request, responsePort.toSendPort()); |
277 dirPort = new ReceivePort(); | 151 responsePort.receive((message, replyTo) { |
278 dirPort.receive((String dir, ignored) { | 152 if (message is !List || message[0] is !int) { |
279 _dirHandler(dir); | 153 responsePort.close(); |
280 }); | 154 if (_errorHandler != null) _errorHandler("Internal error"); |
281 listingParameters['dirPort'] = dirPort.toSendPort(); | 155 return; |
282 } | 156 } |
283 if (_fileHandler !== null) { | 157 switch (message[0]) { |
284 filePort = new ReceivePort(); | 158 case kListDirectory: |
285 filePort.receive((String file, ignored) { | 159 if (_dirHandler != null) _dirHandler(message[1]); |
286 _fileHandler(file); | 160 break; |
287 }); | 161 case kListFile: |
288 listingParameters['filePort'] = filePort.toSendPort(); | 162 if (_fileHandler != null) _fileHandler(message[1]); |
| 163 break; |
| 164 case kListError: |
| 165 if (_errorHandler != null) _errorHandler(message[1]); |
| 166 break; |
| 167 case kListDone: |
| 168 responsePort.close(); |
| 169 if (_doneHandler != null) _doneHandler(message[1]); |
| 170 break; |
289 } | 171 } |
290 if (_doneHandler !== null) { | |
291 donePort = new ReceivePort.singleShot(); | |
292 donePort.receive((bool completed, ignored) { | |
293 _doneHandler(completed); | |
294 }); | |
295 listingParameters['donePort'] = donePort.toSendPort(); | |
296 } | |
297 if (_errorHandler !== null) { | |
298 errorPort = new ReceivePort.singleShot(); | |
299 errorPort.receive((String error, ignored) { | |
300 _errorHandler(error); | |
301 }); | |
302 listingParameters['errorPort'] = errorPort.toSendPort(); | |
303 } | |
304 | |
305 // Close ports when listing is done. | |
306 ReceivePort closePortsPort = new ReceivePort(); | |
307 closePortsPort.receive((message, replyTo) { | |
308 if (!message) { | |
309 errorPort.toSendPort().send( | |
310 "Failed to list directory: $_path recursive: $recursive"); | |
311 donePort.toSendPort().send(false); | |
312 } else { | |
313 _closePort(errorPort); | |
314 _closePort(donePort); | |
315 } | |
316 _closePort(dirPort); | |
317 _closePort(filePort); | |
318 _closePort(closePortsPort); | |
319 }); | |
320 | |
321 // Send the listing parameters to the isolate. | |
322 port.send(listingParameters, closePortsPort.toSendPort()); | |
323 }); | 172 }); |
324 } | 173 } |
325 | 174 |
326 void set dirHandler(void dirHandler(String dir)) { | 175 void set dirHandler(void dirHandler(String dir)) { |
327 _dirHandler = dirHandler; | 176 _dirHandler = dirHandler; |
328 } | 177 } |
329 | 178 |
330 void set fileHandler(void fileHandler(String file)) { | 179 void set fileHandler(void fileHandler(String file)) { |
331 _fileHandler = fileHandler; | 180 _fileHandler = fileHandler; |
332 } | 181 } |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
366 var _dirHandler; | 215 var _dirHandler; |
367 var _fileHandler; | 216 var _fileHandler; |
368 var _doneHandler; | 217 var _doneHandler; |
369 var _existsHandler; | 218 var _existsHandler; |
370 var _createHandler; | 219 var _createHandler; |
371 var _createTempHandler; | 220 var _createTempHandler; |
372 var _deleteHandler; | 221 var _deleteHandler; |
373 var _errorHandler; | 222 var _errorHandler; |
374 | 223 |
375 String _path; | 224 String _path; |
376 _DirectoryOperationScheduler _scheduler; | 225 SendPort _directoryService; |
377 } | 226 } |
OLD | NEW |