diff --git a/tensorflow/c/experimental/filesystem/plugins/gcs/BUILD b/tensorflow/c/experimental/filesystem/plugins/gcs/BUILD index c7a2d68ac3e..c9fee433589 100644 --- a/tensorflow/c/experimental/filesystem/plugins/gcs/BUILD +++ b/tensorflow/c/experimental/filesystem/plugins/gcs/BUILD @@ -27,5 +27,6 @@ cc_library( "//tensorflow/c:tf_status", "//tensorflow/c/experimental/filesystem:filesystem_interface", "@com_github_googlecloudplatform_google_cloud_cpp//:storage_client", + "@com_google_absl//absl/strings", ], ) diff --git a/tensorflow/c/experimental/filesystem/plugins/gcs/gcs_filesystem.cc b/tensorflow/c/experimental/filesystem/plugins/gcs/gcs_filesystem.cc index 7918e7a7310..8c54bc85439 100644 --- a/tensorflow/c/experimental/filesystem/plugins/gcs/gcs_filesystem.cc +++ b/tensorflow/c/experimental/filesystem/plugins/gcs/gcs_filesystem.cc @@ -15,6 +15,7 @@ limitations under the License. #include #include +#include "absl/strings/string_view.h" #include "google/cloud/storage/client.h" #include "tensorflow/c/experimental/filesystem/filesystem_interface.h" #include "tensorflow/c/tf_status.h" @@ -35,6 +36,45 @@ static inline void TF_SetStatusFromGCSStatus( static void* plugin_memory_allocate(size_t size) { return calloc(1, size); } static void plugin_memory_free(void* ptr) { free(ptr); } +static void ParseGCSPath(absl::string_view fname, bool object_empty_ok, + char** bucket, char** object, TF_Status* status) { + size_t scheme_end = fname.find("://") + 2; + if (fname.substr(0, scheme_end + 1) != "gs://") { + TF_SetStatus(status, TF_INVALID_ARGUMENT, + "GCS path doesn't start with 'gs://'."); + return; + } + + size_t bucket_end = fname.find("/", scheme_end + 1); + if (bucket_end == absl::string_view::npos) { + TF_SetStatus(status, TF_INVALID_ARGUMENT, + "GCS path doesn't contain a bucket name."); + return; + } + absl::string_view bucket_view = + fname.substr(scheme_end + 1, bucket_end - scheme_end - 1); + *bucket = + static_cast(plugin_memory_allocate(bucket_view.length() + 1)); + memcpy(*bucket, bucket_view.data(), bucket_view.length()); + (*bucket)[bucket_view.length()] = '\0'; + + absl::string_view object_view = fname.substr(bucket_end + 1); + if (object_view.empty()) { + if (object_empty_ok) { + *object = nullptr; + return; + } else { + TF_SetStatus(status, TF_INVALID_ARGUMENT, + "GCS path doesn't contain an object name."); + return; + } + } + *object = + static_cast(plugin_memory_allocate(object_view.length() + 1)); + // object_view.data() is a null-terminated string_view because fname is. + strcpy(*object, object_view.data()); +} + // SECTION 1. Implementation for `TF_RandomAccessFile` // ---------------------------------------------------------------------------- namespace tf_random_access_file {