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

Side by Side Diff: native_client_sdk/src/libraries/nacl_io/googledrivefs/googledrivefs.cc

Issue 2156503002: [NaCl SDK] Expose Google Drive to nacl_io. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: 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
OLDNEW
(Empty)
1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "nacl_io/googledrivefs/googledrivefs.h"
6
7 #include <fcntl.h>
8
9 #include <map>
10 #include <algorithm>
11 #include <cstdio>
12
13 #include "ppapi/cpp/url_request_info.h"
14 #include "ppapi/cpp/url_response_info.h"
15 #include "ppapi/cpp/url_loader.h"
16 #include "ppapi/cpp/file_ref.h"
17 #include "ppapi/cpp/file_io.h"
18
19 #include "nacl_io/error.h"
20 #include "nacl_io/pepper_interface.h"
21 #include "ppapi/c/pp_completion_callback.h"
22
23 #include "json/reader.h"
binji 2016/07/18 23:24:02 nacl_io currently does not depend on json; We're n
chanpatorikku 2016/08/07 02:41:02 Done. Thanks. Not going to add it as a new depend
24 #include "json/writer.h"
25
26 #include "nacl_io/filesystem.h"
27 #include "nacl_io/kernel_handle.h"
28 #include "nacl_io/getdents_helper.h"
29
30 #ifdef WIN32
31 #include <windows.h>
binji 2016/07/18 23:24:02 what is this needed for?
chanpatorikku 2016/08/07 02:41:02 This used to be needed for Sleep() from windows.h.
32 #else
33 #include <unistd.h>
34 #endif
35
36 namespace nacl_io {
37
38 namespace {
39
40 std::string MapToHeaders(
41 const std::map<std::string, std::string>& header_field_map) {
42 std::string request_headers = "";
43
44 for (std::map<std::string, std::string>::const_iterator it =
45 header_field_map.begin();
46 it != header_field_map.end(); ++it) {
47 request_headers += it->first;
48 request_headers += ": ";
49 request_headers += it->second;
50 request_headers += "\n";
51 }
52 return request_headers;
53 }
54
55 // Continuing DJB2a hash
56 ino_t HashPathSegment(ino_t hash, const char* str, size_t len) {
57 // First add the path seperator
58 hash = (hash * static_cast<ino_t>(33)) ^ '/';
59 while (len--) {
60 hash = (hash * static_cast<ino_t>(33)) ^ *str++;
61 }
62 return hash;
63 }
64
65 ino_t HashPath(const Path& path) {
binji 2016/07/18 23:24:02 better to share the code with Html5Fs rather than
chanpatorikku 2016/08/07 02:41:02 Done. Thanks. Shared the code with Html5Fs.
66 // Prime the DJB2a hash
67 ino_t hash = 5381;
68
69 // Apply a running DJB2a to each part of the path
70 for (size_t segment = 0; segment < path.Size(); segment++) {
71 const std::string& part = path.Part(segment);
72 hash = HashPathSegment(hash, part.c_str(), part.length());
73 }
74 return hash;
75 }
76
77 // A Google Drive item is a file or a directory.
78 // RequestDirId requests to see if a directory with dir_name
79 // and a parent with ID parent_dir_id is there.
80 // If it is, dir_id is set.
81 // RequestDirId returns ENOENT when a file with dir_name is there
82 // but a directory with dir_name is not.
83 Error RequestDirId(const std::string& parent_dir_id,
84 const std::string& dir_name,
85 Filesystem* filesystem,
86 std::string& dir_id) {
87 dir_id = "";
88
89 std::string url = "https://www.googleapis.com/drive/v3/files";
binji 2016/07/18 23:24:02 It's better to have these strings be constants (as
chanpatorikku 2016/08/07 02:41:02 Each URL may be different. I don't know if the cur
90 url += "?";
91 url += "q=";
92 url += "%27";
93 url += parent_dir_id;
94 url += "%27+in+parents";
95 url += "+and+";
96 url += "mimeType+=+";
97 url += "%27application/vnd.google-apps.folder%27";
98 url += "+and+";
99 url += "name+=+%27" + dir_name + "%27";
100
101 GoogleDriveFs* googledrivefs = dynamic_cast<GoogleDriveFs*>(filesystem);
binji 2016/07/18 23:24:02 don't use dynamic_cast, it relies on RTTI. static_
chanpatorikku 2016/08/07 02:41:02 Done. Thanks. static_cast is called in the curren
102 if (googledrivefs == NULL) {
103 return EINVAL;
104 }
105
106 pp::URLLoader loader(pp::InstanceHandle(googledrivefs->instance()));
binji 2016/07/18 23:24:02 nacl_io uses the Pepper C interface, not the C++ i
chanpatorikku 2016/08/07 02:41:02 Done. Thanks. Pepper C interface is used in the c
107 pp::URLRequestInfo request(pp::InstanceHandle(googledrivefs->instance()));
108
109 bool set_url_ok = request.SetURL(url);
binji 2016/07/18 23:24:02 it's better to just inline this than to create a n
chanpatorikku 2016/08/07 02:41:02 I don't know exactly about inlining. Please review
110 if (!set_url_ok) {
111 return EPERM;
112 }
113
114 bool set_method_ok = request.SetMethod("GET");
115 if (!set_method_ok) {
116 return EPERM;
117 }
118
119 std::map<std::string, std::string> headers_map;
binji 2016/07/18 23:24:02 This seems to be duplicated a number of times in t
chanpatorikku 2016/08/07 02:41:02 Done. Thanks. Tried factoring it in a similar way
120 headers_map["Content-type"] = "application/json";
121 std::string authorization_value = "Bearer ";
122 authorization_value += googledrivefs->token();
123 headers_map["Authorization"] = authorization_value;
124
125 std::string headers = MapToHeaders(headers_map);
126
127 bool set_headers_ok = request.SetHeaders(headers);
128 if (!set_headers_ok) {
129 return EPERM;
130 }
131
132 bool set_allow_cross_origin_requests_ok =
133 request.SetAllowCrossOriginRequests(true);
134 if (!set_allow_cross_origin_requests_ok) {
135 return EPERM;
136 }
137
138 bool set_stream_to_file_ok = request.SetStreamToFile(true);
139 if (!set_stream_to_file_ok) {
140 return EPERM;
141 }
142
143 int32_t err = loader.Open(request, pp::BlockUntilComplete());
144 if (err < 0) {
145 return PPERROR_TO_ERRNO(err);
146 }
147
148 pp::URLResponseInfo response = loader.GetResponseInfo();
149 if (response.GetStatusCode() != 200) {
150 return EPERM;
151 }
152
153 pp::FileRef file_ref = response.GetBodyAsFileRef();
154 pp::FileIO file_io(pp::InstanceHandle(googledrivefs->instance()));
155
156 int32_t open_result =
157 file_io.Open(file_ref, PP_FILEOPENFLAG_READ, pp::BlockUntilComplete());
158 if (open_result < 0) {
159 return PPERROR_TO_ERRNO(open_result);
160 }
161
162 int BUFFER_SIZE = 1024;
163 char buffer[BUFFER_SIZE];
binji 2016/07/18 23:24:02 What if the result is greater than 1024 bytes?
chanpatorikku 2016/08/07 02:41:02 Done. Thanks. Code is rewritten for the result gr
164
165 int32_t byte_read =
166 file_io.Read(0, buffer, BUFFER_SIZE, pp::BlockUntilComplete());
167 while (byte_read == 0) {
binji 2016/07/18 23:24:02 This loop is strange, what problem are you trying
chanpatorikku 2016/08/07 02:41:02 Done. The problem I was trying to fix was that Fi
168 #ifdef WIN32
169 Sleep(1000);
170 #else
171 usleep(1000000);
binji 2016/07/18 23:24:02 We never want to call sleep in nacl_io, it's usual
chanpatorikku 2016/08/07 02:41:02 Done. Sleep is not called in nacl_io in the curre
172 #endif
173
174 byte_read = file_io.Read(0, buffer, BUFFER_SIZE, pp::BlockUntilComplete());
175 }
176
177 if (byte_read < 0) {
178 return PPERROR_TO_ERRNO(byte_read);
179 }
180
181 std::string output(buffer);
182
183 Json::Value root;
184
185 Json::Reader reader(Json::Features::strictMode());
186 if (!reader.parse(output, root, false)) {
187 return EPERM;
188 }
189
190 if (!root.isMember("files")) {
191 return EPERM;
192 }
193
194 Json::Value files_array = root["files"];
195 if (!files_array.isArray()) {
196 return EPERM;
197 }
198 if (files_array.size() == 0) {
199 return ENOENT;
200 }
201
202 dir_id = files_array[0]["id"].asString();
203
204 return 0;
205 }
206
207 // A Google Drive item is a file or a directory.
208 // RequestItemId requests to see if either a file with item_name
209 // or a directory with item_name is there.
210 // If it is, item_id is set.
211 Error RequestItemId(const std::string& parent_dir_id,
212 const std::string& item_name,
213 Filesystem* filesystem,
214 std::string& item_id) {
215 item_id = "";
216
217 std::string url = "https://www.googleapis.com/drive/v3/files";
218 url += "?";
219 url += "q=";
220 url += "%27";
221 url += parent_dir_id;
222 url += "%27+in+parents";
223 url += "+and+";
224 url += "name+=+%27" + item_name + "%27";
225
226 GoogleDriveFs* googledrivefs = dynamic_cast<GoogleDriveFs*>(filesystem);
227 if (googledrivefs == NULL) {
228 return EINVAL;
229 }
230
231 pp::URLLoader loader(pp::InstanceHandle(googledrivefs->instance()));
232 pp::URLRequestInfo request(pp::InstanceHandle(googledrivefs->instance()));
233
234 bool set_url_ok = request.SetURL(url);
235 if (!set_url_ok) {
236 return EPERM;
237 }
238
239 bool set_method_ok = request.SetMethod("GET");
240 if (!set_method_ok) {
241 return EPERM;
242 }
243
244 std::map<std::string, std::string> headers_map;
245 headers_map["Content-type"] = "application/json";
246 std::string authorization_value = "Bearer ";
247 authorization_value += googledrivefs->token();
248 headers_map["Authorization"] = authorization_value;
249
250 std::string headers = MapToHeaders(headers_map);
251
252 bool set_headers_ok = request.SetHeaders(headers);
253 if (!set_headers_ok) {
254 return EPERM;
255 }
256
257 bool set_allow_cross_origin_requests_ok =
258 request.SetAllowCrossOriginRequests(true);
259 if (!set_allow_cross_origin_requests_ok) {
260 return EPERM;
261 }
262
263 bool set_stream_to_file_ok = request.SetStreamToFile(true);
264 if (!set_stream_to_file_ok) {
265 return EPERM;
266 }
267
268 int32_t err = loader.Open(request, pp::BlockUntilComplete());
269 if (err < 0) {
270 return PPERROR_TO_ERRNO(err);
271 }
272
273 pp::URLResponseInfo response = loader.GetResponseInfo();
274 if (response.GetStatusCode() != 200) {
275 return EPERM;
276 }
277
278 pp::FileRef file_ref = response.GetBodyAsFileRef();
279 pp::FileIO file_io(pp::InstanceHandle(googledrivefs->instance()));
280
281 int32_t open_result =
282 file_io.Open(file_ref, PP_FILEOPENFLAG_READ, pp::BlockUntilComplete());
283 if (open_result < 0) {
284 return PPERROR_TO_ERRNO(open_result);
285 }
286
287 int BUFFER_SIZE = 1024;
288 char buffer[BUFFER_SIZE];
289
290 int32_t byte_read =
291 file_io.Read(0, buffer, BUFFER_SIZE, pp::BlockUntilComplete());
292 while (byte_read == 0) {
293 #ifdef WIN32
294 Sleep(1000);
295 #else
296 usleep(1000000);
297 #endif
298
299 byte_read = file_io.Read(0, buffer, BUFFER_SIZE, pp::BlockUntilComplete());
300 }
301
302 if (byte_read < 0) {
303 return PPERROR_TO_ERRNO(byte_read);
304 }
305
306 std::string output(buffer);
307
308 Json::Value root;
309
310 Json::Reader reader(Json::Features::strictMode());
311 if (!reader.parse(output, root, false)) {
312 return EPERM;
313 }
314
315 if (!root.isMember("files")) {
316 return EPERM;
317 }
318
319 Json::Value files_array = root["files"];
320
321 if (!files_array.isArray()) {
322 return EPERM;
323 }
324 if (files_array.size() == 0) {
325 return ENOENT;
326 }
327
328 item_id = files_array[0]["id"].asString();
329
330 return 0;
331 }
332
333 Error RequestParentDirId(const Path& path,
334 Filesystem* filesystem,
335 std::string& parent_dir_id) {
binji 2016/07/18 23:24:02 Out parameters should be pointers, not references,
chanpatorikku 2016/08/07 02:41:02 Done. Thanks. Out parameters are pointers and are
336 parent_dir_id = "";
337
338 if (path.Size() < 2) {
339 return EINVAL;
340 }
341
342 std::string helper_parent_dir_id = "root";
343
344 for (unsigned int i = 1; i < path.Size() - 1; ++i) {
345 std::string dir_name = path.Range(i, i + 1);
346
347 std::string dir_id = "";
348 Error error =
349 RequestDirId(helper_parent_dir_id, dir_name, filesystem, dir_id);
350 if (error) {
351 return error;
352 }
353
354 helper_parent_dir_id = dir_id;
355 }
356 parent_dir_id = helper_parent_dir_id;
357
358 return 0;
359 }
360 }
361
362 class GoogleDriveFsNode : public Node {
binji 2016/07/18 23:24:02 It's generally nicer when the nodes are defined in
chanpatorikku 2016/08/07 02:41:02 Done. Thanks. Nodes are defined in a separate fil
363 public:
364 GoogleDriveFsNode(Filesystem* filesystem, Path path)
365 : Node(filesystem), path_(path) {}
366
367 Error GetDents(size_t offs,
368 struct dirent* pdir,
369 size_t size,
370 int* out_bytes) {
371 if (!IsaDir()) {
372 return ENOTDIR;
373 }
374
375 const ino_t kCurDirIno = -1;
376 const ino_t kParentDirIno = -2;
377 GetDentsHelper helper(kCurDirIno, kParentDirIno);
378
379 std::vector<std::string> dirent_names;
380 Error error = RequestDirent(dirent_names);
381 if (error) {
382 return error;
383 }
384
385 for (unsigned int i = 0; i < dirent_names.size(); ++i) {
386 Path child_path(path_);
387 child_path = child_path.Append("/" + dirent_names[i]);
388 ino_t child_ino = HashPath(child_path);
389
390 helper.AddDirent(child_ino, dirent_names[i].c_str(),
391 dirent_names[i].size());
392 }
393
394 return helper.GetDents(offs, pdir, size, out_bytes);
395 }
396
397 Error GetStat(struct stat* pstat) {
398 Error error = GetSize(&pstat->st_size);
399 if (error) {
400 return error;
401 }
402 return 0;
403 }
404
405 Error Write(const HandleAttr& attr,
406 const void* buf,
407 size_t count,
408 int* out_bytes) {
409 *out_bytes = 0;
410
411 if (IsaDir()) {
412 return EISDIR;
413 }
414
415 off_t file_size = 0;
416 Error error = GetSize(&file_size);
417 if (error) {
418 return error;
419 }
420
421 off_t file_buf_size = std::max((unsigned long long int)file_size,
422 (unsigned long long int)attr.offs + count);
423 char file_buf[file_buf_size];
binji 2016/07/18 23:24:02 This will allocate space for the file on the stack
chanpatorikku 2016/08/07 02:41:02 Done. Thanks. Heap memory, as automatically alloc
424
425 if (file_size > 0) {
426 int read_helper_out_bytes = 0;
427
428 error = ReadHelper(0, file_size - 1, file_buf, file_size,
429 &read_helper_out_bytes);
430
431 if (error) {
432 return error;
433 }
434
435 if (read_helper_out_bytes != file_size) {
436 return EPERM;
437 }
438 }
439
440 char* pChar = (char*)buf;
441 for (unsigned int i = 0; i < count; ++i) {
442 file_buf[attr.offs + i] = pChar[i];
443 }
444
445 error = WriteHelper(file_buf, file_buf_size);
446 if (error) {
447 return error;
448 }
449
450 *out_bytes = count;
451
452 return 0;
453 }
454
455 Error FTruncate(off_t length) {
456 if (IsaDir()) {
457 return EISDIR;
458 }
459
460 off_t file_size = 0;
461 Error error = GetSize(&file_size);
462 if (error) {
463 return error;
464 }
465
466 char file_buf[length];
467
468 if (file_size > 0) {
469 int read_helper_out_bytes = 0;
470
471 error = ReadHelper(0, file_size - 1, file_buf, file_size,
472 &read_helper_out_bytes);
473 if (error) {
474 return error;
475 }
476
477 if (read_helper_out_bytes != file_size) {
478 return EPERM;
479 }
480 }
481
482 for (int i = file_size; i < length; ++i) {
483 file_buf[i] = '\0';
484 }
485
486 error = WriteHelper(file_buf, length);
487 if (error) {
488 return error;
489 }
490
491 return 0;
492 }
493
494 Error Read(const HandleAttr& attr, void* buf, size_t count, int* out_bytes) {
495 *out_bytes = 0;
496
497 if (IsaDir()) {
498 return EISDIR;
499 }
500
501 Error error =
502 ReadHelper(attr.offs, attr.offs + count - 1, buf, count, out_bytes);
503 if (error) {
504 return error;
505 }
506
507 return 0;
508 }
509
510 int GetType() { return IsaDir() ? S_IFDIR : S_IFREG; }
511
512 Error GetSize(off_t* out_size) {
513 *out_size = 0;
514
515 if (IsaDir()) {
516 return 0;
517 }
518
519 GoogleDriveFs* googledrivefs = dynamic_cast<GoogleDriveFs*>(filesystem_);
520 if (googledrivefs == NULL) {
521 return EINVAL;
522 }
523
524 pp::URLLoader loader(pp::InstanceHandle(googledrivefs->instance()));
525 pp::URLRequestInfo request(pp::InstanceHandle(googledrivefs->instance()));
526
527 std::string url = "https://www.googleapis.com/drive/v3/files/";
528 url += item_id_;
529 url += "?";
530 url += "fields=size";
531
532 bool set_url_ok = request.SetURL(url);
533 if (!set_url_ok) {
534 return EPERM;
535 }
536
537 bool set_method_ok = request.SetMethod("GET");
538 if (!set_method_ok) {
539 return EPERM;
540 }
541
542 std::map<std::string, std::string> headers_map;
543 headers_map["Content-type"] = "application/json";
544 std::string authorization_value = "Bearer ";
545 authorization_value += googledrivefs->token();
546 headers_map["Authorization"] = authorization_value;
547
548 std::string headers = MapToHeaders(headers_map);
549
550 bool set_headers_ok = request.SetHeaders(headers);
551 if (!set_headers_ok) {
552 return EPERM;
553 }
554
555 bool set_allow_cross_origin_requests_ok =
556 request.SetAllowCrossOriginRequests(true);
557 if (!set_allow_cross_origin_requests_ok) {
558 return EPERM;
559 }
560
561 bool set_stream_to_file_ok = request.SetStreamToFile(true);
562 if (!set_stream_to_file_ok) {
563 return EPERM;
564 }
565
566 int32_t err = loader.Open(request, pp::BlockUntilComplete());
567 if (err < 0) {
568 return PPERROR_TO_ERRNO(err);
569 }
570
571 pp::URLResponseInfo response = loader.GetResponseInfo();
572 if (response.GetStatusCode() != 200) {
573 return EPERM;
574 }
575
576 pp::FileRef file_ref = response.GetBodyAsFileRef();
577 pp::FileIO file_io(pp::InstanceHandle(googledrivefs->instance()));
578 int32_t open_result =
579 file_io.Open(file_ref, PP_FILEOPENFLAG_READ, pp::BlockUntilComplete());
580
581 if (open_result < 0) {
582 return PPERROR_TO_ERRNO(open_result);
583 }
584
585 int BUFFER_SIZE = 1024;
586 char buffer[BUFFER_SIZE];
587
588 int32_t byte_read =
589 file_io.Read(0, buffer, BUFFER_SIZE, pp::BlockUntilComplete());
590 while (byte_read == 0) {
591 #ifdef WIN32
592 Sleep(1000);
593 #else
594 usleep(1000000);
595 #endif
596
597 byte_read =
598 file_io.Read(0, buffer, BUFFER_SIZE, pp::BlockUntilComplete());
599 }
600 if (byte_read < 0) {
601 return PPERROR_TO_ERRNO(byte_read);
602 }
603
604 std::string output(buffer);
605 Json::Value root;
606
607 Json::Reader reader(Json::Features::strictMode());
608 if (!reader.parse(output, root, false)) {
609 return EPERM;
610 }
611
612 if (!root.isMember("size")) {
613 return EPERM;
614 }
615
616 Json::Value size_value = root["size"];
617
618 *out_size = (off_t)atoi(size_value.asCString());
619
620 return 0;
621 }
622
623 Error Init(int open_flags) {
624 Error error = Node::Init(open_flags);
625
626 if (error) {
627 return error;
628 }
629
630 if (path_.Size() == 1) {
631 parent_dir_id_ = "";
632 item_id_ = "root";
633 is_dir_item_ = true;
634 return 0;
635 }
636
637 error = RequestParentDirId(path_, filesystem_, parent_dir_id_);
638 if (error) {
639 return error;
640 }
641
642 // Request the ID of an item, which is a file or a directory
643 error =
644 RequestItemId(parent_dir_id_, path_.Basename(), filesystem_, item_id_);
645
646 if (error == ENOENT) {
647 // Only files are open as mode O_CREAT
648 if ((open_flags & O_CREAT) != 0) {
649 error = CreateEmptyFile();
650 if (error) {
651 return error;
652 }
653 error = RequestItemId(parent_dir_id_, path_.Basename(), filesystem_,
654 item_id_);
655 if (error) {
656 return error;
657 }
658 is_dir_item_ = false;
659 } else {
660 return ENOENT;
661 }
662 } else if (error) {
663 return error;
664 } else {
665 std::string dir_id = "";
666 error =
667 RequestDirId(parent_dir_id_, path_.Basename(), filesystem_, dir_id);
668 if (error == ENOENT) {
669 is_dir_item_ = false;
670 } else if (error) {
671 return error;
672 } else {
673 is_dir_item_ = true;
674 }
675
676 if (open_flags == 0) {
677 // open_flags == 0 for file opened on fopen with mode r and directory
678 // opened on opendir
679 return 0;
680 } else if (is_dir_item_ && open_flags != 0) {
681 return EPERM;
682 } else if ((open_flags & O_TRUNC) != 0) {
683 error = WriteHelper(NULL, 0);
684 if (error) {
685 return error;
686 }
687 }
688 }
689
690 return 0;
691 }
692
693 void Destroy() { Node::Destroy(); }
694
695 bool IsaDir() { return is_dir_item_; }
696
697 private:
698 Error ReadHelper(off_t start,
699 off_t end,
700 void* buf,
701 size_t count,
702 int* out_bytes) {
703 *out_bytes = 0;
704
705 GoogleDriveFs* googledrivefs = dynamic_cast<GoogleDriveFs*>(filesystem_);
706 if (googledrivefs == NULL) {
707 return EINVAL;
708 }
709
710 pp::URLLoader loader(pp::InstanceHandle(googledrivefs->instance()));
711 pp::URLRequestInfo request(pp::InstanceHandle(googledrivefs->instance()));
712
713 std::string url = "https://www.googleapis.com/download/drive/v3/files/";
714 url += item_id_;
715 url += "?";
716 url += "alt=media";
717
718 bool set_url_ok = request.SetURL(url);
719 if (!set_url_ok) {
720 return EPERM;
721 }
722
723 bool set_method_ok = request.SetMethod("GET");
724 if (!set_method_ok) {
725 return EPERM;
726 }
727
728 std::map<std::string, std::string> headers_map;
729 headers_map["Content-type"] = "application/json";
730 std::string authorization_value = "Bearer ";
731 authorization_value += googledrivefs->token();
732 headers_map["Authorization"] = authorization_value;
733 char range_value_buffer[1024];
734 int char_written = sprintf(range_value_buffer, "bytes=%lli-%lli",
735 (long long int)start, (long long int)end);
736 if (char_written < 0) {
737 return EPERM;
738 }
739 std::string range_value(range_value_buffer);
740 headers_map["Range"] = range_value;
741
742 std::string headers = MapToHeaders(headers_map);
743
744 bool set_headers_ok = request.SetHeaders(headers);
745 if (!set_headers_ok) {
746 return EPERM;
747 }
748
749 bool set_allow_cross_origin_requests_ok =
750 request.SetAllowCrossOriginRequests(true);
751 if (!set_allow_cross_origin_requests_ok) {
752 return EPERM;
753 }
754
755 bool set_stream_to_file_ok = request.SetStreamToFile(true);
756 if (!set_stream_to_file_ok) {
757 return EPERM;
758 }
759
760 int32_t err = loader.Open(request, pp::BlockUntilComplete());
761 if (err < 0) {
762 return PPERROR_TO_ERRNO(err);
763 }
764
765 pp::URLResponseInfo response = loader.GetResponseInfo();
766
767 if (response.GetStatusCode() == 200 || response.GetStatusCode() == 206) {
binji 2016/07/18 23:24:02 use consts for the status codes instead (see http_
chanpatorikku 2016/08/07 02:41:02 Done. Thanks. Used consts for the status codes, a
768 pp::FileRef file_ref = response.GetBodyAsFileRef();
769 pp::FileIO file_io(pp::InstanceHandle(googledrivefs->instance()));
770
771 int32_t open_result = file_io.Open(file_ref, PP_FILEOPENFLAG_READ,
772 pp::BlockUntilComplete());
773 if (open_result < 0) {
774 return PPERROR_TO_ERRNO(open_result);
775 }
776
777 int32_t byte_read =
778 file_io.Read(0, (char*)buf, count, pp::BlockUntilComplete());
779 while (byte_read == 0) {
780 #ifdef WIN32
781 Sleep(1000);
782 #else
783 usleep(1000000);
784 #endif
785
786 byte_read =
787 file_io.Read(0, (char*)buf, count, pp::BlockUntilComplete());
788 }
789
790 if (byte_read < 0) {
791 return PPERROR_TO_ERRNO(byte_read);
792 }
793
794 *out_bytes = byte_read;
795
796 return 0;
797
798 } else if (response.GetStatusCode() == 416) {
799 *out_bytes = 0;
800
801 char* pChar = (char*)buf;
802 pChar[0] = '\0';
803
804 return 0;
805 }
806
807 return EPERM;
808 }
809
810 Error WriteHelper(const void* request_body_data, uint32_t request_body_size) {
811 GoogleDriveFs* googledrivefs = dynamic_cast<GoogleDriveFs*>(filesystem_);
812 if (googledrivefs == NULL) {
813 return EINVAL;
814 }
815
816 pp::URLLoader loader(pp::InstanceHandle(googledrivefs->instance()));
817 pp::URLRequestInfo request(pp::InstanceHandle(googledrivefs->instance()));
818
819 std::string url = "https://www.googleapis.com/upload/drive/v3/files/";
820 url += item_id_;
821 url += "?";
822 url += "uploadType=media";
823
824 bool set_url_ok = request.SetURL(url);
825 if (!set_url_ok) {
826 return EPERM;
827 }
828 bool set_method_ok = request.SetMethod("PATCH");
829 if (!set_method_ok) {
830 return EPERM;
831 }
832
833 std::map<std::string, std::string> headers_map;
834 headers_map["Content-type"] = "application/json";
835 std::string authorization_value = "Bearer ";
836 authorization_value += googledrivefs->token();
837 headers_map["Authorization"] = authorization_value;
838
839 std::string headers = MapToHeaders(headers_map);
840
841 bool set_headers_ok = request.SetHeaders(headers);
842 if (!set_headers_ok) {
843 return EPERM;
844 }
845
846 bool set_allow_cross_origin_requests_ok =
847 request.SetAllowCrossOriginRequests(true);
848 if (!set_allow_cross_origin_requests_ok) {
849 return EPERM;
850 }
851
852 bool set_stream_to_file_ok = request.SetStreamToFile(true);
853 if (!set_stream_to_file_ok) {
854 return EPERM;
855 }
856
857 bool append_data_to_body_ok =
858 request.AppendDataToBody(request_body_data, request_body_size);
859 if (!append_data_to_body_ok) {
860 return EPERM;
861 }
862
863 int32_t err = loader.Open(request, pp::BlockUntilComplete());
864 if (err < 0) {
865 return PPERROR_TO_ERRNO(err);
866 }
867
868 pp::URLResponseInfo response = loader.GetResponseInfo();
869 if (response.GetStatusCode() != 200) {
870 return EPERM;
871 }
872
873 return 0;
874 }
875
876 Error CreateEmptyFile() {
877 std::string url =
878 "https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart";
879
880 GoogleDriveFs* googledrivefs = dynamic_cast<GoogleDriveFs*>(filesystem_);
881 if (googledrivefs == NULL) {
882 return EINVAL;
883 }
884
885 pp::URLLoader loader(pp::InstanceHandle(googledrivefs->instance()));
886 pp::URLRequestInfo request(pp::InstanceHandle(googledrivefs->instance()));
887
888 bool set_url_ok = request.SetURL(url);
889 if (!set_url_ok) {
890 return EPERM;
891 }
892
893 bool set_method_ok = request.SetMethod("POST");
894 if (!set_method_ok) {
895 return EPERM;
896 }
897
898 std::string BOUNDARY_VALUE = "foo_bar_baz";
899
900 std::map<std::string, std::string> headers_map;
901 headers_map["Content-type"] =
902 "multipart/related; boundary=" + BOUNDARY_VALUE;
903 std::string authorization_value = "Bearer ";
904 authorization_value += googledrivefs->token();
905 headers_map["Authorization"] = authorization_value;
906
907 std::string headers = MapToHeaders(headers_map);
908
909 bool set_headers_ok = request.SetHeaders(headers);
910 if (!set_headers_ok) {
911 return EPERM;
912 }
913
914 bool set_allow_cross_origin_requests_ok =
915 request.SetAllowCrossOriginRequests(true);
916 if (!set_allow_cross_origin_requests_ok) {
917 return EPERM;
918 }
919
920 bool set_stream_to_file_ok = request.SetStreamToFile(true);
921 if (!set_stream_to_file_ok) {
922 return EPERM;
923 }
924
925 std::string request_body = "--";
926 request_body += BOUNDARY_VALUE;
927 request_body += "\n";
928
929 request_body += "Content-Type: application/json; charset=UTF-8";
930 request_body += "\n";
931
932 request_body += "\n";
933
934 request_body += "{";
935 request_body += "\n";
936
937 request_body += " \"name\": ";
938 request_body += "\"";
939 request_body += path_.Basename();
940 request_body += "\"";
941 request_body += ",";
942 request_body += "\n";
943
944 request_body += " \"parents\": ";
945 request_body += "[";
946 request_body += "\n";
947
948 request_body += " \"";
949 request_body += parent_dir_id_;
950 request_body += "\"";
951 request_body += "\n";
952
953 request_body += " ]";
954 request_body += "\n";
955
956 request_body += "}";
957 request_body += "\n";
958
959 request_body += "\n";
960
961 request_body += "--";
962 request_body += BOUNDARY_VALUE;
963 request_body += "\n";
964
965 request_body += "Content-Type: text/plain";
966 request_body += "\n";
967
968 request_body += "\n";
969
970 request_body += "\n";
971
972 request_body += "--";
973 request_body += BOUNDARY_VALUE;
974 request_body += "--";
975
976 bool append_data_to_body_ok =
977 request.AppendDataToBody(request_body.data(), request_body.size());
978 if (!append_data_to_body_ok) {
979 return EPERM;
980 }
981
982 int32_t err = loader.Open(request, pp::BlockUntilComplete());
983 if (err < 0) {
984 return PPERROR_TO_ERRNO(err);
985 }
986
987 pp::URLResponseInfo response = loader.GetResponseInfo();
988 if (response.GetStatusCode() != 200) {
989 return EPERM;
990 }
991
992 return 0;
993 }
994
995 Error RequestDirent(std::vector<std::string>& dirent_names) {
996 std::string url = "https://www.googleapis.com/drive/v3/files";
997 url += "?";
998 url += "q=";
999 url += "%27";
1000 url += item_id_;
1001 url += "%27+in+parents";
1002
1003 GoogleDriveFs* googledrivefs = dynamic_cast<GoogleDriveFs*>(filesystem_);
1004 if (googledrivefs == NULL) {
1005 return EINVAL;
1006 }
1007
1008 pp::URLLoader loader(pp::InstanceHandle(googledrivefs->instance()));
1009 pp::URLRequestInfo request(pp::InstanceHandle(googledrivefs->instance()));
1010
1011 bool set_url_ok = request.SetURL(url);
1012 if (!set_url_ok) {
1013 return EPERM;
1014 }
1015
1016 bool set_method_ok = request.SetMethod("GET");
1017 if (!set_method_ok) {
1018 return EPERM;
1019 }
1020
1021 std::map<std::string, std::string> headers_map;
1022 headers_map["Content-type"] = "application/json";
1023 std::string authorization_value = "Bearer ";
1024 authorization_value += googledrivefs->token();
1025 headers_map["Authorization"] = authorization_value;
1026
1027 std::string headers = MapToHeaders(headers_map);
1028
1029 bool set_headers_ok = request.SetHeaders(headers);
1030 if (!set_headers_ok) {
1031 return EPERM;
1032 }
1033
1034 bool set_allow_cross_origin_requests_ok =
1035 request.SetAllowCrossOriginRequests(true);
1036 if (!set_allow_cross_origin_requests_ok) {
1037 return EPERM;
1038 }
1039
1040 bool set_stream_to_file_ok = request.SetStreamToFile(true);
1041 if (!set_stream_to_file_ok) {
1042 return EPERM;
1043 }
1044
1045 int32_t err = loader.Open(request, pp::BlockUntilComplete());
1046 if (err < 0) {
1047 return PPERROR_TO_ERRNO(err);
1048 }
1049
1050 pp::URLResponseInfo response = loader.GetResponseInfo();
1051 if (response.GetStatusCode() != 200) {
1052 return EPERM;
1053 }
1054
1055 pp::FileRef file_ref = response.GetBodyAsFileRef();
1056 pp::FileIO file_io(pp::InstanceHandle(googledrivefs->instance()));
1057
1058 int32_t open_result =
1059 file_io.Open(file_ref, PP_FILEOPENFLAG_READ, pp::BlockUntilComplete());
1060 if (open_result < 0) {
1061 return PPERROR_TO_ERRNO(open_result);
1062 }
1063
1064 std::string output = "";
1065 int BUFFER_SIZE = 1024;
1066 char buffer[BUFFER_SIZE];
1067 int byte_read =
1068 file_io.Read(0, buffer, BUFFER_SIZE, pp::BlockUntilComplete());
1069
1070 while (byte_read == 0) {
1071 #ifdef WIN32
1072 Sleep(1000);
1073 #else
1074 usleep(1000000);
1075 #endif
1076
1077 byte_read =
1078 file_io.Read(0, buffer, BUFFER_SIZE, pp::BlockUntilComplete());
1079 }
1080
1081 while (byte_read > 0) {
1082 output += buffer;
1083
1084 byte_read = file_io.Read(byte_read, buffer, BUFFER_SIZE,
1085 pp::BlockUntilComplete());
1086 }
1087
1088 if (byte_read < 0) {
1089 return PPERROR_TO_ERRNO(byte_read);
1090 }
1091
1092 Json::Value root;
1093
1094 Json::Reader reader(Json::Features::strictMode());
1095 if (!reader.parse(output, root, false)) {
1096 return EPERM;
1097 }
1098
1099 if (!root.isMember("files")) {
1100 return EPERM;
1101 }
1102
1103 Json::Value files_array = root["files"];
1104
1105 if (!files_array.isArray()) {
1106 return EPERM;
1107 }
1108
1109 for (unsigned int i = 0; i < files_array.size(); ++i) {
1110 dirent_names.push_back(files_array[i]["name"].asString());
1111 }
1112
1113 // TODO: Too many entries result in nextPageToken in API response and
1114 // out-of-memory in output variable.
1115
1116 return 0;
1117 }
1118
1119 std::string parent_dir_id_;
1120 std::string item_id_;
1121 bool is_dir_item_;
1122 Path path_;
1123
1124 friend class GoogleDriveFs;
1125 };
1126
1127 GoogleDriveFs::GoogleDriveFs() {}
1128
1129 GoogleDriveFs::~GoogleDriveFs() {}
1130
1131 Error GoogleDriveFs::Init(const FsInitArgs& args) {
1132 Error error = Filesystem::Init(args);
1133 if (error) {
1134 return error;
1135 }
1136
1137 std::map<std::string, std::string>::const_iterator instance_it =
1138 args.string_map.find("instance");
1139
1140 if (instance_it == args.string_map.end()) {
1141 return EINVAL;
1142 }
1143
1144 instance_ = atoi(instance_it->second.c_str());
1145
1146 std::map<std::string, std::string>::const_iterator token_it =
1147 args.string_map.find("token");
1148
1149 if (token_it == args.string_map.end()) {
1150 return EINVAL;
1151 }
1152
1153 token_ = token_it->second;
1154
1155 return 0;
1156 }
1157
1158 void GoogleDriveFs::Destroy() {}
1159
1160 Error GoogleDriveFs::OpenWithMode(const Path& path,
1161 int open_flags,
1162 mode_t mode,
1163 ScopedNode* out_node) {
1164 ScopedNode node(new GoogleDriveFsNode(this, path));
1165
1166 Error error = node->Init(open_flags);
1167 if (error) {
1168 return error;
1169 }
1170
1171 *out_node = node;
1172
1173 return 0;
1174 }
1175
1176 Error GoogleDriveFs::Rename(const Path& path, const Path& newPath) {
1177 LOG_ERROR("rename not supported.");
1178 return EPERM;
1179 }
1180
1181 Error GoogleDriveFs::Unlink(const Path& path) {
1182 LOG_ERROR("unlink not supported.");
1183 return EPERM;
1184 }
1185
1186 Error GoogleDriveFs::Mkdir(const Path& path, int permissions) {
1187 std::string parent_dir_id = "";
1188 Error error = RequestParentDirId(path, this, parent_dir_id);
1189 if (error) {
1190 return error;
1191 }
1192
1193 std::string item_id = "";
1194 error = RequestItemId(parent_dir_id, path.Basename(), this, item_id);
1195
1196 // mkdir does not create a directory when a file with path.Basename()
1197 // already exists
1198 if (error == ENOENT) {
1199 std::string url = "https://www.googleapis.com/drive/v3/files";
1200
1201 pp::URLLoader loader(pp::InstanceHandle(this->instance()));
1202 pp::URLRequestInfo request(pp::InstanceHandle(this->instance()));
1203
1204 bool set_url_ok = request.SetURL(url);
1205 if (!set_url_ok) {
1206 return EPERM;
1207 }
1208
1209 bool set_method_ok = request.SetMethod("POST");
1210 if (!set_method_ok) {
1211 return EPERM;
1212 }
1213
1214 std::map<std::string, std::string> headers_map;
1215 headers_map["Content-type"] = "application/json";
1216 std::string authorization_value = "Bearer ";
1217 authorization_value += token_;
1218 headers_map["Authorization"] = authorization_value;
1219
1220 std::string headers = MapToHeaders(headers_map);
1221
1222 bool set_headers_ok = request.SetHeaders(headers);
1223 if (!set_headers_ok) {
1224 return EPERM;
1225 }
1226
1227 Json::Value json_value;
1228 json_value["name"] = path.Basename();
1229 json_value["mimeType"] = "application/vnd.google-apps.folder";
1230 Json::FastWriter fast_writer;
1231 std::string request_body = fast_writer.write(json_value);
1232
1233 bool append_data_to_body_ok =
1234 request.AppendDataToBody(request_body.data(), request_body.size());
1235 if (!append_data_to_body_ok) {
1236 return EPERM;
1237 }
1238
1239 bool set_allow_cross_origin_requests_ok =
1240 request.SetAllowCrossOriginRequests(true);
1241 if (!set_allow_cross_origin_requests_ok) {
1242 return EPERM;
1243 }
1244
1245 bool set_stream_to_file_ok = request.SetStreamToFile(true);
1246 if (!set_stream_to_file_ok) {
1247 return EPERM;
1248 }
1249
1250 int32_t err = loader.Open(request, pp::BlockUntilComplete());
1251 if (err < 0) {
1252 return PPERROR_TO_ERRNO(err);
1253 }
1254
1255 pp::URLResponseInfo response = loader.GetResponseInfo();
1256 if (response.GetStatusCode() != 200) {
1257 return EPERM;
1258 }
1259
1260 return 0;
1261 }
1262
1263 return EEXIST;
1264 }
1265
1266 Error GoogleDriveFs::Rmdir(const Path& path) {
1267 std::string parent_dir_id = "";
1268 Error error = RequestParentDirId(path, this, parent_dir_id);
1269 if (error) {
1270 return error;
1271 }
1272
1273 std::string dir_id = "";
1274 error = RequestDirId(parent_dir_id, path.Basename(), this, dir_id);
1275 if (error) {
1276 return error;
1277 }
1278
1279 std::string url = "https://www.googleapis.com/drive/v3/files";
1280
1281 url += "/";
1282 url += dir_id;
1283
1284 pp::URLLoader loader(pp::InstanceHandle(this->instance()));
1285 pp::URLRequestInfo request(pp::InstanceHandle(this->instance()));
1286
1287 bool set_url_ok = request.SetURL(url);
1288 if (!set_url_ok) {
1289 return EPERM;
1290 }
1291 bool set_method_ok = request.SetMethod("DELETE");
1292 if (!set_method_ok) {
1293 return EPERM;
1294 }
1295
1296 std::map<std::string, std::string> headers_map;
1297 headers_map["Content-type"] = "application/json";
1298 std::string authorization_value = "Bearer ";
1299 authorization_value += token_;
1300 headers_map["Authorization"] = authorization_value;
1301
1302 std::string headers = MapToHeaders(headers_map);
1303
1304 bool set_headers_ok = request.SetHeaders(headers);
1305 if (!set_headers_ok) {
1306 return EPERM;
1307 }
1308
1309 bool set_allow_cross_origin_requests_ok =
1310 request.SetAllowCrossOriginRequests(true);
1311 if (!set_allow_cross_origin_requests_ok) {
1312 return EPERM;
1313 }
1314
1315 bool set_stream_to_file_ok = request.SetStreamToFile(true);
1316 if (!set_stream_to_file_ok) {
1317 return EPERM;
1318 }
1319
1320 int32_t err = loader.Open(request, pp::BlockUntilComplete());
1321 if (err < 0) {
1322 return PPERROR_TO_ERRNO(err);
1323 }
1324
1325 pp::URLResponseInfo response = loader.GetResponseInfo();
1326 if (response.GetStatusCode() != 204) {
1327 return EPERM;
1328 }
1329
1330 return 0;
1331 }
1332
1333 Error GoogleDriveFs::Remove(const Path& path) {
1334 LOG_ERROR("remove not supported.");
1335 return EPERM;
1336 }
1337
1338 std::string GoogleDriveFs::token() {
1339 return token_;
1340 }
1341
1342 PP_Instance GoogleDriveFs::instance() {
1343 return instance_;
1344 }
1345
1346 } // namespace nacl_io
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698