OLD | NEW |
| (Empty) |
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 | |
6 class _Directory implements Directory { | |
7 static const CREATE_REQUEST = 0; | |
8 static const DELETE_REQUEST = 1; | |
9 static const EXISTS_REQUEST = 2; | |
10 static const CREATE_TEMP_REQUEST = 3; | |
11 static const LIST_REQUEST = 4; | |
12 static const RENAME_REQUEST = 5; | |
13 | |
14 static const SUCCESS_RESPONSE = 0; | |
15 static const ILLEGAL_ARGUMENT_RESPONSE = 1; | |
16 static const OSERROR_RESPONSE = 2; | |
17 | |
18 _Directory(String this._path); | |
19 _Directory.fromPath(Path path) : this(path.toNativePath()); | |
20 _Directory.current() : this(_current()); | |
21 | |
22 static String _current() native "Directory_Current"; | |
23 static _createTemp(String template) native "Directory_CreateTemp"; | |
24 static int _exists(String path) native "Directory_Exists"; | |
25 static _create(String path) native "Directory_Create"; | |
26 static _delete(String path, bool recursive) native "Directory_Delete"; | |
27 static _rename(String path, String newPath) native "Directory_Rename"; | |
28 static SendPort _newServicePort() native "Directory_NewServicePort"; | |
29 | |
30 Future<bool> exists() { | |
31 _ensureDirectoryService(); | |
32 List request = new List(2); | |
33 request[0] = EXISTS_REQUEST; | |
34 request[1] = _path; | |
35 return _directoryService.call(request).transform((response) { | |
36 if (_isErrorResponse(response)) { | |
37 throw _exceptionFromResponse(response, "Exists failed"); | |
38 } | |
39 return response == 1; | |
40 }); | |
41 } | |
42 | |
43 bool existsSync() { | |
44 if (_path is !String) { | |
45 throw new ArgumentError(); | |
46 } | |
47 var result = _exists(_path); | |
48 if (result is OSError) { | |
49 throw new DirectoryIOException("Exists failed", _path, result); | |
50 } | |
51 return (result == 1); | |
52 } | |
53 | |
54 Future<Directory> create() { | |
55 _ensureDirectoryService(); | |
56 List request = new List(2); | |
57 request[0] = CREATE_REQUEST; | |
58 request[1] = _path; | |
59 return _directoryService.call(request).transform((response) { | |
60 if (_isErrorResponse(response)) { | |
61 throw _exceptionFromResponse(response, "Creation failed"); | |
62 } | |
63 return this; | |
64 }); | |
65 } | |
66 | |
67 void createSync() { | |
68 if (_path is !String) { | |
69 throw new ArgumentError(); | |
70 } | |
71 var result = _create(_path); | |
72 if (result is OSError) { | |
73 throw new DirectoryIOException("Creation failed", _path, result); | |
74 } | |
75 } | |
76 | |
77 Future<Directory> createTemp() { | |
78 _ensureDirectoryService(); | |
79 List request = new List(2); | |
80 request[0] = CREATE_TEMP_REQUEST; | |
81 request[1] = _path; | |
82 return _directoryService.call(request).transform((response) { | |
83 if (_isErrorResponse(response)) { | |
84 throw _exceptionFromResponse(response, | |
85 "Creation of temporary directory failed"); | |
86 } | |
87 return new Directory(response); | |
88 }); | |
89 } | |
90 | |
91 Directory createTempSync() { | |
92 if (_path is !String) { | |
93 throw new ArgumentError(); | |
94 } | |
95 var result = _createTemp(path); | |
96 if (result is OSError) { | |
97 throw new DirectoryIOException("Creation of temporary directory failed", | |
98 _path, | |
99 result); | |
100 } | |
101 return new Directory(result); | |
102 } | |
103 | |
104 Future<Directory> _deleteHelper(bool recursive, String errorMsg) { | |
105 _ensureDirectoryService(); | |
106 List request = new List(3); | |
107 request[0] = DELETE_REQUEST; | |
108 request[1] = _path; | |
109 request[2] = recursive; | |
110 return _directoryService.call(request).transform((response) { | |
111 if (_isErrorResponse(response)) { | |
112 throw _exceptionFromResponse(response, errorMsg); | |
113 } | |
114 return this; | |
115 }); | |
116 return completer.future; | |
117 } | |
118 | |
119 Future<Directory> delete() { | |
120 return _deleteHelper(false, "Deletion failed"); | |
121 } | |
122 | |
123 void deleteSync() { | |
124 if (_path is !String) { | |
125 throw new ArgumentError(); | |
126 } | |
127 var result = _delete(_path, false); | |
128 if (result is OSError) { | |
129 throw new DirectoryIOException("Deletion failed", _path, result); | |
130 } | |
131 } | |
132 | |
133 Future<Directory> deleteRecursively() { | |
134 return _deleteHelper(true, "Deletion failed"); | |
135 } | |
136 | |
137 void deleteRecursivelySync() { | |
138 if (_path is !String) { | |
139 throw new ArgumentError(); | |
140 } | |
141 var result = _delete(_path, true); | |
142 if (result is OSError) { | |
143 throw new DirectoryIOException("Deletion failed", _path, result); | |
144 } | |
145 } | |
146 | |
147 Future<Directory> rename(String newPath) { | |
148 _ensureDirectoryService(); | |
149 List request = new List(3); | |
150 request[0] = RENAME_REQUEST; | |
151 request[1] = _path; | |
152 request[2] = newPath; | |
153 return _directoryService.call(request).transform((response) { | |
154 if (_isErrorResponse(response)) { | |
155 throw _exceptionFromResponse(response, "Rename failed"); | |
156 } | |
157 return new Directory(newPath); | |
158 }); | |
159 } | |
160 | |
161 Directory renameSync(String newPath) { | |
162 if (_path is !String || newPath is !String) { | |
163 throw new ArgumentError(); | |
164 } | |
165 var result = _rename(_path, newPath); | |
166 if (result is OSError) { | |
167 throw new DirectoryIOException("Rename failed", _path, result); | |
168 } | |
169 return new Directory(newPath); | |
170 } | |
171 | |
172 DirectoryLister list({bool recursive: false}) { | |
173 return new _DirectoryLister(_path, recursive); | |
174 } | |
175 | |
176 String get path { return _path; } | |
177 | |
178 bool _isErrorResponse(response) { | |
179 return response is List && response[0] != _SUCCESS_RESPONSE; | |
180 } | |
181 | |
182 Exception _exceptionFromResponse(response, String message) { | |
183 assert(_isErrorResponse(response)); | |
184 switch (response[_ERROR_RESPONSE_ERROR_TYPE]) { | |
185 case _ILLEGAL_ARGUMENT_RESPONSE: | |
186 return new ArgumentError(); | |
187 case _OSERROR_RESPONSE: | |
188 var err = new OSError(response[_OSERROR_RESPONSE_MESSAGE], | |
189 response[_OSERROR_RESPONSE_ERROR_CODE]); | |
190 return new DirectoryIOException(message, _path, err); | |
191 default: | |
192 return new Exception("Unknown error"); | |
193 } | |
194 } | |
195 | |
196 void _ensureDirectoryService() { | |
197 if (_directoryService == null) { | |
198 _directoryService = _newServicePort(); | |
199 } | |
200 } | |
201 | |
202 final String _path; | |
203 SendPort _directoryService; | |
204 } | |
205 | |
206 class _DirectoryLister implements DirectoryLister { | |
207 _DirectoryLister(String path, bool recursive) { | |
208 const int LIST_DIRECTORY = 0; | |
209 const int LIST_FILE = 1; | |
210 const int LIST_ERROR = 2; | |
211 const int LIST_DONE = 3; | |
212 | |
213 final int RESPONSE_TYPE = 0; | |
214 final int RESPONSE_PATH = 1; | |
215 final int RESPONSE_COMPLETE = 1; | |
216 final int RESPONSE_ERROR = 2; | |
217 | |
218 List request = new List(3); | |
219 request[0] = _Directory.LIST_REQUEST; | |
220 request[1] = path; | |
221 request[2] = recursive; | |
222 ReceivePort responsePort = new ReceivePort(); | |
223 // Use a separate directory service port for each listing as | |
224 // listing operations on the same directory can run in parallel. | |
225 _Directory._newServicePort().send(request, responsePort.toSendPort()); | |
226 responsePort.receive((message, replyTo) { | |
227 if (message is !List || message[RESPONSE_TYPE] is !int) { | |
228 responsePort.close(); | |
229 _reportError(new DirectoryIOException("Internal error")); | |
230 return; | |
231 } | |
232 switch (message[RESPONSE_TYPE]) { | |
233 case LIST_DIRECTORY: | |
234 if (_onDir != null) _onDir(message[RESPONSE_PATH]); | |
235 break; | |
236 case LIST_FILE: | |
237 if (_onFile != null) _onFile(message[RESPONSE_PATH]); | |
238 break; | |
239 case LIST_ERROR: | |
240 var errorType = | |
241 message[RESPONSE_ERROR][_ERROR_RESPONSE_ERROR_TYPE]; | |
242 if (errorType == _ILLEGAL_ARGUMENT_RESPONSE) { | |
243 _reportError(new ArgumentError()); | |
244 } else if (errorType == _OSERROR_RESPONSE) { | |
245 var responseError = message[RESPONSE_ERROR]; | |
246 var err = new OSError( | |
247 responseError[_OSERROR_RESPONSE_MESSAGE], | |
248 responseError[_OSERROR_RESPONSE_ERROR_CODE]); | |
249 var errorPath = message[RESPONSE_PATH]; | |
250 if (errorPath == null) errorPath = path; | |
251 _reportError(new DirectoryIOException("Directory listing failed", | |
252 errorPath, | |
253 err)); | |
254 } else { | |
255 _reportError(new DirectoryIOException("Internal error")); | |
256 } | |
257 break; | |
258 case LIST_DONE: | |
259 responsePort.close(); | |
260 if (_onDone != null) _onDone(message[RESPONSE_COMPLETE]); | |
261 break; | |
262 } | |
263 }); | |
264 } | |
265 | |
266 void set onDir(void onDir(String dir)) { | |
267 _onDir = onDir; | |
268 } | |
269 | |
270 void set onFile(void onFile(String file)) { | |
271 _onFile = onFile; | |
272 } | |
273 | |
274 void set onDone(void onDone(bool completed)) { | |
275 _onDone = onDone; | |
276 } | |
277 | |
278 void set onError(void onError(e)) { | |
279 _onError = onError; | |
280 } | |
281 | |
282 void _reportError(e) { | |
283 if (_onError != null) { | |
284 _onError(e); | |
285 } else { | |
286 throw e; | |
287 } | |
288 } | |
289 | |
290 Function _onDir; | |
291 Function _onFile; | |
292 Function _onDone; | |
293 Function _onError; | |
294 } | |
OLD | NEW |