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

Side by Side Diff: native_client_sdk/src/libraries/nacl_io/googledrivefs/googledrivefs_node.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, 3 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_node.h"
6
7 #include <stdint.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11
12 #include <algorithm>
13 #include <limits>
14
15 #include "ppapi/c/pp_completion_callback.h"
16
17 #include "nacl_io/error.h"
18 #include "nacl_io/filesystem.h"
19 #include "nacl_io/getdents_helper.h"
20 #include "nacl_io/hash.h"
21 #include "nacl_io/kernel_handle.h"
22 #include "nacl_io/statuscode.h"
23 #include "nacl_io/googledrivefs/googledrivefs.h"
24 #include "nacl_io/googledrivefs/googledrivefs_util.h"
25
26 namespace nacl_io {
27
28 GoogleDriveFsNode::GoogleDriveFsNode(Filesystem* filesystem, Path path)
29 : Node(filesystem), path_(path) {}
30
31 Error GoogleDriveFsNode::GetDents(size_t offs,
32 struct dirent* pdir,
33 size_t size,
34 int* out_bytes) {
35 *out_bytes = 0;
36
37 if (!IsaDir()) {
38 return ENOTDIR;
39 }
40
41 GetDentsHelper helper(HashPath(Path(".")), HashPath(Path("..")));
42
43 std::vector<std::string> dirent_names;
44 Error error = RequestDirent("", &dirent_names);
45 if (error) {
46 return error;
47 }
48
49 for (size_t i = 0; i < dirent_names.size(); ++i) {
50 Path child_path(path_);
51 child_path = child_path.Append("/" + dirent_names[i]);
52 ino_t child_ino = HashPath(child_path);
53
54 helper.AddDirent(child_ino, dirent_names[i].c_str(),
55 dirent_names[i].size());
56 }
57
58 return helper.GetDents(offs, pdir, size, out_bytes);
59 }
60
61 Error GoogleDriveFsNode::GetStat(struct stat* pstat) {
62 Error error = GetSize(&pstat->st_size);
63 if (error) {
64 return error;
65 }
66
67 error = GetModifiedTime(&pstat->st_mtime);
68 if (error) {
69 return error;
70 }
71
72 pstat->st_atime = 0;
73 pstat->st_ctime = 0;
74
75 pstat->st_mode = stat_.st_mode;
76
77 return 0;
78 }
79
80 Error GoogleDriveFsNode::Write(const HandleAttr& attr,
81 const void* buf,
82 size_t count,
83 int* out_bytes) {
84 *out_bytes = 0;
85
86 if (IsaDir()) {
87 return EISDIR;
88 }
89 if ((GetMode() & S_IWRITE) == 0) {
90 return EACCES;
91 }
92
93 off_t file_size;
94 Error error = GetSize(&file_size);
95 if (error) {
96 return error;
97 }
98
99 if (attr.offs > file_size ||
100 attr.offs >= std::numeric_limits<int32_t>::max()) {
101 return EFBIG;
102 }
103
104 // GoogleDriveFs has a maximum file size of INT32_MAX (i.e.
105 // std::numeric_limits<int32_t>::max()).
106 int bytes_to_write =
107 std::min<size_t>(count, std::numeric_limits<int32_t>::max());
108 bytes_to_write = std::min<int32_t>(
109 bytes_to_write, std::numeric_limits<int32_t>::max() - attr.offs);
110
111 int32_t file_buffer_size =
112 std::max<int32_t>(file_size, attr.offs + bytes_to_write);
113
114 // use std::string for storing data in the heap, as the size of stack
115 // is measured in megabytes, disallowing files larger than that.
116 std::string file_buffer(file_buffer_size, '\0');
117
118 if (file_size > 0) {
119 int32_t read_helper_out_bytes;
120 error = ReadHelper(0, file_size, &file_buffer[0], &read_helper_out_bytes);
121 if (error) {
122 return error;
123 }
124 }
125
126 memcpy(&file_buffer[0] + attr.offs, buf, bytes_to_write);
127
128 error = WriteHelper(file_buffer.c_str(), file_buffer_size);
129 if (error) {
130 return error;
131 }
132
133 *out_bytes = bytes_to_write;
134
135 return 0;
136 }
137
138 Error GoogleDriveFsNode::FTruncate(off_t length) {
139 if (IsaDir()) {
140 return EISDIR;
141 }
142
143 // GoogleDriveFs has a maximum file size of INT32_MAX (i.e.
144 // std::numeric_limits<int32_t>::max()).
145 if (length > std::numeric_limits<int32_t>::max()) {
146 return EFBIG;
147 }
148
149 off_t file_size;
150 Error error = GetSize(&file_size);
151 if (error) {
152 return error;
153 }
154
155 std::string file_buffer(length, '\0');
156
157 if (file_size > 0) {
158 int32_t read_helper_out_bytes;
159 int32_t read_end = std::min<int32_t>(length, file_size);
160 error = ReadHelper(0, read_end, &file_buffer[0], &read_helper_out_bytes);
161 if (error) {
162 return error;
163 }
164 }
165
166 error = WriteHelper(file_buffer.c_str(), length);
167 if (error) {
168 return error;
169 }
170
171 return 0;
172 }
173
174 Error GoogleDriveFsNode::Read(const HandleAttr& attr,
175 void* buf,
176 size_t count,
177 int* out_bytes) {
178 *out_bytes = 0;
179
180 if (IsaDir()) {
181 return EISDIR;
182 }
183 if ((GetMode() & S_IREAD) == 0) {
184 return EACCES;
185 }
186
187 if (count == 0) {
188 return 0;
189 }
190
191 // GoogleDriveFs has a maximum file size of INT32_MAX (i.e.
192 // std::numeric_limits<int32_t>::max()).
193 if (attr.offs >= std::numeric_limits<int32_t>::max()) {
chanpatorikku 2016/09/21 16:41:10 In patch set 2 and patch set 3, I wrote: “Google D
194 return 0;
195 }
196
197 // Suppose int is >= 32 bits, bytes_to_read is adjusted to
198 // be in the range of a Google Drive file.
199 int bytes_to_read =
200 std::min<size_t>(count, std::numeric_limits<int32_t>::max());
201 bytes_to_read = std::min<int32_t>(
202 bytes_to_read, std::numeric_limits<int32_t>::max() - attr.offs);
203
204 int32_t read_helper_out_bytes;
205 Error error = ReadHelper(attr.offs, attr.offs + bytes_to_read, buf,
206 &read_helper_out_bytes);
207 if (error) {
208 return error;
209 }
210
211 *out_bytes = read_helper_out_bytes;
212
213 return 0;
214 }
215
216 Error GoogleDriveFsNode::GetSize(off_t* out_size) {
217 *out_size = 0;
218
219 if (IsaDir()) {
220 return 0;
221 }
222
223 GoogleDriveFs* googledrivefs = static_cast<GoogleDriveFs*>(filesystem_);
224
225 RequestUrlParams p;
226
227 p.url = DRIVE_URL;
228 AddUrlPath(item_id_, &p.url);
229 AddUrlFirstQueryParameter("fields", "size", &p.url);
230
231 p.method = "GET";
232
233 AddHeaders("Content-type", "application/json", &p.headers);
234 AddHeaders("Authorization", "Bearer " + googledrivefs->token(), &p.headers);
235
236 ScopedResource url_response_info_resource(googledrivefs->ppapi());
237 Error error = LoadUrl(googledrivefs->ppapi(), p, &url_response_info_resource);
238 if (error) {
239 return error;
240 }
241
242 if (ReadStatusCode(googledrivefs->ppapi(),
243 url_response_info_resource.pp_resource()) !=
244 STATUSCODE_OK) {
245 return EPERM;
246 }
247
248 std::string output;
249 error = ReadResponseBody(googledrivefs->ppapi(),
250 url_response_info_resource.pp_resource(),
251 std::numeric_limits<int32_t>::max(), &output);
252 if (error) {
253 return error;
254 }
255
256 std::string size_value;
257 size_t size_index;
258 error =
259 GetValueStringAndValuePos(output, "size", 0, &size_value, &size_index);
260 if (error == EINVAL) {
261 size_value = "0";
262 } else if (error) {
263 return error;
264 }
265
266 // GoogleDriveFs has a maximum file size of INT32_MAX (i.e.
267 // std::numeric_limits<int32_t>::max()).
268 *out_size = atoi(size_value.c_str());
269
270 return 0;
271 }
272
273 Error GoogleDriveFsNode::Init(int open_flags) {
274 Error error = Node::Init(open_flags);
275 if (error) {
276 return error;
277 }
278
279 if (!filesystem_->ppapi()) {
280 return ENOSYS;
281 }
282
283 if (path_.IsRoot()) {
284 item_id_ = "root";
285 SetType(S_IFDIR);
286 SetMode(S_IREAD);
287 return 0;
288 }
289
290 error = RequestParentDirId(path_, static_cast<GoogleDriveFs*>(filesystem_),
291 &parent_dir_id_);
292 if (error) {
293 return error;
294 }
295
296 // Request the ID of an item, which is a file or a directory,
297 // and the item type.
298 bool is_dir_type;
299 error = RequestItemIdAndItemType(parent_dir_id_, path_.Basename(),
300 static_cast<GoogleDriveFs*>(filesystem_),
301 &item_id_, &is_dir_type);
302
303 if (error == ENOENT) {
304 // Only files are open as mode O_CREAT
305 if ((open_flags & O_CREAT) != 0) {
306 error = CreateEmptyFile();
307 if (error) {
308 return error;
309 }
310 error = RequestItemIdAndItemType(parent_dir_id_, path_.Basename(),
311 static_cast<GoogleDriveFs*>(filesystem_),
312 &item_id_, &is_dir_type);
313 if (error) {
314 return error;
315 }
316 SetType(S_IFREG);
317 if ((open_flags & O_RDWR) != 0) {
318 SetMode(S_IREAD | S_IWRITE);
319 } else if ((open_flags & O_WRONLY) != 0) {
320 SetMode(S_IWRITE);
321 } else {
322 SetMode(S_IREAD);
323 }
324 } else {
325 return ENOENT;
326 }
327 } else if (error) {
328 return error;
329 } else {
330 if (is_dir_type) {
331 SetType(S_IFDIR);
332 SetMode(S_IREAD);
333 } else {
334 SetType(S_IFREG);
335 if ((open_flags & O_RDWR) != 0) {
336 SetMode(S_IREAD | S_IWRITE);
337 } else if ((open_flags & O_WRONLY) != 0) {
338 SetMode(S_IWRITE);
339 } else {
340 SetMode(S_IREAD);
341 }
342 }
343
344 if (open_flags == 0) {
345 // open_flags == 0 for file opened on fopen with mode r and
346 // directory opened on opendir
347 return 0;
348 } else if (IsaDir()) {
349 return EPERM;
350 } else if ((open_flags & O_TRUNC) != 0) {
351 error = WriteHelper(NULL, 0);
352 if (error) {
353 return error;
354 }
355 }
356 }
357
358 return 0;
359 }
360
361 Error GoogleDriveFsNode::ReadHelper(int32_t start,
362 int32_t end,
363 void* out_buffer,
364 int32_t* out_bytes) {
365 memset(out_buffer, 0, 1);
366 *out_bytes = 0;
367
368 GoogleDriveFs* googledrivefs = static_cast<GoogleDriveFs*>(filesystem_);
369
370 RequestUrlParams p;
371
372 p.url = DOWNLOAD_DRIVE_URL;
373 AddUrlPath(item_id_, &p.url);
374 AddUrlFirstQueryParameter("alt", "media", &p.url);
375
376 p.method = "GET";
377
378 AddHeaders("Content-type", "application/json", &p.headers);
379 AddHeaders("Authorization", "Bearer " + googledrivefs->token(), &p.headers);
380
381 char range_value_buffer[1024];
382 snprintf(range_value_buffer, sizeof(range_value_buffer), "bytes=%i-%i", start,
383 end - 1);
chanpatorikku 2016/09/21 16:41:10 bytes=%i-%i can become bytes=0--1 when start =
384
385 AddHeaders("Range", range_value_buffer, &p.headers);
386
387 ScopedResource url_response_info_resource(googledrivefs->ppapi());
388 Error error = LoadUrl(googledrivefs->ppapi(), p, &url_response_info_resource);
389 if (error) {
390 return error;
391 }
392
393 int32_t status_code = ReadStatusCode(
394 googledrivefs->ppapi(), url_response_info_resource.pp_resource());
395 if (status_code == STATUSCODE_OK ||
396 status_code == STATUSCODE_PARTIAL_CONTENT) {
397 std::string output;
398 error = ReadResponseBody(googledrivefs->ppapi(),
399 url_response_info_resource.pp_resource(),
400 end - start, &output);
401 if (error) {
402 return error;
403 }
404
405 memcpy(out_buffer, &output[0], output.size());
406 *out_bytes = output.size();
407
408 return 0;
409 } else if (status_code == STATUSCODE_REQUESTED_RANGE_NOT_SATISFIABLE) {
410 return 0;
411 }
412
413 return EPERM;
414 }
415
416 Error GoogleDriveFsNode::WriteHelper(const char* body_data, int32_t body_size) {
417 GoogleDriveFs* googledrivefs = static_cast<GoogleDriveFs*>(filesystem_);
418
419 RequestUrlParams p;
420
421 p.url = UPLOAD_DRIVE_URL;
422 AddUrlPath(item_id_, &p.url);
423 AddUrlFirstQueryParameter("uploadType", "media", &p.url);
424
425 p.method = "PATCH";
426
427 AddHeaders("Content-type", "application/json", &p.headers);
428 AddHeaders("Authorization", "Bearer " + googledrivefs->token(), &p.headers);
429
430 p.body = std::string(body_data, body_size);
431
432 ScopedResource url_response_info_resource(googledrivefs->ppapi());
433 Error error = LoadUrl(googledrivefs->ppapi(), p, &url_response_info_resource);
434 if (error) {
435 return error;
436 }
437
438 if (ReadStatusCode(googledrivefs->ppapi(),
439 url_response_info_resource.pp_resource()) !=
440 STATUSCODE_OK) {
441 return EPERM;
442 }
443
444 return 0;
445 }
446
447 Error GoogleDriveFsNode::GetModifiedTime(time_t* out_mtime) {
448 GoogleDriveFs* googledrivefs = static_cast<GoogleDriveFs*>(filesystem_);
449
450 RequestUrlParams p;
451
452 p.url = DRIVE_URL;
453 AddUrlPath(item_id_, &p.url);
454 AddUrlFirstQueryParameter("fields", "modifiedTime", &p.url);
455
456 p.method = "GET";
457
458 AddHeaders("Content-type", "application/json", &p.headers);
459 AddHeaders("Authorization", "Bearer " + googledrivefs->token(), &p.headers);
460
461 ScopedResource url_response_info_resource(googledrivefs->ppapi());
462 Error error = LoadUrl(googledrivefs->ppapi(), p, &url_response_info_resource);
463 if (error) {
464 return error;
465 }
466
467 if (ReadStatusCode(googledrivefs->ppapi(),
468 url_response_info_resource.pp_resource()) !=
469 STATUSCODE_OK) {
470 return EPERM;
471 }
472
473 std::string output;
474 error = ReadResponseBody(googledrivefs->ppapi(),
475 url_response_info_resource.pp_resource(),
476 std::numeric_limits<int32_t>::max(), &output);
477 if (error) {
478 return error;
479 }
480
481 std::string modified_time_value;
482 size_t modified_time_index;
483 error = GetValueStringAndValuePos(output, "modifiedTime", 0,
484 &modified_time_value, &modified_time_index);
485 if (error) {
486 return EPERM;
487 }
488
489 *out_mtime =
490 ConvertDateTimeToEpochTime(ExtractYearFromRFC3339(modified_time_value),
491 ExtractMonthFromRFC3339(modified_time_value),
492 ExtractDayFromRFC3339(modified_time_value),
493 ExtractHourFromRFC3339(modified_time_value),
494 ExtractMinuteFromRFC3339(modified_time_value),
495 ExtractSecondFromRFC3339(modified_time_value));
496
497 return 0;
498 }
499
500 Error GoogleDriveFsNode::CreateEmptyFile() {
501 GoogleDriveFs* googledrivefs = static_cast<GoogleDriveFs*>(filesystem_);
502
503 RequestUrlParams p;
504 std::string BOUNDARY_VALUE = "foo_bar_baz";
505
506 p.url = UPLOAD_DRIVE_URL;
507 AddUrlFirstQueryParameter("uploadType", "multipart", &p.url);
508
509 p.method = "POST";
510
511 AddHeaders("Content-type", "multipart/related; boundary=" + BOUNDARY_VALUE,
512 &p.headers);
513 AddHeaders("Authorization", "Bearer " + googledrivefs->token(), &p.headers);
514
515 AddBody("--" + BOUNDARY_VALUE, &p.body);
516 AddBody("Content-Type: application/json; charset=UTF-8", &p.body);
517 AddBody("", &p.body);
518 AddBody("{", &p.body);
519 AddBody(" \"name\": \"" + path_.Basename() + "\",", &p.body);
520 AddBody(" \"parents\": [", &p.body);
521 AddBody(" \"" + parent_dir_id_ + "\"", &p.body);
522 AddBody(" ]", &p.body);
523 AddBody("}", &p.body);
524 AddBody("", &p.body);
525 AddBody("--" + BOUNDARY_VALUE, &p.body);
526 AddBody("Content-Type: text/plain", &p.body);
527 AddBody("", &p.body);
528 AddBody("", &p.body);
529 AddBody("--" + BOUNDARY_VALUE + "--", &p.body);
530
531 ScopedResource url_response_info_resource(googledrivefs->ppapi());
532 Error error = LoadUrl(googledrivefs->ppapi(), p, &url_response_info_resource);
533 if (error) {
534 return error;
535 }
536
537 if (ReadStatusCode(googledrivefs->ppapi(),
538 url_response_info_resource.pp_resource()) !=
539 STATUSCODE_OK) {
540 return EPERM;
541 }
542
543 return 0;
544 }
545
546 Error GoogleDriveFsNode::RequestDirent(
547 const std::string& optional_page_token,
548 std::vector<std::string>* out_dirent_names) {
549 GoogleDriveFs* googledrivefs = static_cast<GoogleDriveFs*>(filesystem_);
550
551 RequestUrlParams p;
552
553 p.url = DRIVE_URL;
554 AddUrlFirstQueryParameter("q", ParentEqualClause(item_id_), &p.url);
555
556 if (!optional_page_token.empty()) {
557 AddUrlNextQueryParameter("pageToken", optional_page_token, &p.url);
558 }
559
560 p.method = "GET";
561
562 AddHeaders("Content-type", "application/json", &p.headers);
563 AddHeaders("Authorization", "Bearer " + googledrivefs->token(), &p.headers);
564
565 ScopedResource url_response_info_resource(googledrivefs->ppapi());
566 Error error = LoadUrl(googledrivefs->ppapi(), p, &url_response_info_resource);
567 if (error) {
568 return error;
569 }
570
571 if (ReadStatusCode(googledrivefs->ppapi(),
572 url_response_info_resource.pp_resource()) !=
573 STATUSCODE_OK) {
574 return EPERM;
575 }
576
577 std::string output;
578 error = ReadResponseBody(googledrivefs->ppapi(),
579 url_response_info_resource.pp_resource(),
580 std::numeric_limits<int32_t>::max(), &output);
581 if (error) {
582 return error;
583 }
584
585 std::string name_value;
586 size_t name_index;
587 error =
588 GetValueStringAndValuePos(output, "name", 0, &name_value, &name_index);
589 if (error && error != EINVAL) {
590 return error;
591 }
592
593 while (!error) {
594 out_dirent_names->push_back(name_value);
595
596 error = GetValueStringAndValuePos(output, "name", name_index, &name_value,
597 &name_index);
598 if (error && error != EINVAL) {
599 return error;
600 }
601 }
602
603 std::string next_page_token_value;
604 size_t next_page_token_index;
605 error =
606 GetValueStringAndValuePos(output, "nextPageToken", 0,
607 &next_page_token_value, &next_page_token_index);
608 if (!error) {
609 return RequestDirent(next_page_token_value, out_dirent_names);
610 } else if (error != EINVAL) {
611 return error;
612 }
613
614 return 0;
615 }
616
617 } // namespace nacl_io
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698