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

Unified 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 side-by-side diff with in-line comments
Download patch
Index: native_client_sdk/src/libraries/nacl_io/googledrivefs/googledrivefs.cc
diff --git a/native_client_sdk/src/libraries/nacl_io/googledrivefs/googledrivefs.cc b/native_client_sdk/src/libraries/nacl_io/googledrivefs/googledrivefs.cc
new file mode 100644
index 0000000000000000000000000000000000000000..430714c822c5194c971725aec89f62fb0fa285e0
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/googledrivefs/googledrivefs.cc
@@ -0,0 +1,1346 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "nacl_io/googledrivefs/googledrivefs.h"
+
+#include <fcntl.h>
+
+#include <map>
+#include <algorithm>
+#include <cstdio>
+
+#include "ppapi/cpp/url_request_info.h"
+#include "ppapi/cpp/url_response_info.h"
+#include "ppapi/cpp/url_loader.h"
+#include "ppapi/cpp/file_ref.h"
+#include "ppapi/cpp/file_io.h"
+
+#include "nacl_io/error.h"
+#include "nacl_io/pepper_interface.h"
+#include "ppapi/c/pp_completion_callback.h"
+
+#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
+#include "json/writer.h"
+
+#include "nacl_io/filesystem.h"
+#include "nacl_io/kernel_handle.h"
+#include "nacl_io/getdents_helper.h"
+
+#ifdef WIN32
+#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.
+#else
+#include <unistd.h>
+#endif
+
+namespace nacl_io {
+
+namespace {
+
+std::string MapToHeaders(
+ const std::map<std::string, std::string>& header_field_map) {
+ std::string request_headers = "";
+
+ for (std::map<std::string, std::string>::const_iterator it =
+ header_field_map.begin();
+ it != header_field_map.end(); ++it) {
+ request_headers += it->first;
+ request_headers += ": ";
+ request_headers += it->second;
+ request_headers += "\n";
+ }
+ return request_headers;
+}
+
+// Continuing DJB2a hash
+ino_t HashPathSegment(ino_t hash, const char* str, size_t len) {
+ // First add the path seperator
+ hash = (hash * static_cast<ino_t>(33)) ^ '/';
+ while (len--) {
+ hash = (hash * static_cast<ino_t>(33)) ^ *str++;
+ }
+ return hash;
+}
+
+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.
+ // Prime the DJB2a hash
+ ino_t hash = 5381;
+
+ // Apply a running DJB2a to each part of the path
+ for (size_t segment = 0; segment < path.Size(); segment++) {
+ const std::string& part = path.Part(segment);
+ hash = HashPathSegment(hash, part.c_str(), part.length());
+ }
+ return hash;
+}
+
+// A Google Drive item is a file or a directory.
+// RequestDirId requests to see if a directory with dir_name
+// and a parent with ID parent_dir_id is there.
+// If it is, dir_id is set.
+// RequestDirId returns ENOENT when a file with dir_name is there
+// but a directory with dir_name is not.
+Error RequestDirId(const std::string& parent_dir_id,
+ const std::string& dir_name,
+ Filesystem* filesystem,
+ std::string& dir_id) {
+ dir_id = "";
+
+ 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
+ url += "?";
+ url += "q=";
+ url += "%27";
+ url += parent_dir_id;
+ url += "%27+in+parents";
+ url += "+and+";
+ url += "mimeType+=+";
+ url += "%27application/vnd.google-apps.folder%27";
+ url += "+and+";
+ url += "name+=+%27" + dir_name + "%27";
+
+ 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
+ if (googledrivefs == NULL) {
+ return EINVAL;
+ }
+
+ 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
+ pp::URLRequestInfo request(pp::InstanceHandle(googledrivefs->instance()));
+
+ 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
+ if (!set_url_ok) {
+ return EPERM;
+ }
+
+ bool set_method_ok = request.SetMethod("GET");
+ if (!set_method_ok) {
+ return EPERM;
+ }
+
+ 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
+ headers_map["Content-type"] = "application/json";
+ std::string authorization_value = "Bearer ";
+ authorization_value += googledrivefs->token();
+ headers_map["Authorization"] = authorization_value;
+
+ std::string headers = MapToHeaders(headers_map);
+
+ bool set_headers_ok = request.SetHeaders(headers);
+ if (!set_headers_ok) {
+ return EPERM;
+ }
+
+ bool set_allow_cross_origin_requests_ok =
+ request.SetAllowCrossOriginRequests(true);
+ if (!set_allow_cross_origin_requests_ok) {
+ return EPERM;
+ }
+
+ bool set_stream_to_file_ok = request.SetStreamToFile(true);
+ if (!set_stream_to_file_ok) {
+ return EPERM;
+ }
+
+ int32_t err = loader.Open(request, pp::BlockUntilComplete());
+ if (err < 0) {
+ return PPERROR_TO_ERRNO(err);
+ }
+
+ pp::URLResponseInfo response = loader.GetResponseInfo();
+ if (response.GetStatusCode() != 200) {
+ return EPERM;
+ }
+
+ pp::FileRef file_ref = response.GetBodyAsFileRef();
+ pp::FileIO file_io(pp::InstanceHandle(googledrivefs->instance()));
+
+ int32_t open_result =
+ file_io.Open(file_ref, PP_FILEOPENFLAG_READ, pp::BlockUntilComplete());
+ if (open_result < 0) {
+ return PPERROR_TO_ERRNO(open_result);
+ }
+
+ int BUFFER_SIZE = 1024;
+ 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
+
+ int32_t byte_read =
+ file_io.Read(0, buffer, BUFFER_SIZE, pp::BlockUntilComplete());
+ 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
+#ifdef WIN32
+ Sleep(1000);
+#else
+ 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
+#endif
+
+ byte_read = file_io.Read(0, buffer, BUFFER_SIZE, pp::BlockUntilComplete());
+ }
+
+ if (byte_read < 0) {
+ return PPERROR_TO_ERRNO(byte_read);
+ }
+
+ std::string output(buffer);
+
+ Json::Value root;
+
+ Json::Reader reader(Json::Features::strictMode());
+ if (!reader.parse(output, root, false)) {
+ return EPERM;
+ }
+
+ if (!root.isMember("files")) {
+ return EPERM;
+ }
+
+ Json::Value files_array = root["files"];
+ if (!files_array.isArray()) {
+ return EPERM;
+ }
+ if (files_array.size() == 0) {
+ return ENOENT;
+ }
+
+ dir_id = files_array[0]["id"].asString();
+
+ return 0;
+}
+
+// A Google Drive item is a file or a directory.
+// RequestItemId requests to see if either a file with item_name
+// or a directory with item_name is there.
+// If it is, item_id is set.
+Error RequestItemId(const std::string& parent_dir_id,
+ const std::string& item_name,
+ Filesystem* filesystem,
+ std::string& item_id) {
+ item_id = "";
+
+ std::string url = "https://www.googleapis.com/drive/v3/files";
+ url += "?";
+ url += "q=";
+ url += "%27";
+ url += parent_dir_id;
+ url += "%27+in+parents";
+ url += "+and+";
+ url += "name+=+%27" + item_name + "%27";
+
+ GoogleDriveFs* googledrivefs = dynamic_cast<GoogleDriveFs*>(filesystem);
+ if (googledrivefs == NULL) {
+ return EINVAL;
+ }
+
+ pp::URLLoader loader(pp::InstanceHandle(googledrivefs->instance()));
+ pp::URLRequestInfo request(pp::InstanceHandle(googledrivefs->instance()));
+
+ bool set_url_ok = request.SetURL(url);
+ if (!set_url_ok) {
+ return EPERM;
+ }
+
+ bool set_method_ok = request.SetMethod("GET");
+ if (!set_method_ok) {
+ return EPERM;
+ }
+
+ std::map<std::string, std::string> headers_map;
+ headers_map["Content-type"] = "application/json";
+ std::string authorization_value = "Bearer ";
+ authorization_value += googledrivefs->token();
+ headers_map["Authorization"] = authorization_value;
+
+ std::string headers = MapToHeaders(headers_map);
+
+ bool set_headers_ok = request.SetHeaders(headers);
+ if (!set_headers_ok) {
+ return EPERM;
+ }
+
+ bool set_allow_cross_origin_requests_ok =
+ request.SetAllowCrossOriginRequests(true);
+ if (!set_allow_cross_origin_requests_ok) {
+ return EPERM;
+ }
+
+ bool set_stream_to_file_ok = request.SetStreamToFile(true);
+ if (!set_stream_to_file_ok) {
+ return EPERM;
+ }
+
+ int32_t err = loader.Open(request, pp::BlockUntilComplete());
+ if (err < 0) {
+ return PPERROR_TO_ERRNO(err);
+ }
+
+ pp::URLResponseInfo response = loader.GetResponseInfo();
+ if (response.GetStatusCode() != 200) {
+ return EPERM;
+ }
+
+ pp::FileRef file_ref = response.GetBodyAsFileRef();
+ pp::FileIO file_io(pp::InstanceHandle(googledrivefs->instance()));
+
+ int32_t open_result =
+ file_io.Open(file_ref, PP_FILEOPENFLAG_READ, pp::BlockUntilComplete());
+ if (open_result < 0) {
+ return PPERROR_TO_ERRNO(open_result);
+ }
+
+ int BUFFER_SIZE = 1024;
+ char buffer[BUFFER_SIZE];
+
+ int32_t byte_read =
+ file_io.Read(0, buffer, BUFFER_SIZE, pp::BlockUntilComplete());
+ while (byte_read == 0) {
+#ifdef WIN32
+ Sleep(1000);
+#else
+ usleep(1000000);
+#endif
+
+ byte_read = file_io.Read(0, buffer, BUFFER_SIZE, pp::BlockUntilComplete());
+ }
+
+ if (byte_read < 0) {
+ return PPERROR_TO_ERRNO(byte_read);
+ }
+
+ std::string output(buffer);
+
+ Json::Value root;
+
+ Json::Reader reader(Json::Features::strictMode());
+ if (!reader.parse(output, root, false)) {
+ return EPERM;
+ }
+
+ if (!root.isMember("files")) {
+ return EPERM;
+ }
+
+ Json::Value files_array = root["files"];
+
+ if (!files_array.isArray()) {
+ return EPERM;
+ }
+ if (files_array.size() == 0) {
+ return ENOENT;
+ }
+
+ item_id = files_array[0]["id"].asString();
+
+ return 0;
+}
+
+Error RequestParentDirId(const Path& path,
+ Filesystem* filesystem,
+ 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
+ parent_dir_id = "";
+
+ if (path.Size() < 2) {
+ return EINVAL;
+ }
+
+ std::string helper_parent_dir_id = "root";
+
+ for (unsigned int i = 1; i < path.Size() - 1; ++i) {
+ std::string dir_name = path.Range(i, i + 1);
+
+ std::string dir_id = "";
+ Error error =
+ RequestDirId(helper_parent_dir_id, dir_name, filesystem, dir_id);
+ if (error) {
+ return error;
+ }
+
+ helper_parent_dir_id = dir_id;
+ }
+ parent_dir_id = helper_parent_dir_id;
+
+ return 0;
+}
+}
+
+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
+ public:
+ GoogleDriveFsNode(Filesystem* filesystem, Path path)
+ : Node(filesystem), path_(path) {}
+
+ Error GetDents(size_t offs,
+ struct dirent* pdir,
+ size_t size,
+ int* out_bytes) {
+ if (!IsaDir()) {
+ return ENOTDIR;
+ }
+
+ const ino_t kCurDirIno = -1;
+ const ino_t kParentDirIno = -2;
+ GetDentsHelper helper(kCurDirIno, kParentDirIno);
+
+ std::vector<std::string> dirent_names;
+ Error error = RequestDirent(dirent_names);
+ if (error) {
+ return error;
+ }
+
+ for (unsigned int i = 0; i < dirent_names.size(); ++i) {
+ Path child_path(path_);
+ child_path = child_path.Append("/" + dirent_names[i]);
+ ino_t child_ino = HashPath(child_path);
+
+ helper.AddDirent(child_ino, dirent_names[i].c_str(),
+ dirent_names[i].size());
+ }
+
+ return helper.GetDents(offs, pdir, size, out_bytes);
+ }
+
+ Error GetStat(struct stat* pstat) {
+ Error error = GetSize(&pstat->st_size);
+ if (error) {
+ return error;
+ }
+ return 0;
+ }
+
+ Error Write(const HandleAttr& attr,
+ const void* buf,
+ size_t count,
+ int* out_bytes) {
+ *out_bytes = 0;
+
+ if (IsaDir()) {
+ return EISDIR;
+ }
+
+ off_t file_size = 0;
+ Error error = GetSize(&file_size);
+ if (error) {
+ return error;
+ }
+
+ off_t file_buf_size = std::max((unsigned long long int)file_size,
+ (unsigned long long int)attr.offs + count);
+ 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
+
+ if (file_size > 0) {
+ int read_helper_out_bytes = 0;
+
+ error = ReadHelper(0, file_size - 1, file_buf, file_size,
+ &read_helper_out_bytes);
+
+ if (error) {
+ return error;
+ }
+
+ if (read_helper_out_bytes != file_size) {
+ return EPERM;
+ }
+ }
+
+ char* pChar = (char*)buf;
+ for (unsigned int i = 0; i < count; ++i) {
+ file_buf[attr.offs + i] = pChar[i];
+ }
+
+ error = WriteHelper(file_buf, file_buf_size);
+ if (error) {
+ return error;
+ }
+
+ *out_bytes = count;
+
+ return 0;
+ }
+
+ Error FTruncate(off_t length) {
+ if (IsaDir()) {
+ return EISDIR;
+ }
+
+ off_t file_size = 0;
+ Error error = GetSize(&file_size);
+ if (error) {
+ return error;
+ }
+
+ char file_buf[length];
+
+ if (file_size > 0) {
+ int read_helper_out_bytes = 0;
+
+ error = ReadHelper(0, file_size - 1, file_buf, file_size,
+ &read_helper_out_bytes);
+ if (error) {
+ return error;
+ }
+
+ if (read_helper_out_bytes != file_size) {
+ return EPERM;
+ }
+ }
+
+ for (int i = file_size; i < length; ++i) {
+ file_buf[i] = '\0';
+ }
+
+ error = WriteHelper(file_buf, length);
+ if (error) {
+ return error;
+ }
+
+ return 0;
+ }
+
+ Error Read(const HandleAttr& attr, void* buf, size_t count, int* out_bytes) {
+ *out_bytes = 0;
+
+ if (IsaDir()) {
+ return EISDIR;
+ }
+
+ Error error =
+ ReadHelper(attr.offs, attr.offs + count - 1, buf, count, out_bytes);
+ if (error) {
+ return error;
+ }
+
+ return 0;
+ }
+
+ int GetType() { return IsaDir() ? S_IFDIR : S_IFREG; }
+
+ Error GetSize(off_t* out_size) {
+ *out_size = 0;
+
+ if (IsaDir()) {
+ return 0;
+ }
+
+ GoogleDriveFs* googledrivefs = dynamic_cast<GoogleDriveFs*>(filesystem_);
+ if (googledrivefs == NULL) {
+ return EINVAL;
+ }
+
+ pp::URLLoader loader(pp::InstanceHandle(googledrivefs->instance()));
+ pp::URLRequestInfo request(pp::InstanceHandle(googledrivefs->instance()));
+
+ std::string url = "https://www.googleapis.com/drive/v3/files/";
+ url += item_id_;
+ url += "?";
+ url += "fields=size";
+
+ bool set_url_ok = request.SetURL(url);
+ if (!set_url_ok) {
+ return EPERM;
+ }
+
+ bool set_method_ok = request.SetMethod("GET");
+ if (!set_method_ok) {
+ return EPERM;
+ }
+
+ std::map<std::string, std::string> headers_map;
+ headers_map["Content-type"] = "application/json";
+ std::string authorization_value = "Bearer ";
+ authorization_value += googledrivefs->token();
+ headers_map["Authorization"] = authorization_value;
+
+ std::string headers = MapToHeaders(headers_map);
+
+ bool set_headers_ok = request.SetHeaders(headers);
+ if (!set_headers_ok) {
+ return EPERM;
+ }
+
+ bool set_allow_cross_origin_requests_ok =
+ request.SetAllowCrossOriginRequests(true);
+ if (!set_allow_cross_origin_requests_ok) {
+ return EPERM;
+ }
+
+ bool set_stream_to_file_ok = request.SetStreamToFile(true);
+ if (!set_stream_to_file_ok) {
+ return EPERM;
+ }
+
+ int32_t err = loader.Open(request, pp::BlockUntilComplete());
+ if (err < 0) {
+ return PPERROR_TO_ERRNO(err);
+ }
+
+ pp::URLResponseInfo response = loader.GetResponseInfo();
+ if (response.GetStatusCode() != 200) {
+ return EPERM;
+ }
+
+ pp::FileRef file_ref = response.GetBodyAsFileRef();
+ pp::FileIO file_io(pp::InstanceHandle(googledrivefs->instance()));
+ int32_t open_result =
+ file_io.Open(file_ref, PP_FILEOPENFLAG_READ, pp::BlockUntilComplete());
+
+ if (open_result < 0) {
+ return PPERROR_TO_ERRNO(open_result);
+ }
+
+ int BUFFER_SIZE = 1024;
+ char buffer[BUFFER_SIZE];
+
+ int32_t byte_read =
+ file_io.Read(0, buffer, BUFFER_SIZE, pp::BlockUntilComplete());
+ while (byte_read == 0) {
+#ifdef WIN32
+ Sleep(1000);
+#else
+ usleep(1000000);
+#endif
+
+ byte_read =
+ file_io.Read(0, buffer, BUFFER_SIZE, pp::BlockUntilComplete());
+ }
+ if (byte_read < 0) {
+ return PPERROR_TO_ERRNO(byte_read);
+ }
+
+ std::string output(buffer);
+ Json::Value root;
+
+ Json::Reader reader(Json::Features::strictMode());
+ if (!reader.parse(output, root, false)) {
+ return EPERM;
+ }
+
+ if (!root.isMember("size")) {
+ return EPERM;
+ }
+
+ Json::Value size_value = root["size"];
+
+ *out_size = (off_t)atoi(size_value.asCString());
+
+ return 0;
+ }
+
+ Error Init(int open_flags) {
+ Error error = Node::Init(open_flags);
+
+ if (error) {
+ return error;
+ }
+
+ if (path_.Size() == 1) {
+ parent_dir_id_ = "";
+ item_id_ = "root";
+ is_dir_item_ = true;
+ return 0;
+ }
+
+ error = RequestParentDirId(path_, filesystem_, parent_dir_id_);
+ if (error) {
+ return error;
+ }
+
+ // Request the ID of an item, which is a file or a directory
+ error =
+ RequestItemId(parent_dir_id_, path_.Basename(), filesystem_, item_id_);
+
+ if (error == ENOENT) {
+ // Only files are open as mode O_CREAT
+ if ((open_flags & O_CREAT) != 0) {
+ error = CreateEmptyFile();
+ if (error) {
+ return error;
+ }
+ error = RequestItemId(parent_dir_id_, path_.Basename(), filesystem_,
+ item_id_);
+ if (error) {
+ return error;
+ }
+ is_dir_item_ = false;
+ } else {
+ return ENOENT;
+ }
+ } else if (error) {
+ return error;
+ } else {
+ std::string dir_id = "";
+ error =
+ RequestDirId(parent_dir_id_, path_.Basename(), filesystem_, dir_id);
+ if (error == ENOENT) {
+ is_dir_item_ = false;
+ } else if (error) {
+ return error;
+ } else {
+ is_dir_item_ = true;
+ }
+
+ if (open_flags == 0) {
+ // open_flags == 0 for file opened on fopen with mode r and directory
+ // opened on opendir
+ return 0;
+ } else if (is_dir_item_ && open_flags != 0) {
+ return EPERM;
+ } else if ((open_flags & O_TRUNC) != 0) {
+ error = WriteHelper(NULL, 0);
+ if (error) {
+ return error;
+ }
+ }
+ }
+
+ return 0;
+ }
+
+ void Destroy() { Node::Destroy(); }
+
+ bool IsaDir() { return is_dir_item_; }
+
+ private:
+ Error ReadHelper(off_t start,
+ off_t end,
+ void* buf,
+ size_t count,
+ int* out_bytes) {
+ *out_bytes = 0;
+
+ GoogleDriveFs* googledrivefs = dynamic_cast<GoogleDriveFs*>(filesystem_);
+ if (googledrivefs == NULL) {
+ return EINVAL;
+ }
+
+ pp::URLLoader loader(pp::InstanceHandle(googledrivefs->instance()));
+ pp::URLRequestInfo request(pp::InstanceHandle(googledrivefs->instance()));
+
+ std::string url = "https://www.googleapis.com/download/drive/v3/files/";
+ url += item_id_;
+ url += "?";
+ url += "alt=media";
+
+ bool set_url_ok = request.SetURL(url);
+ if (!set_url_ok) {
+ return EPERM;
+ }
+
+ bool set_method_ok = request.SetMethod("GET");
+ if (!set_method_ok) {
+ return EPERM;
+ }
+
+ std::map<std::string, std::string> headers_map;
+ headers_map["Content-type"] = "application/json";
+ std::string authorization_value = "Bearer ";
+ authorization_value += googledrivefs->token();
+ headers_map["Authorization"] = authorization_value;
+ char range_value_buffer[1024];
+ int char_written = sprintf(range_value_buffer, "bytes=%lli-%lli",
+ (long long int)start, (long long int)end);
+ if (char_written < 0) {
+ return EPERM;
+ }
+ std::string range_value(range_value_buffer);
+ headers_map["Range"] = range_value;
+
+ std::string headers = MapToHeaders(headers_map);
+
+ bool set_headers_ok = request.SetHeaders(headers);
+ if (!set_headers_ok) {
+ return EPERM;
+ }
+
+ bool set_allow_cross_origin_requests_ok =
+ request.SetAllowCrossOriginRequests(true);
+ if (!set_allow_cross_origin_requests_ok) {
+ return EPERM;
+ }
+
+ bool set_stream_to_file_ok = request.SetStreamToFile(true);
+ if (!set_stream_to_file_ok) {
+ return EPERM;
+ }
+
+ int32_t err = loader.Open(request, pp::BlockUntilComplete());
+ if (err < 0) {
+ return PPERROR_TO_ERRNO(err);
+ }
+
+ pp::URLResponseInfo response = loader.GetResponseInfo();
+
+ 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
+ pp::FileRef file_ref = response.GetBodyAsFileRef();
+ pp::FileIO file_io(pp::InstanceHandle(googledrivefs->instance()));
+
+ int32_t open_result = file_io.Open(file_ref, PP_FILEOPENFLAG_READ,
+ pp::BlockUntilComplete());
+ if (open_result < 0) {
+ return PPERROR_TO_ERRNO(open_result);
+ }
+
+ int32_t byte_read =
+ file_io.Read(0, (char*)buf, count, pp::BlockUntilComplete());
+ while (byte_read == 0) {
+#ifdef WIN32
+ Sleep(1000);
+#else
+ usleep(1000000);
+#endif
+
+ byte_read =
+ file_io.Read(0, (char*)buf, count, pp::BlockUntilComplete());
+ }
+
+ if (byte_read < 0) {
+ return PPERROR_TO_ERRNO(byte_read);
+ }
+
+ *out_bytes = byte_read;
+
+ return 0;
+
+ } else if (response.GetStatusCode() == 416) {
+ *out_bytes = 0;
+
+ char* pChar = (char*)buf;
+ pChar[0] = '\0';
+
+ return 0;
+ }
+
+ return EPERM;
+ }
+
+ Error WriteHelper(const void* request_body_data, uint32_t request_body_size) {
+ GoogleDriveFs* googledrivefs = dynamic_cast<GoogleDriveFs*>(filesystem_);
+ if (googledrivefs == NULL) {
+ return EINVAL;
+ }
+
+ pp::URLLoader loader(pp::InstanceHandle(googledrivefs->instance()));
+ pp::URLRequestInfo request(pp::InstanceHandle(googledrivefs->instance()));
+
+ std::string url = "https://www.googleapis.com/upload/drive/v3/files/";
+ url += item_id_;
+ url += "?";
+ url += "uploadType=media";
+
+ bool set_url_ok = request.SetURL(url);
+ if (!set_url_ok) {
+ return EPERM;
+ }
+ bool set_method_ok = request.SetMethod("PATCH");
+ if (!set_method_ok) {
+ return EPERM;
+ }
+
+ std::map<std::string, std::string> headers_map;
+ headers_map["Content-type"] = "application/json";
+ std::string authorization_value = "Bearer ";
+ authorization_value += googledrivefs->token();
+ headers_map["Authorization"] = authorization_value;
+
+ std::string headers = MapToHeaders(headers_map);
+
+ bool set_headers_ok = request.SetHeaders(headers);
+ if (!set_headers_ok) {
+ return EPERM;
+ }
+
+ bool set_allow_cross_origin_requests_ok =
+ request.SetAllowCrossOriginRequests(true);
+ if (!set_allow_cross_origin_requests_ok) {
+ return EPERM;
+ }
+
+ bool set_stream_to_file_ok = request.SetStreamToFile(true);
+ if (!set_stream_to_file_ok) {
+ return EPERM;
+ }
+
+ bool append_data_to_body_ok =
+ request.AppendDataToBody(request_body_data, request_body_size);
+ if (!append_data_to_body_ok) {
+ return EPERM;
+ }
+
+ int32_t err = loader.Open(request, pp::BlockUntilComplete());
+ if (err < 0) {
+ return PPERROR_TO_ERRNO(err);
+ }
+
+ pp::URLResponseInfo response = loader.GetResponseInfo();
+ if (response.GetStatusCode() != 200) {
+ return EPERM;
+ }
+
+ return 0;
+ }
+
+ Error CreateEmptyFile() {
+ std::string url =
+ "https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart";
+
+ GoogleDriveFs* googledrivefs = dynamic_cast<GoogleDriveFs*>(filesystem_);
+ if (googledrivefs == NULL) {
+ return EINVAL;
+ }
+
+ pp::URLLoader loader(pp::InstanceHandle(googledrivefs->instance()));
+ pp::URLRequestInfo request(pp::InstanceHandle(googledrivefs->instance()));
+
+ bool set_url_ok = request.SetURL(url);
+ if (!set_url_ok) {
+ return EPERM;
+ }
+
+ bool set_method_ok = request.SetMethod("POST");
+ if (!set_method_ok) {
+ return EPERM;
+ }
+
+ std::string BOUNDARY_VALUE = "foo_bar_baz";
+
+ std::map<std::string, std::string> headers_map;
+ headers_map["Content-type"] =
+ "multipart/related; boundary=" + BOUNDARY_VALUE;
+ std::string authorization_value = "Bearer ";
+ authorization_value += googledrivefs->token();
+ headers_map["Authorization"] = authorization_value;
+
+ std::string headers = MapToHeaders(headers_map);
+
+ bool set_headers_ok = request.SetHeaders(headers);
+ if (!set_headers_ok) {
+ return EPERM;
+ }
+
+ bool set_allow_cross_origin_requests_ok =
+ request.SetAllowCrossOriginRequests(true);
+ if (!set_allow_cross_origin_requests_ok) {
+ return EPERM;
+ }
+
+ bool set_stream_to_file_ok = request.SetStreamToFile(true);
+ if (!set_stream_to_file_ok) {
+ return EPERM;
+ }
+
+ std::string request_body = "--";
+ request_body += BOUNDARY_VALUE;
+ request_body += "\n";
+
+ request_body += "Content-Type: application/json; charset=UTF-8";
+ request_body += "\n";
+
+ request_body += "\n";
+
+ request_body += "{";
+ request_body += "\n";
+
+ request_body += " \"name\": ";
+ request_body += "\"";
+ request_body += path_.Basename();
+ request_body += "\"";
+ request_body += ",";
+ request_body += "\n";
+
+ request_body += " \"parents\": ";
+ request_body += "[";
+ request_body += "\n";
+
+ request_body += " \"";
+ request_body += parent_dir_id_;
+ request_body += "\"";
+ request_body += "\n";
+
+ request_body += " ]";
+ request_body += "\n";
+
+ request_body += "}";
+ request_body += "\n";
+
+ request_body += "\n";
+
+ request_body += "--";
+ request_body += BOUNDARY_VALUE;
+ request_body += "\n";
+
+ request_body += "Content-Type: text/plain";
+ request_body += "\n";
+
+ request_body += "\n";
+
+ request_body += "\n";
+
+ request_body += "--";
+ request_body += BOUNDARY_VALUE;
+ request_body += "--";
+
+ bool append_data_to_body_ok =
+ request.AppendDataToBody(request_body.data(), request_body.size());
+ if (!append_data_to_body_ok) {
+ return EPERM;
+ }
+
+ int32_t err = loader.Open(request, pp::BlockUntilComplete());
+ if (err < 0) {
+ return PPERROR_TO_ERRNO(err);
+ }
+
+ pp::URLResponseInfo response = loader.GetResponseInfo();
+ if (response.GetStatusCode() != 200) {
+ return EPERM;
+ }
+
+ return 0;
+ }
+
+ Error RequestDirent(std::vector<std::string>& dirent_names) {
+ std::string url = "https://www.googleapis.com/drive/v3/files";
+ url += "?";
+ url += "q=";
+ url += "%27";
+ url += item_id_;
+ url += "%27+in+parents";
+
+ GoogleDriveFs* googledrivefs = dynamic_cast<GoogleDriveFs*>(filesystem_);
+ if (googledrivefs == NULL) {
+ return EINVAL;
+ }
+
+ pp::URLLoader loader(pp::InstanceHandle(googledrivefs->instance()));
+ pp::URLRequestInfo request(pp::InstanceHandle(googledrivefs->instance()));
+
+ bool set_url_ok = request.SetURL(url);
+ if (!set_url_ok) {
+ return EPERM;
+ }
+
+ bool set_method_ok = request.SetMethod("GET");
+ if (!set_method_ok) {
+ return EPERM;
+ }
+
+ std::map<std::string, std::string> headers_map;
+ headers_map["Content-type"] = "application/json";
+ std::string authorization_value = "Bearer ";
+ authorization_value += googledrivefs->token();
+ headers_map["Authorization"] = authorization_value;
+
+ std::string headers = MapToHeaders(headers_map);
+
+ bool set_headers_ok = request.SetHeaders(headers);
+ if (!set_headers_ok) {
+ return EPERM;
+ }
+
+ bool set_allow_cross_origin_requests_ok =
+ request.SetAllowCrossOriginRequests(true);
+ if (!set_allow_cross_origin_requests_ok) {
+ return EPERM;
+ }
+
+ bool set_stream_to_file_ok = request.SetStreamToFile(true);
+ if (!set_stream_to_file_ok) {
+ return EPERM;
+ }
+
+ int32_t err = loader.Open(request, pp::BlockUntilComplete());
+ if (err < 0) {
+ return PPERROR_TO_ERRNO(err);
+ }
+
+ pp::URLResponseInfo response = loader.GetResponseInfo();
+ if (response.GetStatusCode() != 200) {
+ return EPERM;
+ }
+
+ pp::FileRef file_ref = response.GetBodyAsFileRef();
+ pp::FileIO file_io(pp::InstanceHandle(googledrivefs->instance()));
+
+ int32_t open_result =
+ file_io.Open(file_ref, PP_FILEOPENFLAG_READ, pp::BlockUntilComplete());
+ if (open_result < 0) {
+ return PPERROR_TO_ERRNO(open_result);
+ }
+
+ std::string output = "";
+ int BUFFER_SIZE = 1024;
+ char buffer[BUFFER_SIZE];
+ int byte_read =
+ file_io.Read(0, buffer, BUFFER_SIZE, pp::BlockUntilComplete());
+
+ while (byte_read == 0) {
+#ifdef WIN32
+ Sleep(1000);
+#else
+ usleep(1000000);
+#endif
+
+ byte_read =
+ file_io.Read(0, buffer, BUFFER_SIZE, pp::BlockUntilComplete());
+ }
+
+ while (byte_read > 0) {
+ output += buffer;
+
+ byte_read = file_io.Read(byte_read, buffer, BUFFER_SIZE,
+ pp::BlockUntilComplete());
+ }
+
+ if (byte_read < 0) {
+ return PPERROR_TO_ERRNO(byte_read);
+ }
+
+ Json::Value root;
+
+ Json::Reader reader(Json::Features::strictMode());
+ if (!reader.parse(output, root, false)) {
+ return EPERM;
+ }
+
+ if (!root.isMember("files")) {
+ return EPERM;
+ }
+
+ Json::Value files_array = root["files"];
+
+ if (!files_array.isArray()) {
+ return EPERM;
+ }
+
+ for (unsigned int i = 0; i < files_array.size(); ++i) {
+ dirent_names.push_back(files_array[i]["name"].asString());
+ }
+
+ // TODO: Too many entries result in nextPageToken in API response and
+ // out-of-memory in output variable.
+
+ return 0;
+ }
+
+ std::string parent_dir_id_;
+ std::string item_id_;
+ bool is_dir_item_;
+ Path path_;
+
+ friend class GoogleDriveFs;
+};
+
+GoogleDriveFs::GoogleDriveFs() {}
+
+GoogleDriveFs::~GoogleDriveFs() {}
+
+Error GoogleDriveFs::Init(const FsInitArgs& args) {
+ Error error = Filesystem::Init(args);
+ if (error) {
+ return error;
+ }
+
+ std::map<std::string, std::string>::const_iterator instance_it =
+ args.string_map.find("instance");
+
+ if (instance_it == args.string_map.end()) {
+ return EINVAL;
+ }
+
+ instance_ = atoi(instance_it->second.c_str());
+
+ std::map<std::string, std::string>::const_iterator token_it =
+ args.string_map.find("token");
+
+ if (token_it == args.string_map.end()) {
+ return EINVAL;
+ }
+
+ token_ = token_it->second;
+
+ return 0;
+}
+
+void GoogleDriveFs::Destroy() {}
+
+Error GoogleDriveFs::OpenWithMode(const Path& path,
+ int open_flags,
+ mode_t mode,
+ ScopedNode* out_node) {
+ ScopedNode node(new GoogleDriveFsNode(this, path));
+
+ Error error = node->Init(open_flags);
+ if (error) {
+ return error;
+ }
+
+ *out_node = node;
+
+ return 0;
+}
+
+Error GoogleDriveFs::Rename(const Path& path, const Path& newPath) {
+ LOG_ERROR("rename not supported.");
+ return EPERM;
+}
+
+Error GoogleDriveFs::Unlink(const Path& path) {
+ LOG_ERROR("unlink not supported.");
+ return EPERM;
+}
+
+Error GoogleDriveFs::Mkdir(const Path& path, int permissions) {
+ std::string parent_dir_id = "";
+ Error error = RequestParentDirId(path, this, parent_dir_id);
+ if (error) {
+ return error;
+ }
+
+ std::string item_id = "";
+ error = RequestItemId(parent_dir_id, path.Basename(), this, item_id);
+
+ // mkdir does not create a directory when a file with path.Basename()
+ // already exists
+ if (error == ENOENT) {
+ std::string url = "https://www.googleapis.com/drive/v3/files";
+
+ pp::URLLoader loader(pp::InstanceHandle(this->instance()));
+ pp::URLRequestInfo request(pp::InstanceHandle(this->instance()));
+
+ bool set_url_ok = request.SetURL(url);
+ if (!set_url_ok) {
+ return EPERM;
+ }
+
+ bool set_method_ok = request.SetMethod("POST");
+ if (!set_method_ok) {
+ return EPERM;
+ }
+
+ std::map<std::string, std::string> headers_map;
+ headers_map["Content-type"] = "application/json";
+ std::string authorization_value = "Bearer ";
+ authorization_value += token_;
+ headers_map["Authorization"] = authorization_value;
+
+ std::string headers = MapToHeaders(headers_map);
+
+ bool set_headers_ok = request.SetHeaders(headers);
+ if (!set_headers_ok) {
+ return EPERM;
+ }
+
+ Json::Value json_value;
+ json_value["name"] = path.Basename();
+ json_value["mimeType"] = "application/vnd.google-apps.folder";
+ Json::FastWriter fast_writer;
+ std::string request_body = fast_writer.write(json_value);
+
+ bool append_data_to_body_ok =
+ request.AppendDataToBody(request_body.data(), request_body.size());
+ if (!append_data_to_body_ok) {
+ return EPERM;
+ }
+
+ bool set_allow_cross_origin_requests_ok =
+ request.SetAllowCrossOriginRequests(true);
+ if (!set_allow_cross_origin_requests_ok) {
+ return EPERM;
+ }
+
+ bool set_stream_to_file_ok = request.SetStreamToFile(true);
+ if (!set_stream_to_file_ok) {
+ return EPERM;
+ }
+
+ int32_t err = loader.Open(request, pp::BlockUntilComplete());
+ if (err < 0) {
+ return PPERROR_TO_ERRNO(err);
+ }
+
+ pp::URLResponseInfo response = loader.GetResponseInfo();
+ if (response.GetStatusCode() != 200) {
+ return EPERM;
+ }
+
+ return 0;
+ }
+
+ return EEXIST;
+}
+
+Error GoogleDriveFs::Rmdir(const Path& path) {
+ std::string parent_dir_id = "";
+ Error error = RequestParentDirId(path, this, parent_dir_id);
+ if (error) {
+ return error;
+ }
+
+ std::string dir_id = "";
+ error = RequestDirId(parent_dir_id, path.Basename(), this, dir_id);
+ if (error) {
+ return error;
+ }
+
+ std::string url = "https://www.googleapis.com/drive/v3/files";
+
+ url += "/";
+ url += dir_id;
+
+ pp::URLLoader loader(pp::InstanceHandle(this->instance()));
+ pp::URLRequestInfo request(pp::InstanceHandle(this->instance()));
+
+ bool set_url_ok = request.SetURL(url);
+ if (!set_url_ok) {
+ return EPERM;
+ }
+ bool set_method_ok = request.SetMethod("DELETE");
+ if (!set_method_ok) {
+ return EPERM;
+ }
+
+ std::map<std::string, std::string> headers_map;
+ headers_map["Content-type"] = "application/json";
+ std::string authorization_value = "Bearer ";
+ authorization_value += token_;
+ headers_map["Authorization"] = authorization_value;
+
+ std::string headers = MapToHeaders(headers_map);
+
+ bool set_headers_ok = request.SetHeaders(headers);
+ if (!set_headers_ok) {
+ return EPERM;
+ }
+
+ bool set_allow_cross_origin_requests_ok =
+ request.SetAllowCrossOriginRequests(true);
+ if (!set_allow_cross_origin_requests_ok) {
+ return EPERM;
+ }
+
+ bool set_stream_to_file_ok = request.SetStreamToFile(true);
+ if (!set_stream_to_file_ok) {
+ return EPERM;
+ }
+
+ int32_t err = loader.Open(request, pp::BlockUntilComplete());
+ if (err < 0) {
+ return PPERROR_TO_ERRNO(err);
+ }
+
+ pp::URLResponseInfo response = loader.GetResponseInfo();
+ if (response.GetStatusCode() != 204) {
+ return EPERM;
+ }
+
+ return 0;
+}
+
+Error GoogleDriveFs::Remove(const Path& path) {
+ LOG_ERROR("remove not supported.");
+ return EPERM;
+}
+
+std::string GoogleDriveFs::token() {
+ return token_;
+}
+
+PP_Instance GoogleDriveFs::instance() {
+ return instance_;
+}
+
+} // namespace nacl_io

Powered by Google App Engine
This is Rietveld 408576698