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

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

Issue 2120473004: Reimplement devfs in dart. Implementation now writes to disk. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: code review Created 4 years, 5 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
« no previous file with comments | « runtime/vm/dev_fs.h ('k') | runtime/vm/service.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 #ifndef PRODUCT
6
7 #include <map>
8 #include <string>
9 #include <vector>
10
11 #include "vm/dev_fs.h"
12
13 #include "vm/hash_table.h"
14 #include "vm/json_stream.h"
15 #include "vm/lockers.h"
16 #include "vm/object.h"
17 #include "vm/unicode.h"
18
19 namespace dart {
20
21 static const uint8_t decode_table[256] = {
22 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
23 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
24 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63,
25 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64,
26 64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
27 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 64,
28 64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
29 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 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 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
37 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64
38 };
39
40 class Base64 {
41 public:
42 static void decode(const char* base64,
43 std::vector<uint8_t>* output) {
44 ASSERT(output != NULL);
45 ASSERT(base64 != NULL);
46 const intptr_t base64_len = strlen(base64);
47 int b[4];
48 for (intptr_t i = 0; i < base64_len; i += 4) {
49 b[0] = decode_table[static_cast<uint8_t>(base64[i])];
50 b[1] = decode_table[static_cast<uint8_t>(base64[i + 1])];
51 b[2] = decode_table[static_cast<uint8_t>(base64[i + 2])];
52 b[3] = decode_table[static_cast<uint8_t>(base64[i + 3])];
53 output->push_back((b[0] << 2) | (b[1] >> 4));
54 if (b[2] < 64) {
55 output->push_back((b[1] << 4) | (b[2] >> 2));
56 if (b[3] < 64) {
57 output->push_back((b[2] << 6) | b[3]);
58 }
59 }
60 }
61 }
62 };
63
64
65 class FileSystem {
66 public:
67 explicit FileSystem(const std::string& name)
68 : name_(name) {
69 }
70
71 ~FileSystem() {
72 }
73
74 bool ReadFile(const std::string& path,
75 std::vector<uint8_t>** file_contents) {
76 *file_contents = NULL;
77 std::map<std::string, std::vector<uint8_t>*>::iterator iter;
78 iter = files_.find(path);
79 if (iter == files_.end()) {
80 return false;
81 }
82 *file_contents = iter->second;
83 return true;
84 }
85
86 void DeleteFile(const std::string& path) {
87 std::map<std::string, std::vector<uint8_t>*>::iterator iter;
88 iter = files_.find(path);
89 if (iter == files_.end()) {
90 return;
91 }
92 std::vector<uint8_t>* contents = iter->second;
93 files_.erase(iter);
94 delete contents;
95 }
96
97 void WriteFile(const std::string& path,
98 const char* file_contents) {
99 DeleteFile(path);
100 std::vector<uint8_t>* data = new std::vector<uint8_t>();
101 Base64::decode(file_contents, data);
102 files_[path] = data;
103 }
104
105 void ListFiles(JSONStream* js) {
106 JSONObject jsobj(js);
107 jsobj.AddProperty("type", "FSFilesList");
108 JSONArray jsarr(&jsobj, "files");
109 std::map<std::string, std::vector<uint8_t>*>::iterator iter;
110 for (iter = files_.begin(); iter != files_.end(); iter++) {
111 JSONObject file_info(&jsarr);
112 file_info.AddProperty("name", iter->first.c_str());
113 file_info.AddProperty64("size",
114 static_cast<int64_t>(iter->second->size()));
115 }
116 }
117
118 private:
119 std::string name_;
120
121 std::map<std::string, std::vector<uint8_t>*> files_;
122 };
123
124 // Some static state is held outside of the DevFS class so that we don't
125 // have to include stl headers in our vm/ headers.
126 static std::map<std::string, FileSystem*>* file_systems_;
127
128 Mutex* DevFS::mutex_ = NULL;
129
130
131 void DevFS::Init() {
132 if (mutex_ != NULL) {
133 // Already initialized.
134 ASSERT(file_systems_ != NULL);
135 return;
136 }
137 mutex_ = new Mutex();
138 file_systems_ = new std::map<std::string, FileSystem*>();
139 ASSERT(mutex_ != NULL);
140 ASSERT(file_systems_ != NULL);
141 }
142
143
144 void DevFS::Cleanup() {
145 delete mutex_;
146 mutex_ = NULL;
147 std::map<std::string, FileSystem*>::iterator iter;
148 for (iter = file_systems_->begin(); iter != file_systems_->end(); iter++) {
149 FileSystem* fs = iter->second;
150 delete fs;
151 }
152 delete file_systems_;
153 file_systems_ = NULL;
154 }
155
156
157 void DevFS::ListFileSystems(JSONStream* js) {
158 SafepointMutexLocker ml(mutex_);
159 JSONObject jsobj(js);
160 jsobj.AddProperty("type", "FSList");
161 JSONArray jsarr(&jsobj, "fsNames");
162
163 std::map<std::string, FileSystem*>::iterator iter;
164 for (iter = file_systems_->begin(); iter != file_systems_->end(); iter++) {
165 const std::string& key = iter->first;
166 jsarr.AddValue(key.c_str());
167 }
168 }
169
170
171 FileSystem* DevFS::LookupFileSystem(const char* fs_name) {
172 std::string key = std::string(fs_name);
173 std::map<std::string, FileSystem*>::iterator iter;
174 iter = file_systems_->find(key);
175 if (iter != file_systems_->end()) {
176 return iter->second;
177 }
178 return NULL;
179 }
180
181
182 FileSystem* DevFS::LookupFileSystem(const String& fs_name) {
183 return LookupFileSystem(fs_name.ToCString());
184 }
185
186
187 void DevFS::CreateFileSystem(JSONStream* js, const String& fs_name) {
188 SafepointMutexLocker ml(mutex_);
189 // TODO(turnidge): Ensure that fs_name is a legal URI host value, i.e. ascii.
190 if (LookupFileSystem(fs_name) != NULL) {
191 js->PrintError(kFileSystemAlreadyExists,
192 "%s: file system '%s' already exists",
193 js->method(), fs_name.ToCString());
194 return;
195 }
196
197 std::string key = std::string(fs_name.ToCString());
198 FileSystem* file_system = new FileSystem(key);
199 (*file_systems_)[key] = file_system;
200
201 JSONObject jsobj(js);
202 jsobj.AddProperty("type", "Success");
203 }
204
205
206 void DevFS::DeleteFileSystem(JSONStream* js, const String& fs_name) {
207 SafepointMutexLocker ml(mutex_);
208 FileSystem* file_system = LookupFileSystem(fs_name);
209 if (file_system == NULL) {
210 js->PrintError(kFileSystemDoesNotExist,
211 "%s: file system '%s' does not exist",
212 js->method(), fs_name.ToCString());
213 return;
214 }
215 std::string key = std::string(fs_name.ToCString());
216 file_systems_->erase(key);
217 delete file_system;
218 JSONObject jsobj(js);
219 jsobj.AddProperty("type", "Success");
220 }
221
222
223 void DevFS::ListFiles(JSONStream* js, const String& fs_name) {
224 SafepointMutexLocker ml(mutex_);
225 FileSystem* file_system = LookupFileSystem(fs_name);
226 if (file_system == NULL) {
227 js->PrintError(kFileSystemDoesNotExist,
228 "%s: file system '%s' does not exist",
229 js->method(), fs_name.ToCString());
230 return;
231 }
232
233 file_system->ListFiles(js);
234 }
235
236
237 static void PrintWriteFilesError(JSONStream* js,
238 intptr_t i) {
239 js->PrintError(kInvalidParams,
240 "%s: files array invalid at index '%" Pd "'",
241 js->method(), i);
242 }
243
244
245 void DevFS::WriteFiles(JSONStream* js,
246 const String& fs_name,
247 const Array& files) {
248 SafepointMutexLocker ml(mutex_);
249 FileSystem* file_system = LookupFileSystem(fs_name);
250 if (file_system == NULL) {
251 js->PrintError(kFileSystemDoesNotExist,
252 "%s: file system '%s' does not exist",
253 js->method(), fs_name.ToCString());
254 return;
255 }
256
257 Object& test = Object::Handle();
258 GrowableObjectArray& file_info = GrowableObjectArray::Handle();
259 String& path = String::Handle();
260 String& file_contents = String::Handle();
261
262 // First, validate the array of files is properly formed.
263 for (intptr_t i = 0; i < files.Length(); i++) {
264 test = files.At(i);
265 if (!test.IsGrowableObjectArray()) {
266 PrintWriteFilesError(js, i);
267 return;
268 }
269 file_info ^= test.raw();
270 if (file_info.Length() != 2) {
271 PrintWriteFilesError(js, i);
272 return;
273 }
274 test = file_info.At(0);
275 if (!test.IsString()) {
276 PrintWriteFilesError(js, i);
277 return;
278 }
279 std::string key = std::string(String::Cast(test).ToCString());
280 if ((key.size() == 0) || (key[0] != '/')) {
281 js->PrintError(kInvalidParams,
282 "%s: file system path '%s' must begin with a /",
283 js->method(), String::Cast(test).ToCString());
284 return;
285 }
286 test = file_info.At(1);
287 if (!test.IsString()) {
288 PrintWriteFilesError(js, i);
289 return;
290 }
291 }
292
293 // Now atomically update the file system.
294 for (intptr_t i = 0; i < files.Length(); i++) {
295 file_info = GrowableObjectArray::RawCast(files.At(i));
296 path = String::RawCast(file_info.At(0));
297 file_contents = String::RawCast(file_info.At(1));
298 file_system->WriteFile(path.ToCString(),
299 file_contents.ToCString());
300 }
301
302 JSONObject jsobj(js);
303 jsobj.AddProperty("type", "Success");
304 }
305
306
307 void DevFS::WriteFile(JSONStream* js,
308 const String& fs_name,
309 const String& path,
310 const String& file_contents) {
311 SafepointMutexLocker ml(mutex_);
312 FileSystem* file_system = LookupFileSystem(fs_name);
313 if (file_system == NULL) {
314 js->PrintError(kFileSystemDoesNotExist,
315 "%s: file system '%s' does not exist",
316 js->method(), fs_name.ToCString());
317 return;
318 }
319
320 std::string key = std::string(path.ToCString());
321 if ((key.size() == 0) || (key[0] != '/')) {
322 js->PrintError(kInvalidParams,
323 "%s: file system path '%s' must begin with a /",
324 js->method(), path.ToCString());
325 return;
326 }
327
328 file_system->WriteFile(path.ToCString(),
329 file_contents.ToCString());
330
331 JSONObject jsobj(js);
332 jsobj.AddProperty("type", "Success");
333 }
334
335
336 void DevFS::ReadFile(JSONStream* js,
337 const String& fs_name,
338 const String& path) {
339 SafepointMutexLocker ml(mutex_);
340 FileSystem* file_system = LookupFileSystem(fs_name);
341 if (file_system == NULL) {
342 js->PrintError(kFileSystemDoesNotExist,
343 "%s: file system '%s' does not exist",
344 js->method(), fs_name.ToCString());
345 return;
346 }
347
348 std::string key = std::string(path.ToCString());
349 if ((key.size() == 0) || (key[0] != '/')) {
350 js->PrintError(kInvalidParams,
351 "%s: file system path '%s' must begin with a /",
352 js->method(), path.ToCString());
353 return;
354 }
355 std::vector<uint8_t>* file_contents;
356
357 bool success = file_system->ReadFile(key, &file_contents);
358
359 if (!success) {
360 js->PrintError(kFileDoesNotExist,
361 "%s: file 'dart-devfs://%s/%s' does not exist",
362 js->method(), fs_name.ToCString(), path.ToCString());
363 return;
364 }
365
366 JSONObject jsobj(js);
367 jsobj.AddProperty("type", "FSFile");
368 jsobj.AddPropertyBase64("fileContents",
369 &((*file_contents)[0]),
370 file_contents->size());
371 }
372
373 } // namespace dart
374
375 #endif // !PRODUCT
OLDNEW
« no previous file with comments | « runtime/vm/dev_fs.h ('k') | runtime/vm/service.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698