Util to load file contents into grpc_core::Slice (#31176)
* Util to load file contents into grpc_core::Slice * Add test * iwyu * iwyu againpull/31150/head^2
parent
6cac641c64
commit
e1e1f6181f
11 changed files with 469 additions and 108 deletions
@ -0,0 +1,75 @@ |
|||||||
|
// Copyright 2022 gRPC authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include <grpc/support/port_platform.h> |
||||||
|
|
||||||
|
#include "src/core/lib/gprpp/load_file.h" |
||||||
|
|
||||||
|
#include <errno.h> |
||||||
|
#include <stdio.h> |
||||||
|
#include <string.h> |
||||||
|
|
||||||
|
#include "absl/cleanup/cleanup.h" |
||||||
|
#include "absl/status/status.h" |
||||||
|
#include "absl/strings/str_cat.h" |
||||||
|
|
||||||
|
#include <grpc/slice.h> |
||||||
|
#include <grpc/support/alloc.h> |
||||||
|
#include <grpc/support/log.h> |
||||||
|
|
||||||
|
namespace grpc_core { |
||||||
|
|
||||||
|
// Loads the content of a file into a slice. add_null_terminator will add a NULL
|
||||||
|
// terminator if true.
|
||||||
|
absl::StatusOr<Slice> LoadFile(std::string filename, bool add_null_terminator) { |
||||||
|
unsigned char* contents = nullptr; |
||||||
|
size_t contents_size = 0; |
||||||
|
FILE* file; |
||||||
|
size_t bytes_read = 0; |
||||||
|
absl::Status error = absl::OkStatus(); |
||||||
|
auto sock_cleanup = absl::MakeCleanup([&file]() -> void { |
||||||
|
if (file != nullptr) { |
||||||
|
fclose(file); |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
file = fopen(filename.c_str(), "rb"); |
||||||
|
if (file == nullptr) { |
||||||
|
error = absl::InternalError( |
||||||
|
absl::StrCat("Failed to load file: ", filename, |
||||||
|
" due to error(fdopen): ", strerror(errno))); |
||||||
|
return error; |
||||||
|
} |
||||||
|
fseek(file, 0, SEEK_END); |
||||||
|
// Converting to size_t on the assumption that it will not fail.
|
||||||
|
contents_size = static_cast<size_t>(ftell(file)); |
||||||
|
fseek(file, 0, SEEK_SET); |
||||||
|
contents = static_cast<unsigned char*>( |
||||||
|
gpr_malloc(contents_size + (add_null_terminator ? 1 : 0))); |
||||||
|
bytes_read = fread(contents, 1, contents_size, file); |
||||||
|
if (bytes_read < contents_size) { |
||||||
|
gpr_free(contents); |
||||||
|
GPR_ASSERT(ferror(file)); |
||||||
|
error = absl::InternalError( |
||||||
|
absl::StrCat("Failed to load file: ", filename, |
||||||
|
" due to error(fread): ", strerror(errno))); |
||||||
|
return error; |
||||||
|
} |
||||||
|
if (add_null_terminator) { |
||||||
|
contents[contents_size++] = 0; |
||||||
|
} |
||||||
|
return Slice(grpc_slice_new(contents, contents_size, gpr_free)); |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace grpc_core
|
@ -0,0 +1,33 @@ |
|||||||
|
// Copyright 2022 gRPC authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#ifndef GRPC_CORE_LIB_GPRPP_LOAD_FILE_H |
||||||
|
#define GRPC_CORE_LIB_GPRPP_LOAD_FILE_H |
||||||
|
|
||||||
|
#include <grpc/support/port_platform.h> |
||||||
|
|
||||||
|
#include <string> |
||||||
|
|
||||||
|
#include "absl/status/statusor.h" |
||||||
|
|
||||||
|
#include "src/core/lib/slice/slice.h" |
||||||
|
|
||||||
|
namespace grpc_core { |
||||||
|
|
||||||
|
// Loads the content of a file into a slice. add_null_terminator will add a NULL
|
||||||
|
// terminator if true.
|
||||||
|
absl::StatusOr<Slice> LoadFile(std::string filename, bool add_null_terminator); |
||||||
|
} // namespace grpc_core
|
||||||
|
|
||||||
|
#endif // GRPC_CORE_LIB_GPRPP_LOAD_FILE_H
|
@ -0,0 +1,132 @@ |
|||||||
|
// Copyright 2022 gRPC authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "src/core/lib/gprpp/load_file.h" |
||||||
|
|
||||||
|
#include <stdio.h> |
||||||
|
#include <string.h> |
||||||
|
|
||||||
|
#include <cstdint> |
||||||
|
|
||||||
|
#include "gtest/gtest.h" |
||||||
|
|
||||||
|
#include <grpc/support/alloc.h> |
||||||
|
|
||||||
|
#include "src/core/lib/gpr/tmpfile.h" |
||||||
|
#include "test/core/util/test_config.h" |
||||||
|
|
||||||
|
static const char prefix[] = "file_test"; |
||||||
|
|
||||||
|
TEST(LoadFileTest, TestLoadEmptyFile) { |
||||||
|
FILE* tmp = nullptr; |
||||||
|
absl::StatusOr<grpc_core::Slice> result; |
||||||
|
char* tmp_name; |
||||||
|
|
||||||
|
tmp = gpr_tmpfile(prefix, &tmp_name); |
||||||
|
ASSERT_NE(tmp_name, nullptr); |
||||||
|
ASSERT_NE(tmp, nullptr); |
||||||
|
fclose(tmp); |
||||||
|
|
||||||
|
result = grpc_core::LoadFile(tmp_name, false); |
||||||
|
ASSERT_TRUE(result.ok()); |
||||||
|
ASSERT_EQ(result->length(), 0); |
||||||
|
|
||||||
|
result = grpc_core::LoadFile(tmp_name, true); |
||||||
|
ASSERT_TRUE(result.ok()); |
||||||
|
ASSERT_EQ(result->length(), 1); |
||||||
|
ASSERT_EQ(result->begin()[0], 0); |
||||||
|
|
||||||
|
remove(tmp_name); |
||||||
|
gpr_free(tmp_name); |
||||||
|
} |
||||||
|
|
||||||
|
TEST(LoadFileTest, TestLoadFailure) { |
||||||
|
FILE* tmp = nullptr; |
||||||
|
absl::StatusOr<grpc_core::Slice> result; |
||||||
|
char* tmp_name; |
||||||
|
|
||||||
|
tmp = gpr_tmpfile(prefix, &tmp_name); |
||||||
|
ASSERT_NE(tmp_name, nullptr); |
||||||
|
ASSERT_NE(tmp, nullptr); |
||||||
|
fclose(tmp); |
||||||
|
remove(tmp_name); |
||||||
|
|
||||||
|
result = grpc_core::LoadFile(tmp_name, false); |
||||||
|
ASSERT_FALSE(result.ok()); |
||||||
|
|
||||||
|
gpr_free(tmp_name); |
||||||
|
} |
||||||
|
|
||||||
|
TEST(LoadFileTest, TestLoadSmallFile) { |
||||||
|
FILE* tmp = nullptr; |
||||||
|
absl::StatusOr<grpc_core::Slice> result; |
||||||
|
char* tmp_name; |
||||||
|
const char* blah = "blah"; |
||||||
|
|
||||||
|
tmp = gpr_tmpfile(prefix, &tmp_name); |
||||||
|
ASSERT_NE(tmp_name, nullptr); |
||||||
|
ASSERT_NE(tmp, nullptr); |
||||||
|
ASSERT_EQ(fwrite(blah, 1, strlen(blah), tmp), strlen(blah)); |
||||||
|
fclose(tmp); |
||||||
|
|
||||||
|
result = grpc_core::LoadFile(tmp_name, false); |
||||||
|
ASSERT_TRUE(result.ok()); |
||||||
|
ASSERT_EQ(result->length(), strlen(blah)); |
||||||
|
ASSERT_FALSE(memcmp(result->begin(), blah, strlen(blah))); |
||||||
|
|
||||||
|
result = grpc_core::LoadFile(tmp_name, true); |
||||||
|
ASSERT_TRUE(result.ok()); |
||||||
|
ASSERT_EQ(result->length(), strlen(blah) + 1); |
||||||
|
ASSERT_STREQ(reinterpret_cast<const char*>(result->begin()), blah); |
||||||
|
|
||||||
|
remove(tmp_name); |
||||||
|
gpr_free(tmp_name); |
||||||
|
} |
||||||
|
|
||||||
|
TEST(LoadFileTest, TestLoadBigFile) { |
||||||
|
FILE* tmp = nullptr; |
||||||
|
absl::StatusOr<grpc_core::Slice> result; |
||||||
|
char* tmp_name; |
||||||
|
static const size_t buffer_size = 124631; |
||||||
|
unsigned char* buffer = static_cast<unsigned char*>(gpr_malloc(buffer_size)); |
||||||
|
const uint8_t* current; |
||||||
|
size_t i; |
||||||
|
|
||||||
|
memset(buffer, 42, buffer_size); |
||||||
|
|
||||||
|
tmp = gpr_tmpfile(prefix, &tmp_name); |
||||||
|
ASSERT_NE(tmp, nullptr); |
||||||
|
ASSERT_NE(tmp_name, nullptr); |
||||||
|
ASSERT_EQ(fwrite(buffer, 1, buffer_size, tmp), buffer_size); |
||||||
|
fclose(tmp); |
||||||
|
|
||||||
|
result = grpc_core::LoadFile(tmp_name, false); |
||||||
|
ASSERT_TRUE(result.ok()); |
||||||
|
ASSERT_EQ(result->length(), buffer_size); |
||||||
|
current = result->begin(); |
||||||
|
for (i = 0; i < buffer_size; i++) { |
||||||
|
ASSERT_EQ(current[i], 42); |
||||||
|
} |
||||||
|
|
||||||
|
remove(tmp_name); |
||||||
|
gpr_free(tmp_name); |
||||||
|
gpr_free(buffer); |
||||||
|
} |
||||||
|
|
||||||
|
int main(int argc, char** argv) { |
||||||
|
grpc::testing::TestEnvironment env(&argc, argv); |
||||||
|
::testing::InitGoogleTest(&argc, argv); |
||||||
|
grpc::testing::TestGrpcScope grpc_scope; |
||||||
|
return RUN_ALL_TESTS(); |
||||||
|
} |
Loading…
Reference in new issue