Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(5)

Side by Side Diff: runtime/vm/dev_fs.cc

Issue 2059883003: DevFS initial implementation (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2016, 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 #include <map>
6 #include <string>
7 #include <vector>
8
9 #include "vm/dev_fs.h"
10
11 #include "vm/hash_table.h"
12 #include "vm/json_stream.h"
13 #include "vm/lockers.h"
14 #include "vm/object.h"
15 #include "vm/unicode.h"
16
17 namespace dart {
18
19 static const uint8_t decode_table[256] = {
20 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
21 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
22 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63,
23 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64,
24 64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
25 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 64,
26 64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
27 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, 64,
28 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
29 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
30 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
31 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
32 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
33 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
34 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
35 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64
36 };
37
38 class Base64 {
39 public:
40 static void decode(const char* base64,
41 std::vector<uint8_t>* output) {
42 ASSERT(output != NULL);
43 ASSERT(base64 != NULL);
44 const intptr_t base64_len = strlen(base64);
45 int b[4];
46 for (intptr_t i = 0; i < base64_len; i += 4) {
47 b[0] = decode_table[static_cast<uint8_t>(base64[i])];
48 b[1] = decode_table[static_cast<uint8_t>(base64[i + 1])];
49 b[2] = decode_table[static_cast<uint8_t>(base64[i + 2])];
50 b[3] = decode_table[static_cast<uint8_t>(base64[i + 3])];
51 output->push_back((b[0] << 2) | (b[1] >> 4));
52 if (b[2] < 64) {
53 output->push_back((b[1] << 4) | (b[2] >> 2));
54 if (b[3] < 64) {
55 output->push_back((b[2] << 6) | b[3]);
56 }
57 }
58 }
59 }
60 };
61
62
63 class FileSystem {
64 public:
65 explicit FileSystem(const std::string& name)
66 : name_(name) {
67 }
68
69 ~FileSystem() {
70 }
71
72 bool ReadFile(const std::string& path,
73 std::vector<uint8_t>** file_contents) {
74 *file_contents = NULL;
75 std::map<std::string, std::vector<uint8_t>*>::iterator iter;
76 iter = files_.find(path);
77 if (iter == files_.end()) {
78 return false;
79 }
80 *file_contents = iter->second;
81 return true;
82 }
83
84 void DeleteFile(const std::string& path) {
85 std::map<std::string, std::vector<uint8_t>*>::iterator iter;
86 iter = files_.find(path);
87 if (iter == files_.end()) {
88 return;
89 }
90 std::vector<uint8_t>* contents = iter->second;
91 files_.erase(iter);
92 delete contents;
93 }
94
95 void WriteFile(const std::string& path,
96 const char* file_contents) {
97 DeleteFile(path);
98 std::vector<uint8_t>* data = new std::vector<uint8_t>();
99 Base64::decode(file_contents, data);
100 files_[path] = data;
101 }
102
103 void WriteFileRaw(const std::string& path,
104 const char* file_contents) {
105 DeleteFile(path);
106 std::vector<uint8_t>* data = new std::vector<uint8_t>();
107 Base64::decode(file_contents, data);
108 files_[path] = data;
109 }
110
111 void ListFiles(JSONStream* js) {
112 JSONObject jsobj(js);
113 jsobj.AddProperty("type", "FSFilesList");
114 JSONArray jsarr(&jsobj, "files");
115 std::map<std::string, std::vector<uint8_t>*>::iterator iter;
116 for (iter = files_.begin(); iter != files_.end(); iter++) {
117 JSONObject file_info(&jsarr);
118 file_info.AddProperty("name", iter->first.c_str());
119 file_info.AddProperty("size", static_cast<int64_t>(iter->second->size()));
120 }
121 }
122
123 private:
124 std::string name_;
125
126 std::map<std::string, std::vector<uint8_t>*> files_;
127 };
128
129 // Some static state is held outside of the DevFS class so that we don't
130 // have to include stl headers in our vm/ headers.
131 static std::map<std::string, FileSystem*>* file_systems_;
132
133 Mutex* DevFS::mutex_ = NULL;
134
135
136 void DevFS::Init() {
137 if (mutex_ != NULL) {
138 // Already initialized.
139 ASSERT(file_systems_ != NULL);
140 return;
141 }
142 mutex_ = new Mutex();
143 file_systems_ = new std::map<std::string, FileSystem*>();
144 ASSERT(mutex_ != NULL);
145 ASSERT(file_systems_ != NULL);
146 }
147
148
149 void DevFS::Cleanup() {
150 delete mutex_;
151 mutex_ = NULL;
152 std::map<std::string, FileSystem*>::iterator iter;
153 for (iter = file_systems_->begin(); iter != file_systems_->end(); iter++) {
154 FileSystem* fs = iter->second;
155 delete fs;
156 }
157 delete file_systems_;
158 file_systems_ = NULL;
159 }
160
161
162 void DevFS::ListFileSystems(JSONStream* js) {
163 SafepointMutexLocker ml(mutex_);
164 JSONObject jsobj(js);
165 jsobj.AddProperty("type", "FSList");
166 JSONArray jsarr(&jsobj, "ids");
turnidge 2016/06/10 18:45:34 Do we want to call this ids still? Maybe fsNames?
167
168 std::map<std::string, FileSystem*>::iterator iter;
169 for (iter = file_systems_->begin(); iter != file_systems_->end(); iter++) {
170 const std::string& key = iter->first;
171 jsarr.AddValue(key.c_str());
172 }
173 }
174
175
176 FileSystem* DevFS::LookupFileSystem(const char* fs_name) {
177 std::string key = std::string(fs_name);
178 std::map<std::string, FileSystem*>::iterator iter;
179 iter = file_systems_->find(key);
180 if (iter != file_systems_->end()) {
181 return iter->second;
182 }
183 return NULL;
184 }
185
186
187 FileSystem* DevFS::LookupFileSystem(const String& fs_name) {
188 return LookupFileSystem(fs_name.ToCString());
189 }
190
191
192 void DevFS::CreateFileSystem(JSONStream* js, const String& fs_name) {
193 SafepointMutexLocker ml(mutex_);
194 // TODO(turnidge): Ensure that fs_name is a legal URI host value, i.e. ascii.
195 if (LookupFileSystem(fs_name) != NULL) {
196 js->PrintError(kFileSystemAlreadyExists,
197 "%s: file system '%s' already exists",
198 js->method(), fs_name.ToCString());
199 return;
200 }
201
202 std::string key = std::string(fs_name.ToCString());
203 FileSystem* file_system = new FileSystem(key);
204 (*file_systems_)[key] = file_system;
205
206 JSONObject jsobj(js);
207 jsobj.AddProperty("type", "Success");
208 }
209
210
211 void DevFS::DeleteFileSystem(JSONStream* js, const String& fs_name) {
212 SafepointMutexLocker ml(mutex_);
213 FileSystem* file_system = LookupFileSystem(fs_name);
214 if (file_system == NULL) {
215 js->PrintError(kFileSystemDoesNotExist,
216 "%s: file system '%s' does not exist",
217 js->method(), fs_name.ToCString());
218 return;
219 }
220 std::string key = std::string(fs_name.ToCString());
221 file_systems_->erase(key);
222 delete file_system;
223 JSONObject jsobj(js);
224 jsobj.AddProperty("type", "Success");
225 }
226
227
228 void DevFS::ListFiles(JSONStream* js, const String& fs_name) {
229 SafepointMutexLocker ml(mutex_);
230 FileSystem* file_system = LookupFileSystem(fs_name);
231 if (file_system == NULL) {
232 js->PrintError(kFileSystemDoesNotExist,
233 "%s: file system '%s' does not exist",
234 js->method(), fs_name.ToCString());
235 return;
236 }
237
238 file_system->ListFiles(js);
239 }
240
241
242 static void PrintWriteFilesError(JSONStream* js,
243 intptr_t i) {
244 js->PrintError(kInvalidParams,
245 "%s: files array invalid at index '%" Pd "'",
246 js->method(), i);
247 }
248
249
250 void DevFS::WriteFiles(JSONStream* js,
251 const String& fs_name,
252 const Array& files) {
253 SafepointMutexLocker ml(mutex_);
254 FileSystem* file_system = LookupFileSystem(fs_name);
255 if (file_system == NULL) {
256 js->PrintError(kFileSystemDoesNotExist,
257 "%s: file system '%s' does not exist",
258 js->method(), fs_name.ToCString());
259 return;
260 }
261
262 Object& test = Object::Handle();
263 GrowableObjectArray& file_info = GrowableObjectArray::Handle();
264 String& path = String::Handle();
265 String& file_contents = String::Handle();
266
267 // First, validate the array of files is properly formed.
268 for (intptr_t i = 0; i < files.Length(); i++) {
269 test = files.At(i);
270 if (!test.IsGrowableObjectArray()) {
271 PrintWriteFilesError(js, i);
272 return;
273 }
274 file_info ^= test.raw();
275 if (file_info.Length() != 2) {
276 PrintWriteFilesError(js, i);
277 return;
278 }
279 test = file_info.At(0);
280 if (!test.IsString()) {
281 PrintWriteFilesError(js, i);
282 return;
283 }
284 test = file_info.At(1);
285 if (!test.IsString()) {
286 PrintWriteFilesError(js, i);
287 return;
288 }
289 }
290
291 // Now atomically update the file system.
292 for (intptr_t i = 0; i < files.Length(); i++) {
293 file_info = GrowableObjectArray::RawCast(files.At(i));
294 path = String::RawCast(file_info.At(0));
295 file_contents = String::RawCast(file_info.At(1));
296 file_system->WriteFile(path.ToCString(),
297 file_contents.ToCString());
298 }
299
300 JSONObject jsobj(js);
301 jsobj.AddProperty("type", "Success");
302 }
303
304
305 void DevFS::WriteFile(JSONStream* js,
306 const String& fs_name,
307 const String& path,
308 const String& file_contents) {
309 SafepointMutexLocker ml(mutex_);
310 FileSystem* file_system = LookupFileSystem(fs_name);
311 if (file_system == NULL) {
312 js->PrintError(kFileSystemDoesNotExist,
313 "%s: file system '%s' does not exist",
314 js->method(), fs_name.ToCString());
315 return;
316 }
317
318 file_system->WriteFile(path.ToCString(),
319 file_contents.ToCString());
320
321 JSONObject jsobj(js);
322 jsobj.AddProperty("type", "Success");
323 }
324
325
326 void DevFS::WriteFileRaw(JSONStream* js,
327 const String& fs_name,
328 const String& path,
329 const String& file_contents) {
330 SafepointMutexLocker ml(mutex_);
331 FileSystem* file_system = LookupFileSystem(fs_name);
332 if (file_system == NULL) {
333 js->PrintError(kFileSystemDoesNotExist,
334 "%s: file system '%s' does not exist",
335 js->method(), fs_name.ToCString());
336 return;
337 }
338
339 file_system->WriteFile(path.ToCString(),
340 file_contents.ToCString());
341
342 JSONObject jsobj(js);
343 jsobj.AddProperty("type", "Success");
344 }
345
346
347 void DevFS::ReadFile(JSONStream* js,
348 const String& fs_name,
349 const String& path) {
350 SafepointMutexLocker ml(mutex_);
351 FileSystem* file_system = LookupFileSystem(fs_name);
352 if (file_system == NULL) {
353 js->PrintError(kFileSystemDoesNotExist,
354 "%s: file system '%s' does not exist",
355 js->method(), fs_name.ToCString());
356 return;
357 }
358
359 std::string key = std::string(path.ToCString());
360 std::vector<uint8_t>* file_contents;
361
362 bool success = file_system->ReadFile(key, &file_contents);
363
364 if (!success) {
365 js->PrintError(kFileDoesNotExist,
366 "%s: file 'dart-devfs://%s/%s' does not exist",
367 js->method(), fs_name.ToCString(), path.ToCString());
368 return;
369 }
370
371 JSONObject jsobj(js);
372 jsobj.AddProperty("type", "FSFile");
373 jsobj.AddPropertyBase64("fileContents",
374 &((*file_contents)[0]),
375 file_contents->size());
376 }
377
378 Dart_Handle DevFS::ReadFile(const char* fs_name,
379 const char* path) {
380 SafepointMutexLocker ml(mutex_);
381 Thread* T = Thread::Current();
382 FileSystem* file_system = LookupFileSystem(fs_name);
383 if (file_system == NULL) {
384 return Api::NewError("File system '%s' does not exist", fs_name);
385 }
386
387 std::string key = std::string(path);
388 std::vector<uint8_t>* file_contents;
389
390 bool success = file_system->ReadFile(key, &file_contents);
391
392 if (!success) {
393 return Api::NewError("File '%s' does not exist", path);
394 }
395
396 CHECK_CALLBACK_STATE(T);
397
398 const TypedData& typed_data =
399 TypedData::Handle(TypedData::New(kTypedDataUint8ArrayCid,
400 file_contents->size()));
401
402 {
403 NoSafepointScope scope;
404 uint8_t* destination = reinterpret_cast<uint8_t*>(typed_data.DataAddr(0));
405 memmove(destination, &((*file_contents)[0]), file_contents->size());
406 }
407
408 return Api::NewHandle(T, typed_data.raw());
409 }
410
411
412 Dart_Handle DevFS::ReadFileAsString(const char* fs_name,
413 const char* path) {
414 SafepointMutexLocker ml(mutex_);
415 Thread* T = Thread::Current();
416 FileSystem* file_system = LookupFileSystem(fs_name);
417 if (file_system == NULL) {
418 return Api::NewError("File system '%s' does not exist", fs_name);
419 }
420
421 std::string key = std::string(path);
422 std::vector<uint8_t>* file_contents;
423
424 bool success = file_system->ReadFile(key, &file_contents);
425
426 if (!success) {
427 return Api::NewError("File '%s' does not exist", path);
428 }
429
430 uint8_t* data = &((*file_contents)[0]);
431 int64_t length = file_contents->size();
432 CHECK_LENGTH(length, String::kMaxElements);
433 if (!Utf8::IsValid(&((*file_contents)[0]), file_contents->size())) {
434 return Api::NewError("File '%s' does not contain a valid UTF-8 string",
435 path);
436 }
437 CHECK_CALLBACK_STATE(T);
438 return Api::NewHandle(T, String::FromUTF8(data, length));
439 }
440
441
442 Dart_Handle LibraryTagHandler(Dart_LibraryTag tag,
443 Dart_Handle library,
444 Dart_Handle url) {
445 if (tag == Dart_kCanonicalizeUrl) {
446 return Dart_DefaultCanonicalizeUrl(library, url);
447 }
448
449 Dart_Handle source = Dart_DevFSReadFileAsUTF8String(url);
450
451 if (Dart_IsError(source)) {
452 return source;
453 }
454
455 // Lookup the library's url.
456 Dart_Handle library_url = Dart_LibraryUrl(library);
457
458 switch (tag) {
459 case Dart_kImportTag:
460 return Dart_LoadLibrary(url, source, 0, 0);
461 break;
462 case Dart_kSourceTag: {
463 Dart_Handle library = Dart_LookupLibrary(library_url);
464 if (Dart_IsError(library)) {
465 return library;
466 }
467 return Dart_LoadSource(library, url, source, 0, 0);
468 }
469 break;
470 case Dart_kScriptTag:
471 return Dart_LoadScript(url, source, 0, 0);
472 break;
473 default:
474 UNREACHABLE();
475 return Dart_Null();
476 }
477 }
478
479 } // namespace dart
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698