Chromium Code Reviews| OLD | NEW |
|---|---|
| (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 | |
| OLD | NEW |