mirror of
https://github.com/google/sandboxed-api.git
synced 2024-03-22 13:11:30 +08:00
Merge branch 'master' into gdal_sandbox
This commit is contained in:
commit
2e3b118ec9
12
.gitmodules
vendored
12
.gitmodules
vendored
|
@ -1,12 +1,18 @@
|
|||
[submodule "oss-internship-2020/sapi_lodepng/lodepng"]
|
||||
path = oss-internship-2020/lodepng/lodepng
|
||||
url = https://github.com/lvandeve/lodepng
|
||||
[submodule "oss-internship-2020/jsonnet/jsonnet"]
|
||||
path = oss-internship-2020/jsonnet/jsonnet
|
||||
url = https://github.com/google/jsonnet.git
|
||||
[submodule "oss-internship-2020/openjpeg/openjpeg"]
|
||||
path = oss-internship-2020/openjpeg/openjpeg
|
||||
url = https://github.com/uclouvain/openjpeg.git
|
||||
[submodule "oss-internship-2020/pffft/master"]
|
||||
path = oss-internship-2020/pffft/master
|
||||
url = https://bitbucket.org/jpommier/pffft/src/master/
|
||||
[submodule "oss-internship-2020/curl/curl_wrapper/curl"]
|
||||
path = oss-internship-2020/curl/curl_wrapper/curl
|
||||
url = https://github.com/curl/curl
|
||||
[submodule "oss-internship-2020/gdal/gdal"]
|
||||
path = oss-internship-2020/gdal/gdal
|
||||
url = https://github.com/OSGeo/gdal/
|
||||
[submodule "oss-internship-2020/curl/curl_wrapper/curl"]
|
||||
path = oss-internship-2020/curl/curl_wrapper/curl
|
||||
url = git@github.com:curl/curl.git
|
||||
|
|
|
@ -12,15 +12,15 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
cmake_minimum_required(VERSION 3.12)
|
||||
|
||||
project(libcurl_sandbox)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED True)
|
||||
|
||||
option(CURL_SAPI_ENABLE_EXAMPLES "" ON)
|
||||
option(CURL_SAPI_ENABLE_TESTS "" ON)
|
||||
option(SAPI_CURL_ENABLE_EXAMPLES "" ON)
|
||||
option(SAPI_CURL_ENABLE_TESTS "" ON)
|
||||
|
||||
# Add callbacks used by examples and tests
|
||||
if (CURL_SAPI_ENABLE_EXAMPLES OR CURL_SAPI_ENABLE_TESTS)
|
||||
|
@ -35,8 +35,8 @@ add_subdirectory(curl_wrapper)
|
|||
|
||||
# Setup Sandboxed API
|
||||
set(SAPI_ROOT "" CACHE PATH "Path to the Sandboxed API source tree")
|
||||
set(SAPI_ENABLE_EXAMPLES ${CURL_SAPI_ENABLE_EXAMPLES} CACHE BOOL "" FORCE)
|
||||
set(SAPI_ENABLE_TESTS ${CURL_SAPI_ENABLE_TESTS} CACHE BOOL "" FORCE)
|
||||
set(SAPI_ENABLE_EXAMPLES ${SAPI_CURL_ENABLE_EXAMPLES} CACHE BOOL "" FORCE)
|
||||
set(SAPI_ENABLE_TESTS ${SAPI_CURL_ENABLE_TESTS} CACHE BOOL "" FORCE)
|
||||
add_subdirectory(
|
||||
"${SAPI_ROOT}"
|
||||
"${CMAKE_BINARY_DIR}/sandboxed-api-build"
|
||||
|
@ -125,7 +125,7 @@ add_sapi_library(curl_sapi
|
|||
|
||||
LIBRARY_NAME Curl
|
||||
|
||||
NAMESPACE ""
|
||||
NAMESPACE curl
|
||||
)
|
||||
|
||||
# Include generated SAPI header
|
||||
|
@ -134,11 +134,11 @@ target_include_directories(curl_sapi INTERFACE
|
|||
)
|
||||
|
||||
# Add examples
|
||||
if (CURL_SAPI_ENABLE_EXAMPLES)
|
||||
if (SAPI_CURL_ENABLE_EXAMPLES)
|
||||
add_subdirectory(examples)
|
||||
endif()
|
||||
|
||||
# Add tests
|
||||
if (CURL_SAPI_ENABLE_TESTS)
|
||||
if (SAPI_CURL_ENABLE_TESTS)
|
||||
add_subdirectory(tests)
|
||||
endif()
|
||||
|
|
|
@ -38,12 +38,15 @@ Variadic methods are currently not supported by Sandboxed API. To solve this,
|
|||
these methods are defined with an additional explicit parameter in
|
||||
`custom_curl.h`.
|
||||
|
||||
The methods are: - `curl_easy_setopt`. Use `curl_easy_setopt_ptr`,
|
||||
`curl_easy_setopt_long` or `curl_easy_setopt_curl_off_t` instead. -
|
||||
`curl_easy_getinfo`. Use `curl_easy_getinfo_ptr` instead. - `curl_multi_setopt`.
|
||||
Use `curl_multi_setopt_ptr`, `curl_multi_setopt_long` or
|
||||
`curl_multi_setopt_curl_off_t` instead. - `curl_share_setopt`. Use
|
||||
`curl_share_setopt_ptr` or `curl_share_setopt_long` instead
|
||||
The methods are:
|
||||
|
||||
- `curl_easy_setopt`. Use `curl_easy_setopt_ptr`, `curl_easy_setopt_long` or
|
||||
`curl_easy_setopt_curl_off_t` instead.
|
||||
- `curl_easy_getinfo`. Use `curl_easy_getinfo_ptr` instead.
|
||||
- `curl_multi_setopt`. Use `curl_multi_setopt_ptr`, `curl_multi_setopt_long`
|
||||
or `curl_multi_setopt_curl_off_t` instead.
|
||||
- `curl_share_setopt`. Use `curl_share_setopt_ptr` or `curl_share_setopt_long`
|
||||
instead
|
||||
|
||||
#### Methods with incomplete array arguments
|
||||
|
||||
|
@ -51,8 +54,10 @@ Incomplete array arguments are currently not supported by Sandboxed API. To
|
|||
solve this, methods taking an incomplete array argument have a wrapper in
|
||||
`custom_curl.h`, and take a pointer as the argument.
|
||||
|
||||
The methods are: - `curl_multi_poll`. Use `curl_multi_poll_sapi` instead. -
|
||||
`curl_multi_wait`. Use `curl_multi_wait_sapi` instead.
|
||||
The methods are:
|
||||
|
||||
- `curl_multi_poll`. Use `curl_multi_poll_sapi` instead.
|
||||
- `curl_multi_wait`. Use `curl_multi_wait_sapi` instead.
|
||||
|
||||
#### Methods with conflicts on the generated header
|
||||
|
||||
|
@ -60,11 +65,15 @@ Some methods create conflicts on the generated header because of redefined
|
|||
`#define` directives from files included by the header. To solve this, the
|
||||
conflicting types and methods are redefined in `custom_curl.h`.
|
||||
|
||||
The types are: - `time_t`. Use `time_t_sapi` instead. - `fd_set`. Use
|
||||
`fd_set_sapi` instead.
|
||||
The types are:
|
||||
|
||||
The methods are: - `curl_getdate`. Use `curl_getdate_sapi` instead. -
|
||||
`curl_multi_fdset`. Use `curl_multi_fdset_sapi` instead.
|
||||
- `time_t`. Use `time_t_sapi` instead.
|
||||
- `fd_set`. Use `fd_set_sapi` instead.
|
||||
|
||||
The methods are:
|
||||
|
||||
- `curl_getdate`. Use `curl_getdate_sapi` instead.
|
||||
- `curl_multi_fdset`. Use `curl_multi_fdset_sapi` instead.
|
||||
|
||||
#### Function pointers
|
||||
|
||||
|
|
|
@ -12,8 +12,8 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef TESTS_CALLBACKS_H
|
||||
#define TESTS_CALLBACKS_H
|
||||
#ifndef CALLBACKS_H_
|
||||
#define CALLBACKS_H_
|
||||
|
||||
#include <curl/curl.h>
|
||||
|
||||
|
@ -21,4 +21,4 @@
|
|||
extern "C" size_t WriteToMemory(char* contents, size_t size, size_t num_bytes,
|
||||
void* userp);
|
||||
|
||||
#endif // TESTS_CALLBACKS_H
|
||||
#endif // CALLBACKS_H_
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
Subproject commit cbe7fad20d969626a5c4eb0501a273dfe812bcd3
|
|
@ -14,8 +14,8 @@
|
|||
|
||||
// Wrapper for curl library
|
||||
|
||||
#ifndef CURL_WRAPPER_H
|
||||
#define CURL_WRAPPER_H
|
||||
#ifndef CURL_WRAPPER_H_
|
||||
#define CURL_WRAPPER_H_
|
||||
|
||||
#include <curl/curl.h>
|
||||
|
||||
|
@ -77,6 +77,7 @@ CURLSHcode curl_share_setopt_ptr(CURLSH* handle, CURLSHoption option,
|
|||
// The wrapper method is needed to make the variadic argument explicit
|
||||
CURLSHcode curl_share_setopt_long(CURLSH* handle, CURLSHoption option,
|
||||
long parameter);
|
||||
}
|
||||
|
||||
#endif // CURL_WRAPPER_H
|
||||
} // extern "C"
|
||||
|
||||
#endif // CURL_WRAPPER_H_
|
||||
|
|
|
@ -19,59 +19,67 @@
|
|||
|
||||
#include "../sandbox.h" // NOLINT(build/include)
|
||||
|
||||
namespace {
|
||||
|
||||
absl::Status Example1() {
|
||||
// Initialize sandbox2 and sapi
|
||||
curl::CurlSapiSandbox sandbox;
|
||||
SAPI_RETURN_IF_ERROR(sandbox.Init());
|
||||
curl::CurlApi api(&sandbox);
|
||||
|
||||
// Initialize the curl session
|
||||
curl::CURL* curl_handle;
|
||||
SAPI_ASSIGN_OR_RETURN(curl_handle, api.curl_easy_init());
|
||||
sapi::v::RemotePtr curl(curl_handle);
|
||||
if (!curl_handle) {
|
||||
return absl::UnavailableError("curl_easy_init failed: curl is NULL");
|
||||
}
|
||||
|
||||
int curl_code;
|
||||
|
||||
// Specify URL to get
|
||||
sapi::v::ConstCStr url("http://example.com");
|
||||
SAPI_ASSIGN_OR_RETURN(curl_code, api.curl_easy_setopt_ptr(&curl, curl::CURLOPT_URL,
|
||||
url.PtrBefore()));
|
||||
if (curl_code != 0) {
|
||||
return absl::UnavailableError("curl_easy_setopt_ptr failed: " + curl_code);
|
||||
}
|
||||
|
||||
// Set the library to follow a redirection
|
||||
SAPI_ASSIGN_OR_RETURN(curl_code, api.curl_easy_setopt_long(
|
||||
&curl, curl::CURLOPT_FOLLOWLOCATION, 1l));
|
||||
if (curl_code != 0) {
|
||||
return absl::UnavailableError("curl_easy_setopt_long failed: " + curl_code);
|
||||
}
|
||||
|
||||
// Disable authentication of peer certificate
|
||||
SAPI_ASSIGN_OR_RETURN(curl_code, api.curl_easy_setopt_long(
|
||||
&curl, curl::CURLOPT_SSL_VERIFYPEER, 0l));
|
||||
if (curl_code != 0) {
|
||||
return absl::UnavailableError("curl_easy_setopt_long failed: " + curl_code);
|
||||
}
|
||||
|
||||
// Perform the request
|
||||
SAPI_ASSIGN_OR_RETURN(curl_code, api.curl_easy_perform(&curl));
|
||||
if (curl_code != 0) {
|
||||
return absl::UnavailableError("curl_easy_perform failed: " + curl_code);
|
||||
}
|
||||
|
||||
// Cleanup curl
|
||||
SAPI_RETURN_IF_ERROR(api.curl_easy_cleanup(&curl));
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
gflags::ParseCommandLineFlags(&argc, &argv, true);
|
||||
google::InitGoogleLogging(argv[0]);
|
||||
|
||||
absl::Status status;
|
||||
|
||||
// Initialize sandbox2 and sapi
|
||||
CurlSapiSandbox sandbox;
|
||||
status = sandbox.Init();
|
||||
if (!status.ok()) {
|
||||
LOG(FATAL) << "Couldn't initialize Sandboxed API: " << status;
|
||||
}
|
||||
CurlApi api(&sandbox);
|
||||
|
||||
// Initialize the curl session
|
||||
absl::StatusOr<CURL*> curl_handle = api.curl_easy_init();
|
||||
if (!curl_handle.ok()) {
|
||||
LOG(FATAL) << "curl_easy_init failed: " << curl_handle.status();
|
||||
}
|
||||
sapi::v::RemotePtr curl(curl_handle.value());
|
||||
if (!curl.GetValue()) LOG(FATAL) << "curl_easy_init failed: curl is NULL";
|
||||
|
||||
absl::StatusOr<int> curl_code;
|
||||
|
||||
// Specify URL to get
|
||||
sapi::v::ConstCStr url("http://example.com");
|
||||
curl_code = api.curl_easy_setopt_ptr(&curl, CURLOPT_URL, url.PtrBefore());
|
||||
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_easy_setopt_ptr failed: " << curl_code.status();
|
||||
}
|
||||
|
||||
// Set the library to follow a redirection
|
||||
curl_code = api.curl_easy_setopt_long(&curl, CURLOPT_FOLLOWLOCATION, 1l);
|
||||
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_easy_setopt_long failed: " << curl_code.status();
|
||||
}
|
||||
|
||||
// Disable authentication of peer certificate
|
||||
curl_code = api.curl_easy_setopt_long(&curl, CURLOPT_SSL_VERIFYPEER, 0l);
|
||||
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_easy_setopt_long failed: " << curl_code.status();
|
||||
}
|
||||
|
||||
// Perform the request
|
||||
curl_code = api.curl_easy_perform(&curl);
|
||||
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_easy_perform failed: " << curl_code.status();
|
||||
}
|
||||
|
||||
// Cleanup curl
|
||||
status = api.curl_easy_cleanup(&curl);
|
||||
if (!status.ok()) {
|
||||
LOG(FATAL) << "curl_easy_cleanup failed: " << status;
|
||||
if (absl::Status status = Example1(); !status.ok()) {
|
||||
LOG(ERROR) << "Example1 failed: " << status.ToString();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
|
|
|
@ -20,87 +20,89 @@
|
|||
|
||||
#include "../sandbox.h" // NOLINT(build/include)
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
gflags::ParseCommandLineFlags(&argc, &argv, true);
|
||||
google::InitGoogleLogging(argv[0]);
|
||||
|
||||
absl::Status status;
|
||||
namespace {
|
||||
|
||||
absl::Status Example2() {
|
||||
// Initialize sandbox2 and sapi
|
||||
CurlSapiSandbox sandbox;
|
||||
status = sandbox.Init();
|
||||
if (!status.ok()) {
|
||||
LOG(FATAL) << "Couldn't initialize Sandboxed API: " << status;
|
||||
}
|
||||
CurlApi api(&sandbox);
|
||||
curl::CurlSapiSandbox sandbox;
|
||||
SAPI_RETURN_IF_ERROR(sandbox.Init());
|
||||
curl::CurlApi api(&sandbox);
|
||||
|
||||
// Generate pointer to WriteMemoryCallback function
|
||||
void* function_ptr;
|
||||
status = sandbox.rpc_channel()->Symbol("WriteToMemory", &function_ptr);
|
||||
if (!status.ok()) {
|
||||
LOG(FATAL) << "sapi::Sandbox::rpc_channel().Symbol failed: " << status;
|
||||
}
|
||||
sapi::v::RemotePtr remote_function_ptr(function_ptr);
|
||||
SAPI_RETURN_IF_ERROR(
|
||||
sandbox.rpc_channel()->Symbol("WriteToMemory", &function_ptr));
|
||||
sapi::v::RemotePtr write_to_memory(function_ptr);
|
||||
|
||||
// Initialize the curl session
|
||||
absl::StatusOr<CURL*> curl_handle = api.curl_easy_init();
|
||||
if (!curl_handle.ok()) {
|
||||
LOG(FATAL) << "curl_easy_init failed: " << curl_handle.status();
|
||||
}
|
||||
sapi::v::RemotePtr curl(curl_handle.value());
|
||||
if (!curl.GetValue()) {
|
||||
LOG(FATAL) << "curl_easy_init failed: curl is NULL";
|
||||
curl::CURL* curl_handle;
|
||||
SAPI_ASSIGN_OR_RETURN(curl_handle, api.curl_easy_init());
|
||||
sapi::v::RemotePtr curl(curl_handle);
|
||||
if (!curl_handle) {
|
||||
return absl::UnavailableError("curl_easy_init failed: curl is NULL");
|
||||
}
|
||||
|
||||
absl::StatusOr<int> curl_code;
|
||||
int curl_code;
|
||||
|
||||
// Specify URL to get
|
||||
sapi::v::ConstCStr url("http://example.com");
|
||||
curl_code = api.curl_easy_setopt_ptr(&curl, CURLOPT_URL, url.PtrBefore());
|
||||
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_easy_setopt_ptr failed: " << curl_code.status();
|
||||
SAPI_ASSIGN_OR_RETURN(curl_code, api.curl_easy_setopt_ptr(&curl, curl::CURLOPT_URL,
|
||||
url.PtrBefore()));
|
||||
if (curl_code != 0) {
|
||||
return absl::UnavailableError("curl_easy_setopt_ptr failed: " + curl_code);
|
||||
}
|
||||
|
||||
// Set WriteMemoryCallback as the write function
|
||||
curl_code = api.curl_easy_setopt_ptr(&curl, CURLOPT_WRITEFUNCTION,
|
||||
&remote_function_ptr);
|
||||
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_easy_setopt_ptr failed: " << curl_code.status();
|
||||
SAPI_ASSIGN_OR_RETURN(curl_code,
|
||||
api.curl_easy_setopt_ptr(&curl, curl::CURLOPT_WRITEFUNCTION,
|
||||
&write_to_memory));
|
||||
if (curl_code != 0) {
|
||||
return absl::UnavailableError("curl_easy_setopt_ptr failed: " + curl_code);
|
||||
}
|
||||
|
||||
// Pass 'chunk' struct to the callback function
|
||||
sapi::v::LenVal chunk(0);
|
||||
curl_code =
|
||||
api.curl_easy_setopt_ptr(&curl, CURLOPT_WRITEDATA, chunk.PtrBoth());
|
||||
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_easy_setopt_ptr failed: " << curl_code.status();
|
||||
SAPI_ASSIGN_OR_RETURN(curl_code,
|
||||
api.curl_easy_setopt_ptr(&curl, curl::CURLOPT_WRITEDATA,
|
||||
chunk.PtrBoth()));
|
||||
if (curl_code != 0) {
|
||||
return absl::UnavailableError("curl_easy_setopt_ptr failed: " + curl_code);
|
||||
}
|
||||
|
||||
// Set a user agent
|
||||
sapi::v::ConstCStr user_agent("libcurl-agent/1.0");
|
||||
curl_code = api.curl_easy_setopt_ptr(&curl, CURLOPT_USERAGENT,
|
||||
user_agent.PtrBefore());
|
||||
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_easy_setopt_ptr failed: " << curl_code.status();
|
||||
SAPI_ASSIGN_OR_RETURN(curl_code,
|
||||
api.curl_easy_setopt_ptr(&curl, curl::CURLOPT_USERAGENT,
|
||||
user_agent.PtrBefore()));
|
||||
if (curl_code != 0) {
|
||||
return absl::UnavailableError("curl_easy_setopt_ptr failed: " + curl_code);
|
||||
}
|
||||
|
||||
// Perform the request
|
||||
curl_code = api.curl_easy_perform(&curl);
|
||||
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_easy_perform failed: " << curl_code.status();
|
||||
SAPI_ASSIGN_OR_RETURN(curl_code, api.curl_easy_perform(&curl));
|
||||
if (curl_code != 0) {
|
||||
return absl::UnavailableError("curl_easy_perform failed: " + curl_code);
|
||||
}
|
||||
|
||||
// Retrieve memory size
|
||||
status = sandbox.TransferFromSandboxee(&chunk);
|
||||
if (!status.ok()) {
|
||||
LOG(FATAL) << "sandbox.TransferFromSandboxee failed: " << status;
|
||||
}
|
||||
SAPI_RETURN_IF_ERROR(sandbox.TransferFromSandboxee(&chunk));
|
||||
std::cout << "memory size: " << chunk.GetDataSize() << " bytes" << std::endl;
|
||||
|
||||
// Cleanup curl
|
||||
status = api.curl_easy_cleanup(&curl);
|
||||
if (!status.ok()) {
|
||||
LOG(FATAL) << "curl_easy_cleanup failed: " << status;
|
||||
SAPI_RETURN_IF_ERROR(api.curl_easy_cleanup(&curl));
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
gflags::ParseCommandLineFlags(&argc, &argv, true);
|
||||
google::InitGoogleLogging(argv[0]);
|
||||
|
||||
if (absl::Status status = Example2(); !status.ok()) {
|
||||
LOG(ERROR) << "Example2 failed: " << status.ToString();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
|
|
|
@ -19,7 +19,9 @@
|
|||
|
||||
#include "../sandbox.h" // NOLINT(build/include)
|
||||
|
||||
class CurlSapiSandboxEx3 : public CurlSapiSandbox {
|
||||
namespace {
|
||||
|
||||
class CurlSapiSandboxEx3 : public curl::CurlSapiSandbox {
|
||||
public:
|
||||
CurlSapiSandboxEx3(std::string ssl_certificate, std::string ssl_key,
|
||||
std::string ca_certificates)
|
||||
|
@ -42,7 +44,7 @@ class CurlSapiSandboxEx3 : public CurlSapiSandbox {
|
|||
.AddFile(ssl_key)
|
||||
.AddFile(ca_certificates);
|
||||
// Provide the new PolicyBuilder to ModifyPolicy in CurlSandbox
|
||||
return CurlSapiSandbox::ModifyPolicy(policy_builder.get());
|
||||
return curl::CurlSapiSandbox::ModifyPolicy(policy_builder.get());
|
||||
}
|
||||
|
||||
std::string ssl_certificate;
|
||||
|
@ -50,116 +52,121 @@ class CurlSapiSandboxEx3 : public CurlSapiSandbox {
|
|||
std::string ca_certificates;
|
||||
};
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
gflags::ParseCommandLineFlags(&argc, &argv, true);
|
||||
google::InitGoogleLogging(argv[0]);
|
||||
|
||||
absl::Status status;
|
||||
|
||||
// Get input parameters (should be absolute paths)
|
||||
if (argc != 5) {
|
||||
LOG(FATAL) << "wrong number of arguments (4 expected)";
|
||||
}
|
||||
std::string ssl_certificate = argv[1];
|
||||
std::string ssl_key = argv[2];
|
||||
std::string ssl_key_password = argv[3];
|
||||
std::string ca_certificates = argv[4];
|
||||
|
||||
absl::Status Example3(std::string ssl_certificate, std::string ssl_key,
|
||||
std::string ssl_key_password,
|
||||
std::string ca_certificates) {
|
||||
// Initialize sandbox2 and sapi
|
||||
CurlSapiSandboxEx3 sandbox(ssl_certificate, ssl_key, ca_certificates);
|
||||
status = sandbox.Init();
|
||||
if (!status.ok()) {
|
||||
LOG(FATAL) << "Couldn't initialize Sandboxed API: " << status;
|
||||
}
|
||||
CurlApi api(&sandbox);
|
||||
SAPI_RETURN_IF_ERROR(sandbox.Init());
|
||||
curl::CurlApi api(&sandbox);
|
||||
|
||||
absl::StatusOr<int> curl_code;
|
||||
int curl_code;
|
||||
|
||||
// Initialize curl (CURL_GLOBAL_DEFAULT = 3)
|
||||
curl_code = api.curl_global_init(3l);
|
||||
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_global_init failed: " << curl_code.status();
|
||||
SAPI_ASSIGN_OR_RETURN(curl_code, api.curl_global_init(3l));
|
||||
if (curl_code != 0) {
|
||||
return absl::UnavailableError("curl_global_init failed: " + curl_code);
|
||||
}
|
||||
|
||||
// Initialize curl easy handle
|
||||
absl::StatusOr<CURL*> curl_handle = api.curl_easy_init();
|
||||
if (!curl_handle.ok()) {
|
||||
LOG(FATAL) << "curl_easy_init failed: " << curl_handle.status();
|
||||
}
|
||||
sapi::v::RemotePtr curl(curl_handle.value());
|
||||
if (!curl.GetValue()) {
|
||||
LOG(FATAL) << "curl_easy_init failed: curl is NULL";
|
||||
curl::CURL* curl_handle;
|
||||
SAPI_ASSIGN_OR_RETURN(curl_handle, api.curl_easy_init());
|
||||
sapi::v::RemotePtr curl(curl_handle);
|
||||
if (!curl_handle) {
|
||||
return absl::UnavailableError("curl_easy_init failed: curl is NULL");
|
||||
}
|
||||
|
||||
// Specify URL to get (using HTTPS)
|
||||
sapi::v::ConstCStr url("https://example.com");
|
||||
curl_code = api.curl_easy_setopt_ptr(&curl, CURLOPT_URL, url.PtrBefore());
|
||||
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_easy_setopt_ptr failed: " << curl_code.status();
|
||||
SAPI_ASSIGN_OR_RETURN(curl_code, api.curl_easy_setopt_ptr(&curl, curl::CURLOPT_URL,
|
||||
url.PtrBefore()));
|
||||
if (curl_code != 0) {
|
||||
return absl::UnavailableError("curl_easy_setopt_ptr failed: " + curl_code);
|
||||
}
|
||||
|
||||
// Set the SSL certificate type to "PEM"
|
||||
sapi::v::ConstCStr ssl_cert_type("PEM");
|
||||
curl_code = api.curl_easy_setopt_ptr(&curl, CURLOPT_SSLCERTTYPE,
|
||||
ssl_cert_type.PtrBefore());
|
||||
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_easy_setopt_ptr failed: " << curl_code.status();
|
||||
SAPI_ASSIGN_OR_RETURN(curl_code,
|
||||
api.curl_easy_setopt_ptr(&curl, curl::CURLOPT_SSLCERTTYPE,
|
||||
ssl_cert_type.PtrBefore()));
|
||||
if (curl_code != 0) {
|
||||
return absl::UnavailableError("curl_easy_setopt_ptr failed: " + curl_code);
|
||||
}
|
||||
|
||||
// Set the certificate for client authentication
|
||||
sapi::v::ConstCStr sapi_ssl_certificate(ssl_certificate.c_str());
|
||||
curl_code = api.curl_easy_setopt_ptr(&curl, CURLOPT_SSLCERT,
|
||||
sapi_ssl_certificate.PtrBefore());
|
||||
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_easy_setopt_ptr failed: " << curl_code.status();
|
||||
SAPI_ASSIGN_OR_RETURN(curl_code,
|
||||
api.curl_easy_setopt_ptr(&curl, curl::CURLOPT_SSLCERT,
|
||||
sapi_ssl_certificate.PtrBefore()));
|
||||
if (curl_code != 0) {
|
||||
return absl::UnavailableError("curl_easy_setopt_ptr failed: " + curl_code);
|
||||
}
|
||||
|
||||
// Set the private key for client authentication
|
||||
sapi::v::ConstCStr sapi_ssl_key(ssl_key.c_str());
|
||||
curl_code =
|
||||
api.curl_easy_setopt_ptr(&curl, CURLOPT_SSLKEY, sapi_ssl_key.PtrBefore());
|
||||
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_easy_setopt_ptr failed: " << curl_code.status();
|
||||
SAPI_ASSIGN_OR_RETURN(curl_code,
|
||||
api.curl_easy_setopt_ptr(&curl, curl::CURLOPT_SSLKEY,
|
||||
sapi_ssl_key.PtrBefore()));
|
||||
if (curl_code != 0) {
|
||||
return absl::UnavailableError("curl_easy_setopt_ptr failed: " + curl_code);
|
||||
}
|
||||
|
||||
// Set the password used to protect the private key
|
||||
sapi::v::ConstCStr sapi_ssl_key_password(ssl_key_password.c_str());
|
||||
curl_code = api.curl_easy_setopt_ptr(&curl, CURLOPT_KEYPASSWD,
|
||||
sapi_ssl_key_password.PtrBefore());
|
||||
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_easy_setopt_ptr failed: " << curl_code.status();
|
||||
SAPI_ASSIGN_OR_RETURN(curl_code,
|
||||
api.curl_easy_setopt_ptr(&curl, curl::CURLOPT_KEYPASSWD,
|
||||
sapi_ssl_key_password.PtrBefore()));
|
||||
if (curl_code != 0) {
|
||||
return absl::UnavailableError("curl_easy_setopt_ptr failed: " + curl_code);
|
||||
}
|
||||
|
||||
// Set the file with the certificates vaildating the server
|
||||
sapi::v::ConstCStr sapi_ca_certificates(ca_certificates.c_str());
|
||||
curl_code = api.curl_easy_setopt_ptr(&curl, CURLOPT_CAINFO,
|
||||
sapi_ca_certificates.PtrBefore());
|
||||
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_easy_setopt_ptr failed: " << curl_code.status();
|
||||
SAPI_ASSIGN_OR_RETURN(curl_code,
|
||||
api.curl_easy_setopt_ptr(&curl, curl::CURLOPT_CAINFO,
|
||||
sapi_ca_certificates.PtrBefore()));
|
||||
if (curl_code != 0) {
|
||||
return absl::UnavailableError("curl_easy_setopt_ptr failed: " + curl_code);
|
||||
}
|
||||
|
||||
// Verify the authenticity of the server
|
||||
curl_code = api.curl_easy_setopt_long(&curl, CURLOPT_SSL_VERIFYPEER, 1L);
|
||||
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_easy_setopt_long failed: " << curl_code.status();
|
||||
SAPI_ASSIGN_OR_RETURN(curl_code, api.curl_easy_setopt_long(
|
||||
&curl, curl::CURLOPT_SSL_VERIFYPEER, 1L));
|
||||
if (curl_code != 0) {
|
||||
return absl::UnavailableError("curl_easy_setopt_long failed: " + curl_code);
|
||||
}
|
||||
|
||||
// Perform the request
|
||||
curl_code = api.curl_easy_perform(&curl);
|
||||
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_easy_perform failed: " << curl_code.status();
|
||||
SAPI_ASSIGN_OR_RETURN(curl_code, api.curl_easy_perform(&curl));
|
||||
if (curl_code != 0) {
|
||||
return absl::UnavailableError("curl_easy_perform failed: " + curl_code);
|
||||
}
|
||||
|
||||
// Cleanup curl easy handle
|
||||
status = api.curl_easy_cleanup(&curl);
|
||||
if (!status.ok()) {
|
||||
LOG(FATAL) << "curl_easy_cleanup failed: " << status;
|
||||
}
|
||||
SAPI_RETURN_IF_ERROR(api.curl_easy_cleanup(&curl));
|
||||
|
||||
// Cleanup curl
|
||||
status = api.curl_global_cleanup();
|
||||
if (!status.ok()) {
|
||||
LOG(FATAL) << "curl_global_cleanup failed: " << status;
|
||||
SAPI_RETURN_IF_ERROR(api.curl_global_cleanup());
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
gflags::ParseCommandLineFlags(&argc, &argv, true);
|
||||
google::InitGoogleLogging(argv[0]);
|
||||
|
||||
// Get input parameters (should be absolute paths)
|
||||
if (argc != 5) {
|
||||
LOG(ERROR) << "wrong number of arguments (4 expected)";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (absl::Status status = Example3(argv[1], argv[2], argv[3], argv[4]);
|
||||
!status.ok()) {
|
||||
LOG(ERROR) << "Example3 failed: " << status.ToString();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
|
|
|
@ -21,107 +21,113 @@
|
|||
#include "curl_sapi.sapi.h" // NOLINT(build/include)
|
||||
#include "sandboxed_api/util/flag.h"
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
gflags::ParseCommandLineFlags(&argc, &argv, true);
|
||||
google::InitGoogleLogging(argv[0]);
|
||||
|
||||
absl::Status status;
|
||||
namespace {
|
||||
|
||||
absl::Status Example4() {
|
||||
// Initialize sandbox2 and sapi
|
||||
CurlSapiSandbox sandbox;
|
||||
status = sandbox.Init();
|
||||
if (!status.ok()) {
|
||||
LOG(FATAL) << "Couldn't initialize Sandboxed API: " << status;
|
||||
}
|
||||
CurlApi api(&sandbox);
|
||||
curl::CurlSapiSandbox sandbox;
|
||||
SAPI_RETURN_IF_ERROR(sandbox.Init());
|
||||
curl::CurlApi api(&sandbox);
|
||||
|
||||
// Number of running handles
|
||||
sapi::v::Int still_running(1);
|
||||
|
||||
absl::StatusOr<int> curl_code;
|
||||
int curl_code;
|
||||
|
||||
// Initialize curl (CURL_GLOBAL_DEFAULT = 3)
|
||||
curl_code = api.curl_global_init(3l);
|
||||
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_global_init failed: " << curl_code.status();
|
||||
SAPI_ASSIGN_OR_RETURN(curl_code, api.curl_global_init(3l));
|
||||
if (curl_code != 0) {
|
||||
return absl::UnavailableError("curl_global_init failed: " + curl_code);
|
||||
}
|
||||
|
||||
// Initialize http_handle
|
||||
absl::StatusOr<CURL*> curl_handle = api.curl_easy_init();
|
||||
if (!curl_handle.ok()) {
|
||||
LOG(FATAL) << "curl_easy_init failed: " << curl_handle.status();
|
||||
}
|
||||
sapi::v::RemotePtr http_handle(curl_handle.value());
|
||||
if (!http_handle.GetValue()) {
|
||||
LOG(FATAL) << "curl_easy_init failed: http_handle is NULL";
|
||||
curl::CURL* curl_handle;
|
||||
SAPI_ASSIGN_OR_RETURN(curl_handle, api.curl_easy_init());
|
||||
sapi::v::RemotePtr http_handle(curl_handle);
|
||||
if (!curl_handle) {
|
||||
return absl::UnavailableError("curl_easy_init failed: curl is NULL");
|
||||
}
|
||||
|
||||
// Specify URL to get
|
||||
sapi::v::ConstCStr url("http://example.com");
|
||||
curl_code =
|
||||
api.curl_easy_setopt_ptr(&http_handle, CURLOPT_URL, url.PtrBefore());
|
||||
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_easy_setopt_ptr failed: " << curl_code.status();
|
||||
SAPI_ASSIGN_OR_RETURN(curl_code,
|
||||
api.curl_easy_setopt_ptr(&http_handle, curl::CURLOPT_URL,
|
||||
url.PtrBefore()));
|
||||
if (curl_code != 0) {
|
||||
return absl::UnavailableError("curl_easy_setopt_ptr failed: " + curl_code);
|
||||
}
|
||||
|
||||
// Initialize multi_handle
|
||||
absl::StatusOr<CURLM*> curlm_handle = api.curl_multi_init();
|
||||
if (!curlm_handle.ok()) {
|
||||
LOG(FATAL) << "curl_multi_init failed: " << curlm_handle.status();
|
||||
}
|
||||
sapi::v::RemotePtr multi_handle(curlm_handle.value());
|
||||
if (!multi_handle.GetValue()) {
|
||||
LOG(FATAL) << "curl_multi_init failed: multi_handle is NULL";
|
||||
curl::CURLM* curlm_handle;
|
||||
SAPI_ASSIGN_OR_RETURN(curlm_handle, api.curl_multi_init());
|
||||
sapi::v::RemotePtr multi_handle(curlm_handle);
|
||||
if (!curlm_handle) {
|
||||
return absl::UnavailableError(
|
||||
"curl_multi_init failed: multi_handle is NULL");
|
||||
}
|
||||
|
||||
// Add http_handle to the multi stack
|
||||
curl_code = api.curl_multi_add_handle(&multi_handle, &http_handle);
|
||||
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_multi_add_handle failed: " << curl_code.status();
|
||||
SAPI_ASSIGN_OR_RETURN(curl_code,
|
||||
api.curl_multi_add_handle(&multi_handle, &http_handle));
|
||||
if (curl_code != 0) {
|
||||
return absl::UnavailableError("curl_multi_add_handle failed: " + curl_code);
|
||||
}
|
||||
|
||||
while (still_running.GetValue()) {
|
||||
sapi::v::Int numfds(0);
|
||||
|
||||
// Perform the request
|
||||
curl_code = api.curl_multi_perform(&multi_handle, still_running.PtrBoth());
|
||||
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_mutli_perform failed: " << curl_code.status();
|
||||
SAPI_ASSIGN_OR_RETURN(curl_code, api.curl_multi_perform(
|
||||
&multi_handle, still_running.PtrBoth()));
|
||||
if (curl_code != 0) {
|
||||
return absl::UnavailableError("curl_mutli_perform failed: " + curl_code);
|
||||
}
|
||||
|
||||
if (still_running.GetValue()) {
|
||||
// Wait for an event or timeout
|
||||
sapi::v::NullPtr null_ptr;
|
||||
curl_code = api.curl_multi_poll_sapi(&multi_handle, &null_ptr, 0, 1000,
|
||||
numfds.PtrBoth());
|
||||
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_multi_poll_sapi failed: " << curl_code.status();
|
||||
SAPI_ASSIGN_OR_RETURN(
|
||||
curl_code, api.curl_multi_poll_sapi(&multi_handle, &null_ptr, 0, 1000,
|
||||
numfds.PtrBoth()));
|
||||
if (curl_code != 0) {
|
||||
return absl::UnavailableError("curl_multi_poll_sapi failed: " +
|
||||
curl_code);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove http_handle from the multi stack
|
||||
curl_code = api.curl_multi_remove_handle(&multi_handle, &http_handle);
|
||||
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_multi_remove_handle failed: " << curl_code.status();
|
||||
SAPI_ASSIGN_OR_RETURN(curl_code,
|
||||
api.curl_multi_remove_handle(&multi_handle, &http_handle));
|
||||
if (curl_code != 0) {
|
||||
return absl::UnavailableError("curl_multi_remove_handle failed: " +
|
||||
curl_code);
|
||||
}
|
||||
|
||||
// Cleanup http_handle
|
||||
status = api.curl_easy_cleanup(&http_handle);
|
||||
if (!status.ok()) {
|
||||
LOG(FATAL) << "curl_easy_cleanup failed: " << status;
|
||||
}
|
||||
SAPI_RETURN_IF_ERROR(api.curl_easy_cleanup(&http_handle));
|
||||
|
||||
// Cleanup multi_handle
|
||||
curl_code = api.curl_multi_cleanup(&multi_handle);
|
||||
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_multi_cleanup failed: " << curl_code.status();
|
||||
SAPI_ASSIGN_OR_RETURN(curl_code, api.curl_multi_cleanup(&multi_handle));
|
||||
if (curl_code != 0) {
|
||||
return absl::UnavailableError("curl_multi_cleanup failed: " + curl_code);
|
||||
}
|
||||
|
||||
// Cleanup curl
|
||||
status = api.curl_global_cleanup();
|
||||
if (!status.ok()) {
|
||||
LOG(FATAL) << "curl_global_cleanup failed: " << status;
|
||||
SAPI_RETURN_IF_ERROR(api.curl_global_cleanup());
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
gflags::ParseCommandLineFlags(&argc, &argv, true);
|
||||
google::InitGoogleLogging(argv[0]);
|
||||
|
||||
if (absl::Status status = Example4(); !status.ok()) {
|
||||
LOG(ERROR) << "Example4 failed: " << status.ToString();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
|
|
|
@ -15,87 +15,90 @@
|
|||
// Sandboxed version of multithread.c
|
||||
// Multithreaded HTTP GET requests
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#include <cstdlib>
|
||||
#include <future> // NOLINT(build/c++11)
|
||||
#include <thread> // NOLINT(build/c++11)
|
||||
|
||||
#include "../sandbox.h" // NOLINT(build/include)
|
||||
|
||||
void pull_one_url(const std::string& url, CurlApi& api) {
|
||||
namespace {
|
||||
|
||||
absl::Status pull_one_url(const std::string& url, curl::CurlApi& api) {
|
||||
// Initialize the curl session
|
||||
absl::StatusOr<CURL*> curl_handle = api.curl_easy_init();
|
||||
if (!curl_handle.ok()) {
|
||||
LOG(FATAL) << "curl_easy_init failed: " << curl_handle.status();
|
||||
}
|
||||
sapi::v::RemotePtr curl(curl_handle.value());
|
||||
if (!curl.GetValue()) {
|
||||
LOG(FATAL) << "curl_easy_init failed: curl is NULL";
|
||||
curl::CURL* curl_handle;
|
||||
SAPI_ASSIGN_OR_RETURN(curl_handle, api.curl_easy_init());
|
||||
sapi::v::RemotePtr curl(curl_handle);
|
||||
if (!curl_handle) {
|
||||
return absl::UnavailableError("curl_easy_init failed: curl is NULL");
|
||||
}
|
||||
|
||||
absl::StatusOr<int> curl_code;
|
||||
int curl_code;
|
||||
|
||||
// Specify URL to get
|
||||
sapi::v::ConstCStr sapi_url(url.c_str());
|
||||
curl_code =
|
||||
api.curl_easy_setopt_ptr(&curl, CURLOPT_URL, sapi_url.PtrBefore());
|
||||
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_easy_setopt_ptr failed: " << curl_code.status();
|
||||
SAPI_ASSIGN_OR_RETURN(curl_code, api.curl_easy_setopt_ptr(&curl, curl::CURLOPT_URL,
|
||||
sapi_url.PtrBefore()));
|
||||
if (curl_code != 0) {
|
||||
return absl::UnavailableError("curl_easy_setopt_ptr failed: " + curl_code);
|
||||
}
|
||||
|
||||
// Perform the request
|
||||
curl_code = api.curl_easy_perform(&curl);
|
||||
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_easy_perform failed: " << curl_code.status();
|
||||
SAPI_ASSIGN_OR_RETURN(curl_code, api.curl_easy_perform(&curl));
|
||||
if (curl_code != 0) {
|
||||
return absl::UnavailableError("curl_easy_perform failed: " + curl_code);
|
||||
}
|
||||
|
||||
// Cleanup curl
|
||||
absl::Status status = api.curl_easy_cleanup(&curl);
|
||||
if (!status.ok()) {
|
||||
LOG(FATAL) << "curl_easy_cleanup failed: " << status;
|
||||
}
|
||||
// Cleanup curl easy handle
|
||||
SAPI_RETURN_IF_ERROR(api.curl_easy_cleanup(&curl));
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
const std::vector<std::string> urls = {
|
||||
"http://example.com", "http://example.edu", "http://example.net",
|
||||
"http://example.org"};
|
||||
|
||||
absl::Status Example5() {
|
||||
// Initialize sandbox2 and sapi
|
||||
curl::CurlSapiSandbox sandbox;
|
||||
SAPI_RETURN_IF_ERROR(sandbox.Init());
|
||||
curl::CurlApi api(&sandbox);
|
||||
|
||||
int curl_code;
|
||||
|
||||
// Initialize curl (CURL_GLOBAL_DEFAULT = 3)
|
||||
SAPI_ASSIGN_OR_RETURN(curl_code, api.curl_global_init(3l));
|
||||
if (curl_code != 0) {
|
||||
return absl::UnavailableError("curl_global_init failed: " + curl_code);
|
||||
}
|
||||
|
||||
// Create the threads (by using futures)
|
||||
std::vector<std::future<absl::Status>> futures;
|
||||
for (auto& url : urls) {
|
||||
futures.emplace_back(
|
||||
std::async(pull_one_url, std::ref(url), std::ref(api)));
|
||||
}
|
||||
|
||||
// Join the threads and check for errors
|
||||
for (auto& future : futures) {
|
||||
SAPI_RETURN_IF_ERROR(future.get());
|
||||
}
|
||||
|
||||
// Cleanup curl
|
||||
SAPI_RETURN_IF_ERROR(api.curl_global_cleanup());
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
gflags::ParseCommandLineFlags(&argc, &argv, true);
|
||||
google::InitGoogleLogging(argv[0]);
|
||||
|
||||
absl::Status status;
|
||||
|
||||
// Initialize sandbox2 and sapi
|
||||
CurlSapiSandbox sandbox;
|
||||
status = sandbox.Init();
|
||||
if (!status.ok()) {
|
||||
LOG(FATAL) << "Couldn't initialize Sandboxed API: " << status;
|
||||
}
|
||||
CurlApi api(&sandbox);
|
||||
|
||||
absl::StatusOr<int> curl_code;
|
||||
|
||||
// Initialize curl (CURL_GLOBAL_DEFAULT = 3)
|
||||
curl_code = api.curl_global_init(3l);
|
||||
if (!curl_code.ok() || curl_code.value() != CURLE_OK) {
|
||||
LOG(FATAL) << "curl_global_init failed: " << curl_code.status();
|
||||
}
|
||||
|
||||
// Create the threads
|
||||
std::vector<std::thread> threads;
|
||||
for (auto& url : urls) {
|
||||
threads.emplace_back(pull_one_url, std::ref(url), std::ref(api));
|
||||
}
|
||||
|
||||
// Join the threads
|
||||
for (auto& thread : threads) {
|
||||
thread.join();
|
||||
}
|
||||
|
||||
// Cleanup curl
|
||||
status = api.curl_global_cleanup();
|
||||
if (!status.ok()) {
|
||||
LOG(FATAL) << "curl_global_cleanup failed: " << status;
|
||||
if (absl::Status status = Example5(); !status.ok()) {
|
||||
LOG(ERROR) << "Example5 failed: " << status.ToString();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
|
|
|
@ -20,6 +20,8 @@
|
|||
#include "../sandbox.h" // NOLINT(build/include)
|
||||
#include "sandboxed_api/transaction.h"
|
||||
|
||||
namespace {
|
||||
|
||||
class CurlTransaction : public sapi::Transaction {
|
||||
public:
|
||||
explicit CurlTransaction(std::unique_ptr<sapi::Sandbox> sandbox)
|
||||
|
@ -36,7 +38,7 @@ class CurlTransaction : public sapi::Transaction {
|
|||
};
|
||||
|
||||
absl::Status CurlTransaction::Main() {
|
||||
CurlApi api(sandbox());
|
||||
curl::CurlApi api(sandbox());
|
||||
|
||||
// Initialize the curl session
|
||||
SAPI_ASSIGN_OR_RETURN(void* curl_remote, api.curl_easy_init());
|
||||
|
@ -47,13 +49,13 @@ absl::Status CurlTransaction::Main() {
|
|||
sapi::v::ConstCStr url("http://example.com");
|
||||
SAPI_ASSIGN_OR_RETURN(
|
||||
int setopt_url_code,
|
||||
api.curl_easy_setopt_ptr(&curl, CURLOPT_URL, url.PtrBefore()));
|
||||
TRANSACTION_FAIL_IF_NOT(setopt_url_code == CURLE_OK,
|
||||
api.curl_easy_setopt_ptr(&curl, curl::CURLOPT_URL, url.PtrBefore()));
|
||||
TRANSACTION_FAIL_IF_NOT(setopt_url_code == curl::CURLE_OK,
|
||||
"curl_easy_setopt_ptr failed");
|
||||
|
||||
// Perform the request
|
||||
SAPI_ASSIGN_OR_RETURN(int perform_code, api.curl_easy_perform(&curl));
|
||||
TRANSACTION_FAIL_IF_NOT(setopt_url_code == CURLE_OK,
|
||||
TRANSACTION_FAIL_IF_NOT(setopt_url_code == curl::CURLE_OK,
|
||||
"curl_easy_perform failed");
|
||||
|
||||
// Cleanup curl
|
||||
|
@ -63,8 +65,10 @@ absl::Status CurlTransaction::Main() {
|
|||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
CurlTransaction curl{std::make_unique<CurlSapiSandbox>()};
|
||||
CurlTransaction curl{std::make_unique<curl::CurlSapiSandbox>()};
|
||||
absl::Status status = curl.Run();
|
||||
CHECK(status.ok()) << "CurlTransaction failed";
|
||||
|
||||
|
|
|
@ -24,7 +24,9 @@
|
|||
#include "curl_sapi.sapi.h" // NOLINT(build/include)
|
||||
#include "sandboxed_api/sandbox2/util/bpf_helper.h"
|
||||
|
||||
class CurlSapiSandbox : public CurlSandbox {
|
||||
namespace curl {
|
||||
|
||||
class CurlSapiSandbox : public curl::CurlSandbox {
|
||||
protected:
|
||||
std::unique_ptr<sandbox2::Policy> ModifyPolicy(
|
||||
sandbox2::PolicyBuilder* policy_builder) override {
|
||||
|
@ -64,4 +66,6 @@ class CurlSapiSandbox : public CurlSandbox {
|
|||
}
|
||||
};
|
||||
|
||||
} // namespace curl
|
||||
|
||||
#endif // SANDBOX_H_
|
||||
|
|
|
@ -28,17 +28,17 @@
|
|||
int CurlTestUtils::port_;
|
||||
std::thread CurlTestUtils::server_thread_;
|
||||
|
||||
absl::Status CurlTestUtils::CurlTestSetUp() {
|
||||
absl::Status curl::tests::CurlTestUtils::CurlTestSetUp() {
|
||||
// Initialize sandbox2 and sapi
|
||||
sandbox_ = std::make_unique<CurlSapiSandbox>();
|
||||
sandbox_ = std::make_unique<curl::CurlSapiSandbox>();
|
||||
absl::Status init = sandbox_->Init();
|
||||
if (!init.ok()) {
|
||||
return init;
|
||||
}
|
||||
api_ = std::make_unique<CurlApi>(sandbox_.get());
|
||||
api_ = std::make_unique<curl::CurlApi>(sandbox_.get());
|
||||
|
||||
// Initialize curl
|
||||
absl::StatusOr<CURL*> curl_handle = api_->curl_easy_init();
|
||||
absl::StatusOr<curl::CURL*> curl_handle = api_->curl_easy_init();
|
||||
if (!curl_handle.ok()) {
|
||||
return curl_handle.status();
|
||||
}
|
||||
|
@ -51,23 +51,24 @@ absl::Status CurlTestUtils::CurlTestSetUp() {
|
|||
|
||||
// Specify request URL
|
||||
sapi::v::ConstCStr sapi_url(kUrl.data());
|
||||
curl_code = api_->curl_easy_setopt_ptr(curl_.get(), CURLOPT_URL,
|
||||
curl_code = api_->curl_easy_setopt_ptr(curl_.get(), curl::CURLOPT_URL,
|
||||
sapi_url.PtrBefore());
|
||||
if (!curl_code.ok()) {
|
||||
return curl_code.status();
|
||||
}
|
||||
if (curl_code.value() != CURLE_OK) {
|
||||
if (curl_code.value() != curl::CURLE_OK) {
|
||||
return absl::UnavailableError(
|
||||
"curl_easy_setopt_ptr returned with the error code " +
|
||||
curl_code.value());
|
||||
}
|
||||
|
||||
// Set port
|
||||
curl_code = api_->curl_easy_setopt_long(curl_.get(), CURLOPT_PORT, port_);
|
||||
curl_code =
|
||||
api_->curl_easy_setopt_long(curl_.get(), curl::CURLOPT_PORT, port_);
|
||||
if (!curl_code.ok()) {
|
||||
return curl_code.status();
|
||||
}
|
||||
if (curl_code.value() != CURLE_OK) {
|
||||
if (curl_code.value() != curl::CURLE_OK) {
|
||||
return absl::UnavailableError(
|
||||
"curl_easy_setopt_long returned with the error code " +
|
||||
curl_code.value());
|
||||
|
@ -83,12 +84,12 @@ absl::Status CurlTestUtils::CurlTestSetUp() {
|
|||
sapi::v::RemotePtr remote_function_ptr(function_ptr);
|
||||
|
||||
// Set WriteToMemory as the write function
|
||||
curl_code = api_->curl_easy_setopt_ptr(curl_.get(), CURLOPT_WRITEFUNCTION,
|
||||
&remote_function_ptr);
|
||||
curl_code = api_->curl_easy_setopt_ptr(
|
||||
curl_.get(), curl::CURLOPT_WRITEFUNCTION, &remote_function_ptr);
|
||||
if (!curl_code.ok()) {
|
||||
return curl_code.status();
|
||||
}
|
||||
if (curl_code.value() != CURLE_OK) {
|
||||
if (curl_code.value() != curl::CURLE_OK) {
|
||||
return absl::UnavailableError(
|
||||
"curl_easy_setopt_ptr returned with the error code " +
|
||||
curl_code.value());
|
||||
|
@ -96,12 +97,12 @@ absl::Status CurlTestUtils::CurlTestSetUp() {
|
|||
|
||||
// Pass memory chunk object to the callback
|
||||
chunk_ = std::make_unique<sapi::v::LenVal>(0);
|
||||
curl_code = api_->curl_easy_setopt_ptr(curl_.get(), CURLOPT_WRITEDATA,
|
||||
curl_code = api_->curl_easy_setopt_ptr(curl_.get(), curl::CURLOPT_WRITEDATA,
|
||||
chunk_->PtrBoth());
|
||||
if (!curl_code.ok()) {
|
||||
return curl_code.status();
|
||||
}
|
||||
if (curl_code.value() != CURLE_OK) {
|
||||
if (curl_code.value() != curl::CURLE_OK) {
|
||||
return absl::UnavailableError(
|
||||
"curl_easy_setopt_ptr returned with the error code " +
|
||||
curl_code.value());
|
||||
|
@ -110,18 +111,18 @@ absl::Status CurlTestUtils::CurlTestSetUp() {
|
|||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
absl::Status CurlTestUtils::CurlTestTearDown() {
|
||||
absl::Status curl::tests::CurlTestUtils::CurlTestTearDown() {
|
||||
// Cleanup curl
|
||||
return api_->curl_easy_cleanup(curl_.get());
|
||||
}
|
||||
|
||||
absl::StatusOr<std::string> CurlTestUtils::PerformRequest() {
|
||||
absl::StatusOr<std::string> curl::tests::CurlTestUtils::PerformRequest() {
|
||||
// Perform the request
|
||||
absl::StatusOr<int> curl_code = api_->curl_easy_perform(curl_.get());
|
||||
if (!curl_code.ok()) {
|
||||
return curl_code.status();
|
||||
}
|
||||
if (curl_code.value() != CURLE_OK) {
|
||||
if (curl_code.value() != curl::CURLE_OK) {
|
||||
return absl::UnavailableError(
|
||||
"curl_easy_perform returned with the error code " + curl_code.value());
|
||||
}
|
||||
|
@ -267,7 +268,7 @@ void ServerLoop(int listening_socket, sockaddr_in socket_address) {
|
|||
|
||||
} // namespace
|
||||
|
||||
void CurlTestUtils::StartMockServer() {
|
||||
void curl::tests::CurlTestUtils::StartMockServer() {
|
||||
// Get the socket file descriptor
|
||||
int listening_socket = socket(AF_INET, SOCK_STREAM, 0);
|
||||
|
||||
|
|
|
@ -21,6 +21,8 @@
|
|||
#include "sandboxed_api/util/flag.h"
|
||||
#include "sandboxed_api/util/status_matchers.h"
|
||||
|
||||
namespace curl::tests {
|
||||
|
||||
// Helper class that can be used to test Curl Sandboxed
|
||||
class CurlTestUtils {
|
||||
protected:
|
||||
|
@ -39,8 +41,8 @@ class CurlTestUtils {
|
|||
// Responds with the POST request fields to a POST request
|
||||
static void StartMockServer();
|
||||
|
||||
std::unique_ptr<CurlSapiSandbox> sandbox_;
|
||||
std::unique_ptr<CurlApi> api_;
|
||||
std::unique_ptr<curl::CurlSapiSandbox> sandbox_;
|
||||
std::unique_ptr<curl::CurlApi> api_;
|
||||
std::unique_ptr<sapi::v::RemotePtr> curl_;
|
||||
|
||||
static std::thread server_thread_;
|
||||
|
@ -52,4 +54,6 @@ class CurlTestUtils {
|
|||
std::unique_ptr<sapi::v::LenVal> chunk_;
|
||||
};
|
||||
|
||||
} // namespace curl::tests
|
||||
|
||||
#endif // TESTS_H_
|
||||
|
|
|
@ -14,7 +14,9 @@
|
|||
|
||||
#include "test_utils.h" // NOLINT(build/include)
|
||||
|
||||
class CurlTest : public CurlTestUtils, public ::testing::Test {
|
||||
namespace {
|
||||
|
||||
class CurlTest : public curl::tests::CurlTestUtils, public ::testing::Test {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
// Start mock server, get port number and check for any error
|
||||
|
@ -38,9 +40,9 @@ TEST_F(CurlTest, EffectiveUrl) {
|
|||
// Get effective URL
|
||||
SAPI_ASSERT_OK_AND_ASSIGN(
|
||||
int getinfo_code,
|
||||
api_->curl_easy_getinfo_ptr(curl_.get(), CURLINFO_EFFECTIVE_URL,
|
||||
api_->curl_easy_getinfo_ptr(curl_.get(), curl::CURLINFO_EFFECTIVE_URL,
|
||||
effective_url_ptr.PtrBoth()));
|
||||
ASSERT_EQ(getinfo_code, CURLE_OK);
|
||||
ASSERT_EQ(getinfo_code, curl::CURLE_OK);
|
||||
|
||||
// Store effective URL in a string
|
||||
SAPI_ASSERT_OK_AND_ASSIGN(std::string effective_url,
|
||||
|
@ -74,9 +76,9 @@ TEST_F(CurlTest, ResponseCode) {
|
|||
// Get response code
|
||||
SAPI_ASSERT_OK_AND_ASSIGN(
|
||||
int getinfo_code,
|
||||
api_->curl_easy_getinfo_ptr(curl_.get(), CURLINFO_RESPONSE_CODE,
|
||||
api_->curl_easy_getinfo_ptr(curl_.get(), curl::CURLINFO_RESPONSE_CODE,
|
||||
response_code.PtrBoth()));
|
||||
ASSERT_EQ(getinfo_code, CURLE_OK);
|
||||
ASSERT_EQ(getinfo_code, curl::CURLE_OK);
|
||||
|
||||
// Check response code
|
||||
ASSERT_EQ(response_code.GetValue(), 200);
|
||||
|
@ -120,19 +122,21 @@ TEST_F(CurlTest, POSTResponse) {
|
|||
// Set the size of the POST fields
|
||||
SAPI_ASSERT_OK_AND_ASSIGN(
|
||||
int setopt_post_fields_size,
|
||||
api_->curl_easy_setopt_long(curl_.get(), CURLOPT_POSTFIELDSIZE,
|
||||
api_->curl_easy_setopt_long(curl_.get(), curl::CURLOPT_POSTFIELDSIZE,
|
||||
post_fields.GetSize()));
|
||||
ASSERT_EQ(setopt_post_fields_size, CURLE_OK);
|
||||
ASSERT_EQ(setopt_post_fields_size, curl::CURLE_OK);
|
||||
|
||||
// Set the POST fields
|
||||
SAPI_ASSERT_OK_AND_ASSIGN(
|
||||
int setopt_post_fields,
|
||||
api_->curl_easy_setopt_ptr(curl_.get(), CURLOPT_POSTFIELDS,
|
||||
api_->curl_easy_setopt_ptr(curl_.get(), curl::CURLOPT_POSTFIELDS,
|
||||
post_fields.PtrBefore()));
|
||||
ASSERT_EQ(setopt_post_fields, CURLE_OK);
|
||||
ASSERT_EQ(setopt_post_fields, curl::CURLE_OK);
|
||||
|
||||
SAPI_ASSERT_OK_AND_ASSIGN(std::string response, PerformRequest());
|
||||
|
||||
// Compare response with expected response
|
||||
ASSERT_EQ(std::string(post_fields.GetData()), response);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
58
oss-internship-2020/jsonnet/CMakeLists.txt
Normal file
58
oss-internship-2020/jsonnet/CMakeLists.txt
Normal file
|
@ -0,0 +1,58 @@
|
|||
# Copyright 2020 Google LLC
|
||||
#
|
||||
# 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.
|
||||
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
|
||||
project(jsonnet-sapi C CXX)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED True)
|
||||
|
||||
add_subdirectory(jsonnet)
|
||||
|
||||
add_subdirectory(examples)
|
||||
|
||||
set(SAPI_ROOT "../.." CACHE PATH "Path to the Sandboxed API source tree")
|
||||
set(SAPI_ENABLE_EXAMPLES OFF CACHE BOOL "")
|
||||
set(SAPI_ENABLE_TESTS OFF CACHE BOOL "")
|
||||
|
||||
add_subdirectory("${SAPI_ROOT}"
|
||||
"${CMAKE_BINARY_DIR}/sandboxed-api-build"
|
||||
EXCLUDE_FROM_ALL)
|
||||
|
||||
add_sapi_library(jsonnet_sapi
|
||||
FUNCTIONS c_jsonnet_evaluate_snippet
|
||||
c_jsonnet_make
|
||||
c_jsonnet_destroy
|
||||
c_read_input
|
||||
c_write_output_file
|
||||
c_jsonnet_realloc
|
||||
c_jsonnet_evaluate_snippet_multi
|
||||
c_write_multi_output_files
|
||||
c_write_output_stream
|
||||
c_jsonnet_evaluate_snippet_stream
|
||||
c_jsonnet_fmt_snippet
|
||||
INPUTS jsonnet_helper.h
|
||||
LIBRARY jsonnet_helper
|
||||
LIBRARY_NAME Jsonnet
|
||||
NAMESPACE ""
|
||||
)
|
||||
|
||||
target_include_directories(jsonnet_sapi INTERFACE
|
||||
"${PROJECT_BINARY_DIR}"
|
||||
)
|
||||
|
||||
target_link_libraries(jsonnet_sapi PUBLIC jsonnet_helper)
|
||||
|
||||
add_subdirectory(tests)
|
84
oss-internship-2020/jsonnet/README.md
Normal file
84
oss-internship-2020/jsonnet/README.md
Normal file
|
@ -0,0 +1,84 @@
|
|||
# Jsonnet Sandboxed API
|
||||
|
||||
This library provides sandboxed version of the
|
||||
[Jsonnet](https://github.com/google/jsonnet) library.
|
||||
|
||||
## Examples
|
||||
|
||||
The `examples/` directory contains code to produce three command-line tools --
|
||||
`jsonnet_sandboxed`, `jsonnet_yaml_stream_sandboxed` and
|
||||
`jsonnet_multiple_files_sandboxed` to evaluate jsonnet code. The first one
|
||||
enables the user to evaluate jsonnet code held in one file and writing to one
|
||||
output file. The second evaluates one jsonnet file into one file, which can be
|
||||
interepreted as YAML stream. The third one is for evaluating one jsonnet file
|
||||
into multiple output files. All three tools are based on what can be found
|
||||
[here](https://github.com/google/jsonnet/blob/master/cmd/jsonnet.cpp).
|
||||
|
||||
Apart from these, there is also a file producing `jsonnet_formatter_sandboxed`
|
||||
executable. It is based on a tool found from
|
||||
[here](https://github.com/google/jsonnet/blob/master/cmd/jsonnetfmt.cpp). It is
|
||||
a jsonnet code formatter -- it changes poorly written jsonnet files into their
|
||||
canonical form.
|
||||
|
||||
## Build
|
||||
|
||||
To build these examples, after cloning the whole Sandbox API project, you also
|
||||
need to run
|
||||
|
||||
```
|
||||
git submodule update --init --recursive
|
||||
```
|
||||
anywhere in the project tree in order to clone the `jsonnet` submodule.
|
||||
Then in the `sandboxed-api/oss-internship-2020/jsonnet` run
|
||||
|
||||
```
|
||||
mkdir build && cd build
|
||||
cmake -G Ninja
|
||||
ninja
|
||||
```
|
||||
|
||||
To run `jsonnet_sandboxed` (or `jsonnet_yaml_stream_sandboxed` or
|
||||
`jsonnet_formatter_sandboxed` in a similar way):
|
||||
|
||||
```
|
||||
cd examples
|
||||
./jsonnet_sandboxed \
|
||||
absolute/path/to/the/input_file.jsonnet \
|
||||
absolute/path/to/the/output_file
|
||||
```
|
||||
|
||||
To run `jsonnet_mutiple_files_sandboxed`:
|
||||
|
||||
```
|
||||
cd examples
|
||||
./jsonnet_mutiple_files_sandboxed \
|
||||
absolute/path/to/the/input_file.jsonnet \
|
||||
absolute/path/to/the/output_directory
|
||||
```
|
||||
|
||||
All three tools support evaluating one input file (possibly relying on multiple
|
||||
other files, e.x. by jsonnet `import` command; the files must be held in the
|
||||
same directory as input file) into one or more output files. Example jsonnet
|
||||
codes to evaluate in a one-in-one-out manner can be found
|
||||
[here](https://github.com/google/jsonnet/tree/master/examples). Example code
|
||||
producing multiple output files or YAML stream files can be found in the
|
||||
`examples/jsonnet_codes` directory (along with some other examples copied with
|
||||
minimal changes from the library files), in files called
|
||||
`multiple_files_example.jsonnet` and `yaml_stream_example.jsonnet`,
|
||||
respectively. In the `examples/jsonnet_codes_expected_output` directory one can
|
||||
found outputs the mentioned above files' evaluation should produce.
|
||||
|
||||
The formatter reads one input file and produces one output file as a result.
|
||||
Example code for this tool can also be found in `examples/jsonnet_codes`
|
||||
directory, in a file called `formatter_example.jsonnet`.
|
||||
|
||||
## Testing
|
||||
|
||||
A few tests prepared with a use of
|
||||
[Google Test](https://github.com/google/googletest) framework can be found in
|
||||
the `tests/` directory. To run them type:
|
||||
|
||||
```
|
||||
cd tests
|
||||
./tests
|
||||
```
|
75
oss-internship-2020/jsonnet/examples/CMakeLists.txt
Normal file
75
oss-internship-2020/jsonnet/examples/CMakeLists.txt
Normal file
|
@ -0,0 +1,75 @@
|
|||
# Copyright 2020 Google LLC
|
||||
#
|
||||
# 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.
|
||||
|
||||
file(MAKE_DIRECTORY "${PROJECT_BINARY_DIR}/gen_files")
|
||||
file(COPY "${PROJECT_SOURCE_DIR}/jsonnet/cmd/jsonnet.cpp" DESTINATION "${PROJECT_BINARY_DIR}/gen_files/")
|
||||
file(COPY "${PROJECT_SOURCE_DIR}/jsonnet.patch" DESTINATION "${PROJECT_BINARY_DIR}/gen_files/")
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${PROJECT_BINARY_DIR}/gen_files/write_helper.cc
|
||||
COMMAND cd ${PROJECT_BINARY_DIR}/gen_files && patch < ${PROJECT_SOURCE_DIR}/jsonnet.patch > /dev/null
|
||||
COMMAND mv ${PROJECT_BINARY_DIR}/gen_files/jsonnet.cpp ${PROJECT_BINARY_DIR}/gen_files/write_helper.cc
|
||||
)
|
||||
|
||||
list(APPEND JSONNET_SAPI_HEADERS
|
||||
${PROJECT_SOURCE_DIR}
|
||||
${PROJECT_SOURCE_DIR}/headers
|
||||
${PROJECT_BINARY_DIR}/gen_files
|
||||
)
|
||||
|
||||
add_library(jsonnet_helper STATIC
|
||||
${PROJECT_SOURCE_DIR}/jsonnet_helper.cc
|
||||
${PROJECT_SOURCE_DIR}/jsonnet_helper.h
|
||||
${PROJECT_SOURCE_DIR}/jsonnet/cmd/utils.h
|
||||
${PROJECT_SOURCE_DIR}/jsonnet/cmd/utils.cpp
|
||||
${PROJECT_BINARY_DIR}/gen_files/write_helper.cc
|
||||
)
|
||||
|
||||
target_include_directories(jsonnet_helper PUBLIC
|
||||
${JSONNET_SAPI_HEADERS}
|
||||
)
|
||||
|
||||
target_link_libraries(jsonnet_helper
|
||||
libjsonnet_for_binaries
|
||||
)
|
||||
|
||||
foreach(exe base multiple_files yaml_stream formatter)
|
||||
add_executable(jsonnet_${exe}_sandboxed
|
||||
jsonnet_${exe}_example.cc
|
||||
)
|
||||
|
||||
target_link_libraries(jsonnet_${exe}_sandboxed PRIVATE
|
||||
libjsonnet
|
||||
jsonnet_helper
|
||||
jsonnet_sapi
|
||||
sandbox2::file_base
|
||||
sandbox2::fileops
|
||||
sapi::sapi
|
||||
)
|
||||
|
||||
target_include_directories(jsonnet_${exe}_sandboxed PUBLIC
|
||||
${JSONNET_SAPI_HEADERS}
|
||||
)
|
||||
endforeach()
|
||||
|
||||
add_executable(jsonnet_base_transacted
|
||||
jsonnet_base_transaction.cc
|
||||
)
|
||||
|
||||
target_link_libraries(jsonnet_base_transacted PRIVATE
|
||||
libjsonnet
|
||||
jsonnet_helper
|
||||
jsonnet_sapi
|
||||
sapi::sapi
|
||||
)
|
95
oss-internship-2020/jsonnet/examples/jsonnet_base_example.cc
Normal file
95
oss-internship-2020/jsonnet/examples/jsonnet_base_example.cc
Normal file
|
@ -0,0 +1,95 @@
|
|||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// 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 <cstdlib>
|
||||
#include <iostream>
|
||||
|
||||
#include "jsonnet_base_sandbox.h" // NOLINT(build/include)
|
||||
#include "sandboxed_api/sandbox2/util/fileops.h"
|
||||
#include "sandboxed_api/sandbox2/util/path.h"
|
||||
|
||||
absl::Status JsonnetMain(std::string in_file, std::string out_file) {
|
||||
using sandbox2::file::JoinPath;
|
||||
using sandbox2::file_util::fileops::Basename;
|
||||
|
||||
// Initialize sandbox.
|
||||
JsonnetBaseSandbox sandbox(in_file, out_file);
|
||||
SAPI_RETURN_IF_ERROR(sandbox.Init())
|
||||
|
||||
JsonnetApi api(&sandbox);
|
||||
|
||||
// Initialize library's main structure.
|
||||
SAPI_ASSIGN_OR_RETURN(JsonnetVm * jsonnet_vm, api.c_jsonnet_make());
|
||||
sapi::v::RemotePtr vm_pointer(jsonnet_vm);
|
||||
|
||||
// Read input file.
|
||||
std::string in_file_in_sandboxee(JoinPath("/input", Basename(in_file)));
|
||||
sapi::v::ConstCStr in_file_var(in_file_in_sandboxee.c_str());
|
||||
SAPI_ASSIGN_OR_RETURN(char* input,
|
||||
api.c_read_input(false, in_file_var.PtrBefore()));
|
||||
|
||||
// Process jsonnet data.
|
||||
sapi::v::RemotePtr input_pointer(input);
|
||||
sapi::v::Int error;
|
||||
SAPI_ASSIGN_OR_RETURN(char* output, api.c_jsonnet_evaluate_snippet(
|
||||
&vm_pointer, in_file_var.PtrBefore(),
|
||||
&input_pointer, error.PtrAfter()));
|
||||
CHECK(!error.GetValue()) << "Jsonnet code evaluation failed: "
|
||||
<< error.GetValue() << "\n"
|
||||
<< "Make sure all files used by your jsonnet file "
|
||||
"are in the same directory as your file.";
|
||||
|
||||
// Write data to file.
|
||||
std::string out_file_in_sandboxee(JoinPath("/output", Basename(out_file)));
|
||||
sapi::v::ConstCStr out_file_var(out_file_in_sandboxee.c_str());
|
||||
sapi::v::RemotePtr output_pointer(output);
|
||||
|
||||
SAPI_ASSIGN_OR_RETURN(
|
||||
bool success,
|
||||
api.c_write_output_file(&output_pointer, out_file_var.PtrBefore()));
|
||||
CHECK(success) << "Writing to output file failed: " << success;
|
||||
|
||||
// Clean up.
|
||||
SAPI_ASSIGN_OR_RETURN(char* result,
|
||||
api.c_jsonnet_realloc(&vm_pointer, &output_pointer, 0));
|
||||
SAPI_RETURN_IF_ERROR(api.c_jsonnet_destroy(&vm_pointer));
|
||||
SAPI_RETURN_IF_ERROR(api.c_free_input(&input_pointer));
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
using sandbox2::file_util::fileops::Basename;
|
||||
|
||||
google::InitGoogleLogging(argv[0]);
|
||||
gflags::ParseCommandLineFlags(&argc, &argv, true);
|
||||
|
||||
if (!(argc == 3)) {
|
||||
std::cerr << "Usage:\n"
|
||||
<< Basename(argv[0])
|
||||
<< " /absolute/path/to/INPUT.jsonnet /absolute/path/to/OUTPUT\n";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
std::string in_file(argv[1]);
|
||||
std::string out_file(argv[2]);
|
||||
|
||||
absl::Status status = JsonnetMain(in_file, out_file);
|
||||
if (!status.ok()) {
|
||||
LOG(ERROR) << "Failed: " << status.ToString();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// 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 "jsonnet_base_transaction.h" // NOLINT(build/include)
|
||||
|
||||
#include "sandboxed_api/sandbox2/util/fileops.h"
|
||||
#include "sandboxed_api/sandbox2/util/path.h"
|
||||
|
||||
absl::Status JsonnetTransaction::Main() {
|
||||
using sandbox2::file::JoinPath;
|
||||
using sandbox2::file_util::fileops::Basename;
|
||||
|
||||
JsonnetApi api(sandbox());
|
||||
|
||||
// Initialize library's main structure.
|
||||
SAPI_ASSIGN_OR_RETURN(JsonnetVm * jsonnet_vm, api.c_jsonnet_make());
|
||||
sapi::v::RemotePtr vm_pointer(jsonnet_vm);
|
||||
|
||||
// Read input file.
|
||||
std::string in_file_in_sandboxee(JoinPath("/input", Basename(in_file)));
|
||||
sapi::v::ConstCStr in_file_var(in_file_in_sandboxee.c_str());
|
||||
SAPI_ASSIGN_OR_RETURN(char* input,
|
||||
api.c_read_input(false, in_file_var.PtrBefore()));
|
||||
|
||||
// Process jsonnet data.
|
||||
sapi::v::RemotePtr input_pointer(input);
|
||||
sapi::v::Int error;
|
||||
SAPI_ASSIGN_OR_RETURN(char* output, api.c_jsonnet_evaluate_snippet(
|
||||
&vm_pointer, in_file_var.PtrBefore(),
|
||||
&input_pointer, error.PtrAfter()));
|
||||
TRANSACTION_FAIL_IF_NOT(error.GetValue() == 0,
|
||||
"Jsonnet code evaluation failed.");
|
||||
|
||||
// Write data to file.
|
||||
std::string out_file_in_sandboxee(JoinPath("/output", Basename(out_file)));
|
||||
sapi::v::ConstCStr out_file_var(out_file_in_sandboxee.c_str());
|
||||
sapi::v::RemotePtr output_pointer(output);
|
||||
SAPI_ASSIGN_OR_RETURN(
|
||||
bool success,
|
||||
api.c_write_output_file(&output_pointer, out_file_var.PtrBefore()));
|
||||
TRANSACTION_FAIL_IF_NOT(success, "Writing to output file failed.");
|
||||
|
||||
// Clean up.
|
||||
SAPI_ASSIGN_OR_RETURN(char* result,
|
||||
api.c_jsonnet_realloc(&vm_pointer, &output_pointer, 0));
|
||||
|
||||
SAPI_RETURN_IF_ERROR(api.c_jsonnet_destroy(&vm_pointer));
|
||||
SAPI_RETURN_IF_ERROR(api.c_free_input(&input_pointer));
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
using sandbox2::file_util::fileops::Basename;
|
||||
|
||||
google::InitGoogleLogging(argv[0]);
|
||||
gflags::ParseCommandLineFlags(&argc, &argv, true);
|
||||
|
||||
if (!(argc == 3)) {
|
||||
std::cerr << "Usage:\n"
|
||||
<< Basename(argv[0])
|
||||
<< " /absolute/path/to/INPUT.jsonnet /absolute/path/to/OUTPUT\n";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
std::string in_file(argv[1]);
|
||||
std::string out_file(argv[2]);
|
||||
|
||||
JsonnetTransaction jsonnet_transaction(in_file, out_file);
|
||||
|
||||
auto result = jsonnet_transaction.Run();
|
||||
|
||||
LOG(INFO) << "Transaction result: " << result.message();
|
||||
CHECK(result.ok());
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
Copyright 2015 Google Inc. All rights reserved.
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
{
|
||||
concat_array: [1, 2, 3] + [4],
|
||||
concat_string: '123' + 4,
|
||||
equality1: 1 == '1',
|
||||
equality2: [{}, { x: 3 - 1 }]
|
||||
== [{}, { x: 2 }],
|
||||
ex1: 1 + 2 * 3 / (4 + 5),
|
||||
// Bitwise operations first cast to int.
|
||||
ex2: self.ex1 | 3,
|
||||
// Modulo operator.
|
||||
ex3: self.ex1 % 2,
|
||||
// Boolean logic
|
||||
ex4: (4 > 3) && (1 <= 3) || false,
|
||||
// Mixing objects together
|
||||
obj: { a: 1, b: 2 } + { b: 3, c: 4 },
|
||||
// Test if a field is in an object
|
||||
obj_member: 'foo' in { foo: 1 },
|
||||
// String formatting
|
||||
str1: 'The value of self.ex2 is '
|
||||
+ self.ex2 + '.',
|
||||
str2: 'The value of self.ex2 is %g.'
|
||||
% self.ex2,
|
||||
str3: 'ex1=%0.2f, ex2=%0.2f'
|
||||
% [self.ex1, self.ex2],
|
||||
// By passing self, we allow ex1 and ex2 to
|
||||
// be extracted internally.
|
||||
str4: 'ex1=%(ex1)0.2f, ex2=%(ex2)0.2f'
|
||||
% self,
|
||||
// Do textual templating of entire files:
|
||||
str5: |||
|
||||
ex1=%(ex1)0.2f
|
||||
ex2=%(ex2)0.2f
|
||||
||| % self,
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// 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.
|
||||
|
||||
// This is a poorly written jsonnet file. Given to the formatter executable will be changed into a canonical jsonnet file form.
|
||||
local b = import "somefile.libsonnet"; # comment
|
||||
local a = import "differentfile.libsonnet"; // another comment in different style
|
||||
|
||||
local SomeStuff = {bar: "foo"};
|
||||
|
||||
local funtion_to_do_addition(x,y)=x+y;
|
||||
|
||||
{
|
||||
"this": ((3)) ,
|
||||
"that that":
|
||||
funtion_to_do_addition(4,2),
|
||||
arrArr: [[
|
||||
1, 2, 5
|
||||
],
|
||||
3, 10, 19
|
||||
]
|
||||
} + SomeStuff
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
Copyright 2015 Google Inc. All rights reserved.
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
local martinis = import 'martinis.libsonnet';
|
||||
|
||||
{
|
||||
'Vodka Martini': martinis['Vodka Martini'],
|
||||
Manhattan: {
|
||||
ingredients: [
|
||||
{ kind: 'Rye', qty: 2.5 },
|
||||
{ kind: 'Sweet Red Vermouth', qty: 1 },
|
||||
{ kind: 'Angostura', qty: 'dash' },
|
||||
],
|
||||
garnish: importstr 'garnish.txt',
|
||||
served: 'Straight Up',
|
||||
},
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// 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.
|
||||
|
||||
// This is a jsonnet code which evaluates to mutliple output files.
|
||||
{
|
||||
"first_file.json": {
|
||||
name: 'This is the first file created by the multiple-files example code.',
|
||||
caption: 'The other one\'s name is -> ' + $["second_file.json"].name,
|
||||
},
|
||||
"second_file.json": {
|
||||
name: 'And that is the other one.',
|
||||
caption: 'If it was the first one, variable name would hold what\'s in <first_name> variable.',
|
||||
first_name: $["first_file.json"].name,
|
||||
},
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
Copyright 2015 Google Inc. All rights reserved.
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
local utils = import 'utils.libsonnet';
|
||||
{
|
||||
Negroni: {
|
||||
// Divide 3oz among the 3 ingredients.
|
||||
ingredients: utils.equal_parts(3, [
|
||||
'Farmers Gin',
|
||||
'Sweet Red Vermouth',
|
||||
'Campari',
|
||||
]),
|
||||
garnish: 'Orange Peel',
|
||||
served: 'On The Rocks',
|
||||
},
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
Copyright 2015 Google Inc. All rights reserved.
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
{
|
||||
equal_parts(size, ingredients)::
|
||||
// Define a function-scoped variable.
|
||||
local qty = size / std.length(ingredients);
|
||||
// Return an array.
|
||||
[
|
||||
{ kind: i, qty: qty }
|
||||
for i in ingredients
|
||||
],
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// 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.
|
||||
|
||||
// This is a jsonnet code which evaluates to json file, which can be interpreted as YAML stream.
|
||||
local
|
||||
first_object = {
|
||||
name: 'First object\'s name.',
|
||||
age: 'Just created!',
|
||||
},
|
||||
second_object = {
|
||||
name: 'Hi, my name is <second_object>.',
|
||||
sibling: first_object.name
|
||||
};
|
||||
|
||||
[first_object, second_object]
|
|
@ -0,0 +1,26 @@
|
|||
{
|
||||
"concat_array": [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4
|
||||
],
|
||||
"concat_string": "1234",
|
||||
"equality1": false,
|
||||
"equality2": true,
|
||||
"ex1": 1.6666666666666665,
|
||||
"ex2": 3,
|
||||
"ex3": 1.6666666666666665,
|
||||
"ex4": true,
|
||||
"obj": {
|
||||
"a": 1,
|
||||
"b": 3,
|
||||
"c": 4
|
||||
},
|
||||
"obj_member": true,
|
||||
"str1": "The value of self.ex2 is 3.",
|
||||
"str2": "The value of self.ex2 is 3.",
|
||||
"str3": "ex1=1.67, ex2=3.00",
|
||||
"str4": "ex1=1.67, ex2=3.00",
|
||||
"str5": "ex1=1.67\nex2=3.00\n"
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"caption": "The other one's name is -> And that is the other one.",
|
||||
"name": "This is the first file created by the multiple-files example code."
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"Negroni": {
|
||||
"garnish": "Orange Peel",
|
||||
"ingredients": [
|
||||
{
|
||||
"kind": "Farmers Gin",
|
||||
"qty": 1
|
||||
},
|
||||
{
|
||||
"kind": "Sweet Red Vermouth",
|
||||
"qty": 1
|
||||
},
|
||||
{
|
||||
"kind": "Campari",
|
||||
"qty": 1
|
||||
}
|
||||
],
|
||||
"served": "On The Rocks"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"caption": "If it was the first one, variable name would hold what's in <first_name> variable.",
|
||||
"first_name": "This is the first file created by the multiple-files example code.",
|
||||
"name": "And that is the other one."
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
{
|
||||
"age": "Just created!",
|
||||
"name": "First object's name."
|
||||
}
|
||||
---
|
||||
{
|
||||
"name": "Hi, my name is <second_object>.",
|
||||
"sibling": "First object's name."
|
||||
}
|
||||
...
|
|
@ -0,0 +1,128 @@
|
|||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// 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 <libgen.h>
|
||||
#include <syscall.h>
|
||||
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
|
||||
#include "jsonnet_sapi.sapi.h" // NOLINT(build/include)
|
||||
#include "sandboxed_api/util/flag.h"
|
||||
#include "sandboxed_api/sandbox2/util/fileops.h"
|
||||
#include "sandboxed_api/sandbox2/util/path.h"
|
||||
|
||||
class JsonnetSapiSandbox : public JsonnetSandbox {
|
||||
public:
|
||||
explicit JsonnetSapiSandbox(std::string in_file, std::string out_file)
|
||||
: in_file_(std::move(in_file)), out_file_(std::move(out_file)) {}
|
||||
|
||||
// We need only the input file here, not the whole input directory
|
||||
std::unique_ptr<sandbox2::Policy> ModifyPolicy(
|
||||
sandbox2::PolicyBuilder*) override {
|
||||
return sandbox2::PolicyBuilder()
|
||||
.AllowStaticStartup()
|
||||
.AllowOpen()
|
||||
.AllowRead()
|
||||
.AllowWrite()
|
||||
.AllowStat()
|
||||
.AllowSystemMalloc()
|
||||
.AllowExit()
|
||||
.AllowSyscalls({
|
||||
__NR_futex,
|
||||
__NR_close,
|
||||
})
|
||||
.AddDirectoryAt(dirname(&out_file_[0]), "/output", /*is_ro=*/false)
|
||||
.AddFile(in_file_, true)
|
||||
.BuildOrDie();
|
||||
}
|
||||
|
||||
private:
|
||||
std::string in_file_;
|
||||
std::string out_file_;
|
||||
};
|
||||
|
||||
absl::Status JsonnetMain(std::string in_file, std::string out_file) {
|
||||
using sandbox2::file::JoinPath;
|
||||
using sandbox2::file_util::fileops::Basename;
|
||||
|
||||
// Initialize sandbox.
|
||||
JsonnetSapiSandbox sandbox(in_file, out_file);
|
||||
SAPI_RETURN_IF_ERROR(sandbox.Init())
|
||||
|
||||
JsonnetApi api(&sandbox);
|
||||
|
||||
// Initialize library's main structure.
|
||||
SAPI_ASSIGN_OR_RETURN(JsonnetVm * jsonnet_vm, api.c_jsonnet_make());
|
||||
sapi::v::RemotePtr vm_pointer(jsonnet_vm);
|
||||
|
||||
// Read input file.
|
||||
std::string in_file_in_sandboxee(JoinPath("/input", Basename(in_file)));
|
||||
sapi::v::ConstCStr in_file_var(in_file_in_sandboxee.c_str());
|
||||
SAPI_ASSIGN_OR_RETURN(char* input,
|
||||
api.c_read_input(false, in_file_var.PtrBefore()));
|
||||
|
||||
// Process jsonnet data.
|
||||
sapi::v::RemotePtr input_pointer(input);
|
||||
sapi::v::Int error;
|
||||
SAPI_ASSIGN_OR_RETURN(char* output, api.c_jsonnet_fmt_snippet(
|
||||
&vm_pointer, in_file_var.PtrBefore(),
|
||||
&input_pointer, error.PtrAfter()));
|
||||
|
||||
CHECK(!error.GetValue()) << "Jsonnet code evaluation failed: "
|
||||
<< error.GetValue() << "\n";
|
||||
|
||||
// Write data to file.
|
||||
std::string out_file_in_sandboxee(JoinPath("/output", Basename(out_file)));
|
||||
sapi::v::ConstCStr out_file_var(out_file_in_sandboxee.c_str());
|
||||
sapi::v::RemotePtr output_pointer(output);
|
||||
|
||||
SAPI_ASSIGN_OR_RETURN(
|
||||
bool success,
|
||||
api.c_write_output_file(&output_pointer, out_file_var.PtrBefore()));
|
||||
CHECK(success) << "Writing to output file failed: " << success;
|
||||
|
||||
// Clean up.
|
||||
SAPI_ASSIGN_OR_RETURN(char* result,
|
||||
api.c_jsonnet_realloc(&vm_pointer, &output_pointer, 0));
|
||||
SAPI_RETURN_IF_ERROR(api.c_jsonnet_destroy(&vm_pointer));
|
||||
SAPI_RETURN_IF_ERROR(api.c_free_input(&input_pointer));
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
using sandbox2::file_util::fileops::Basename;
|
||||
|
||||
google::InitGoogleLogging(argv[0]);
|
||||
gflags::ParseCommandLineFlags(&argc, &argv, true);
|
||||
|
||||
if (!(argc == 3)) {
|
||||
std::cerr << "Usage:\n"
|
||||
<< Basename(argv[0])
|
||||
<< " /absolute/path/to/INPUT.jsonnet /absolute/path/to/OUTPUT\n";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
std::string in_file(argv[1]);
|
||||
std::string out_file(argv[2]);
|
||||
|
||||
absl::Status status = JsonnetMain(in_file, out_file);
|
||||
if (!status.ok()) {
|
||||
LOG(ERROR) << "Failed: " << status.ToString();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
|
@ -0,0 +1,132 @@
|
|||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// 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 <libgen.h>
|
||||
#include <syscall.h>
|
||||
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
|
||||
#include "jsonnet_sapi.sapi.h" // NOLINT(build/include)
|
||||
#include "sandboxed_api/util/flag.h"
|
||||
#include "sandboxed_api/sandbox2/util/fileops.h"
|
||||
#include "sandboxed_api/sandbox2/util/path.h"
|
||||
|
||||
class JsonnetSapiSandbox : public JsonnetSandbox {
|
||||
public:
|
||||
explicit JsonnetSapiSandbox(std::string in_file, std::string out_directory)
|
||||
: in_file_(std::move(in_file)),
|
||||
out_directory_(std::move(out_directory)) {}
|
||||
|
||||
// We need a slightly different policy than the default one
|
||||
std::unique_ptr<sandbox2::Policy> ModifyPolicy(
|
||||
sandbox2::PolicyBuilder*) override {
|
||||
return sandbox2::PolicyBuilder()
|
||||
.AllowStaticStartup()
|
||||
.AllowOpen()
|
||||
.AllowRead()
|
||||
.AllowWrite()
|
||||
.AllowStat()
|
||||
.AllowSystemMalloc()
|
||||
.AllowExit()
|
||||
.AllowSyscalls({
|
||||
__NR_futex,
|
||||
__NR_close,
|
||||
})
|
||||
.AddDirectoryAt(sandbox2::file::CleanPath(&out_directory_[0]),
|
||||
"/output",
|
||||
/*is_ro=*/false)
|
||||
.AddDirectoryAt(dirname(&in_file_[0]), "/input", true)
|
||||
.BuildOrDie();
|
||||
}
|
||||
|
||||
private:
|
||||
std::string in_file_;
|
||||
std::string out_directory_;
|
||||
};
|
||||
|
||||
absl::Status JsonnetMain(std::string in_file, std::string out_file) {
|
||||
using sandbox2::file::JoinPath;
|
||||
using sandbox2::file_util::fileops::Basename;
|
||||
|
||||
// Initialize sandbox.
|
||||
JsonnetSapiSandbox sandbox(in_file, out_file);
|
||||
SAPI_RETURN_IF_ERROR(sandbox.Init())
|
||||
|
||||
JsonnetApi api(&sandbox);
|
||||
|
||||
// Initialize library's main structure.
|
||||
SAPI_ASSIGN_OR_RETURN(JsonnetVm * jsonnet_vm, api.c_jsonnet_make());
|
||||
sapi::v::RemotePtr vm_pointer(jsonnet_vm);
|
||||
|
||||
// Read input file.
|
||||
std::string in_file_in_sandboxee(JoinPath("/input", Basename(in_file)));
|
||||
sapi::v::ConstCStr in_file_var(in_file_in_sandboxee.c_str());
|
||||
SAPI_ASSIGN_OR_RETURN(char* input,
|
||||
api.c_read_input(false, in_file_var.PtrBefore()));
|
||||
|
||||
// Process jsonnet data.
|
||||
sapi::v::RemotePtr input_pointer(input);
|
||||
sapi::v::Int error;
|
||||
SAPI_ASSIGN_OR_RETURN(char* output, api.c_jsonnet_evaluate_snippet_multi(
|
||||
&vm_pointer, in_file_var.PtrBefore(),
|
||||
&input_pointer, error.PtrAfter()));
|
||||
CHECK(!error.GetValue()) << "Jsonnet code evaluation failed: "
|
||||
<< error.GetValue() << "\n"
|
||||
<< "Make sure all files used by your jsonnet file "
|
||||
"are in the same directory as your file.";
|
||||
|
||||
// Write data to file.
|
||||
std::string out_file_in_sandboxee(JoinPath("/output", Basename(out_file)));
|
||||
sapi::v::ConstCStr out_file_var(out_file_in_sandboxee.c_str());
|
||||
sapi::v::RemotePtr output_pointer(output);
|
||||
|
||||
SAPI_ASSIGN_OR_RETURN(
|
||||
bool success,
|
||||
api.c_write_output_file(&output_pointer, out_file_var.PtrBefore()));
|
||||
CHECK(success) << "Writing to output file failed: " << success;
|
||||
|
||||
// Clean up.
|
||||
SAPI_ASSIGN_OR_RETURN(char* result,
|
||||
api.c_jsonnet_realloc(&vm_pointer, &output_pointer, 0));
|
||||
SAPI_RETURN_IF_ERROR(api.c_jsonnet_destroy(&vm_pointer));
|
||||
SAPI_RETURN_IF_ERROR(api.c_free_input(&input_pointer));
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
using sandbox2::file_util::fileops::Basename;
|
||||
|
||||
google::InitGoogleLogging(argv[0]);
|
||||
gflags::ParseCommandLineFlags(&argc, &argv, true);
|
||||
|
||||
if (!(argc == 3)) {
|
||||
std::cerr << "Usage:\n"
|
||||
<< Basename(argv[0])
|
||||
<< " /absolute/path/to/INPUT.jsonnet /absolute/path/to/OUTPUT\n";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
std::string in_file(argv[1]);
|
||||
std::string out_file(argv[2]);
|
||||
|
||||
absl::Status status = JsonnetMain(in_file, out_file);
|
||||
if (!status.ok()) {
|
||||
LOG(ERROR) << "Failed: " << status.ToString();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// 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 <cstdlib>
|
||||
#include <iostream>
|
||||
|
||||
#include "jsonnet_base_sandbox.h" // NOLINT(build/include)
|
||||
#include "sandboxed_api/sandbox2/util/fileops.h"
|
||||
#include "sandboxed_api/sandbox2/util/path.h"
|
||||
|
||||
absl::Status JsonnetMain(std::string in_file, std::string out_file) {
|
||||
using sandbox2::file::JoinPath;
|
||||
using sandbox2::file_util::fileops::Basename;
|
||||
|
||||
// Initialize sandbox.
|
||||
JsonnetBaseSandbox sandbox(in_file, out_file);
|
||||
SAPI_RETURN_IF_ERROR(sandbox.Init())
|
||||
|
||||
JsonnetApi api(&sandbox);
|
||||
|
||||
// Initialize library's main structure.
|
||||
SAPI_ASSIGN_OR_RETURN(JsonnetVm * jsonnet_vm, api.c_jsonnet_make());
|
||||
sapi::v::RemotePtr vm_pointer(jsonnet_vm);
|
||||
|
||||
// Read input file.
|
||||
std::string in_file_in_sandboxee(JoinPath("/input", Basename(in_file)));
|
||||
sapi::v::ConstCStr in_file_var(in_file_in_sandboxee.c_str());
|
||||
SAPI_ASSIGN_OR_RETURN(char* input,
|
||||
api.c_read_input(false, in_file_var.PtrBefore()));
|
||||
|
||||
// Process jsonnet data.
|
||||
sapi::v::RemotePtr input_pointer(input);
|
||||
sapi::v::Int error;
|
||||
SAPI_ASSIGN_OR_RETURN(char* output, api.c_jsonnet_evaluate_snippet_stream(
|
||||
&vm_pointer, in_file_var.PtrBefore(),
|
||||
&input_pointer, error.PtrAfter()));
|
||||
CHECK(!error.GetValue())
|
||||
<< "Jsonnet code evaluation failed: " << error.GetValue() << "\n"
|
||||
<< "Make sure all files used by your jsonnet file are in the same "
|
||||
"directory as your file.";
|
||||
|
||||
// Write data to file.
|
||||
std::string out_file_in_sandboxee(JoinPath("/output", Basename(out_file)));
|
||||
sapi::v::ConstCStr out_file_var(out_file_in_sandboxee.c_str());
|
||||
sapi::v::RemotePtr output_pointer(output);
|
||||
|
||||
SAPI_ASSIGN_OR_RETURN(
|
||||
bool success,
|
||||
api.c_write_output_file(&output_pointer, out_file_var.PtrBefore()));
|
||||
CHECK(success) << "Writing to output file failed: " << success;
|
||||
|
||||
// Clean up.
|
||||
SAPI_ASSIGN_OR_RETURN(char* result,
|
||||
api.c_jsonnet_realloc(&vm_pointer, &output_pointer, 0));
|
||||
SAPI_RETURN_IF_ERROR(api.c_jsonnet_destroy(&vm_pointer));
|
||||
SAPI_RETURN_IF_ERROR(api.c_free_input(&input_pointer));
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
using sandbox2::file_util::fileops::Basename;
|
||||
|
||||
google::InitGoogleLogging(argv[0]);
|
||||
gflags::ParseCommandLineFlags(&argc, &argv, true);
|
||||
|
||||
if (!(argc == 3)) {
|
||||
std::cerr << "Usage:\n"
|
||||
<< Basename(argv[0])
|
||||
<< " /absolute/path/to/INPUT.jsonnet /absolute/path/to/OUTPUT\n";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
std::string in_file(argv[1]);
|
||||
std::string out_file(argv[2]);
|
||||
|
||||
absl::Status status = JsonnetMain(in_file, out_file);
|
||||
if (!status.ok()) {
|
||||
LOG(ERROR) << "Failed: " << status.ToString();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
55
oss-internship-2020/jsonnet/headers/jsonnet_base_sandbox.h
Normal file
55
oss-internship-2020/jsonnet/headers/jsonnet_base_sandbox.h
Normal file
|
@ -0,0 +1,55 @@
|
|||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// 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 JSONNET_BASE_SANDBOX_H_
|
||||
#define JSONNET_BASE_SANDBOX_H_
|
||||
|
||||
#include <libgen.h>
|
||||
#include <syscall.h>
|
||||
|
||||
#include "jsonnet_sapi.sapi.h" // NOLINT(build/include)
|
||||
#include "sandboxed_api/util/flag.h"
|
||||
#include "sandboxed_api/transaction.h"
|
||||
#include "sandboxed_api/vars.h"
|
||||
|
||||
class JsonnetBaseSandbox : public JsonnetSandbox {
|
||||
public:
|
||||
explicit JsonnetBaseSandbox(std::string in_file, std::string out_file)
|
||||
: in_file_(in_file), out_file_(out_file) {}
|
||||
|
||||
std::unique_ptr<sandbox2::Policy> ModifyPolicy(
|
||||
sandbox2::PolicyBuilder *) override {
|
||||
return sandbox2::PolicyBuilder()
|
||||
.AllowStaticStartup()
|
||||
.AllowOpen()
|
||||
.AllowRead()
|
||||
.AllowWrite()
|
||||
.AllowStat()
|
||||
.AllowSystemMalloc()
|
||||
.AllowExit()
|
||||
.AllowSyscalls({
|
||||
__NR_futex,
|
||||
__NR_close,
|
||||
})
|
||||
.AddDirectoryAt(dirname(&out_file_[0]), "/output", /*is_ro=*/false)
|
||||
.AddDirectoryAt(dirname(&in_file_[0]), "/input", true)
|
||||
.BuildOrDie();
|
||||
}
|
||||
|
||||
private:
|
||||
std::string in_file_;
|
||||
std::string out_file_;
|
||||
};
|
||||
|
||||
#endif // JSONNET_BASE_SANDBOX_H_
|
|
@ -0,0 +1,38 @@
|
|||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// 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 JSNONNET_BASE_TRANSACTION_H_
|
||||
#define JSNONNET_BASE_TRANSACTION_H_
|
||||
|
||||
#include "jsonnet_base_sandbox.h" // NOLINT(build/include)
|
||||
|
||||
class JsonnetTransaction : public sapi::Transaction {
|
||||
public:
|
||||
JsonnetTransaction(std::string in_file, std::string out_file)
|
||||
: sapi::Transaction(
|
||||
std::make_unique<JsonnetBaseSandbox>(in_file, out_file)),
|
||||
in_file_(in_file),
|
||||
out_file_(out_file) {
|
||||
sapi::Transaction::set_retry_count(0); // Try once, no retries
|
||||
sapi::Transaction::SetTimeLimit(0); // Infinite time limit
|
||||
}
|
||||
|
||||
private:
|
||||
std::string in_file_;
|
||||
std::string out_file_;
|
||||
|
||||
absl::Status Main() override;
|
||||
};
|
||||
|
||||
#endif // JSNONNET_BASE_TRANSACTION_H_
|
57
oss-internship-2020/jsonnet/headers/jsonnet_tests.h
Normal file
57
oss-internship-2020/jsonnet/headers/jsonnet_tests.h
Normal file
|
@ -0,0 +1,57 @@
|
|||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// 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 JSONNET_TESTS_H_
|
||||
#define JSONNET_TESTS_H_
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <streambuf>
|
||||
#include <string>
|
||||
|
||||
#include "jsonnet_base_sandbox.h" // NOLINT(build/include)
|
||||
#include "jsonnet_sapi.sapi.h" // NOLINT(build/include)
|
||||
#include "gtest/gtest.h"
|
||||
#include "sandboxed_api/util/flag.h"
|
||||
#include "sandboxed_api/sandbox2/util/path.h"
|
||||
#include "sandboxed_api/util/status_matchers.h"
|
||||
|
||||
class JsonnetTestHelper {
|
||||
protected:
|
||||
enum Evaluation { kBase, kMultipleFiles, kYamlStream };
|
||||
|
||||
void TestSetUp();
|
||||
void TestTearDown();
|
||||
|
||||
void ReadInput(const char* filename);
|
||||
void EvaluateJsonnetCode(Evaluation type, bool expected_correct);
|
||||
void WriteOutput(const char* filename_or_directory, Evaluation type);
|
||||
std::string ReadOutput(const char* filename);
|
||||
|
||||
std::unique_ptr<JsonnetBaseSandbox> sandbox_;
|
||||
std::unique_ptr<JsonnetApi> api_;
|
||||
std::unique_ptr<sapi::v::RemotePtr> input_;
|
||||
std::unique_ptr<sapi::v::RemotePtr> output_;
|
||||
std::unique_ptr<sapi::v::RemotePtr> vm_;
|
||||
|
||||
std::string input_filename_in_sandboxee_;
|
||||
bool jsonnet_vm_was_used_;
|
||||
bool input_was_read_;
|
||||
};
|
||||
|
||||
#endif // JSONNET_TESTS_H_
|
1
oss-internship-2020/jsonnet/jsonnet
Submodule
1
oss-internship-2020/jsonnet/jsonnet
Submodule
|
@ -0,0 +1 @@
|
|||
Subproject commit 3e25595d5c4acd32a1c3951a57471986b90d3bad
|
664
oss-internship-2020/jsonnet/jsonnet.patch
Normal file
664
oss-internship-2020/jsonnet/jsonnet.patch
Normal file
|
@ -0,0 +1,664 @@
|
|||
--- jsonnet.cpp 2020-09-09 12:15:33.687539042 +0000
|
||||
+++ write_helper.cpp 2020-09-25 15:38:37.317147682 +0000
|
||||
@@ -14,559 +14,125 @@
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
-#include <cassert>
|
||||
-#include <cstdlib>
|
||||
-#include <cstring>
|
||||
+// We need two functions defined in jsonnet.cpp file, used for writing output
|
||||
+// (multiple files and yaml streams) -- with minor changes (e.x. return type).
|
||||
|
||||
-#include <exception>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
-#include <list>
|
||||
#include <map>
|
||||
-#include <sstream>
|
||||
-#include <string>
|
||||
#include <vector>
|
||||
|
||||
-#include "utils.h"
|
||||
+#include "jsonnet_helper.h" // NOLINT(build/include)
|
||||
|
||||
-extern "C" {
|
||||
-#include <libjsonnet.h>
|
||||
-}
|
||||
-
|
||||
-#ifdef _WIN32
|
||||
-const char PATH_SEP = ';';
|
||||
-#else
|
||||
-const char PATH_SEP = ':';
|
||||
-#endif
|
||||
-
|
||||
-void version(std::ostream &o)
|
||||
-{
|
||||
- o << "Jsonnet commandline interpreter " << jsonnet_version() << std::endl;
|
||||
-}
|
||||
-
|
||||
-void usage(std::ostream &o)
|
||||
-{
|
||||
- version(o);
|
||||
- o << "\n";
|
||||
- o << "jsonnet {<option>} <filename>\n";
|
||||
- o << "\n";
|
||||
- o << "Available options:\n";
|
||||
- o << " -h / --help This message\n";
|
||||
- o << " -e / --exec Treat filename as code\n";
|
||||
- o << " -J / --jpath <dir> Specify an additional library search dir (right-most wins)\n";
|
||||
- o << " -o / --output-file <file> Write to the output file rather than stdout\n";
|
||||
- o << " -m / --multi <dir> Write multiple files to the directory, list files on stdout\n";
|
||||
- o << " -y / --yaml-stream Write output as a YAML stream of JSON documents\n";
|
||||
- o << " -S / --string Expect a string, manifest as plain text\n";
|
||||
- o << " -s / --max-stack <n> Number of allowed stack frames\n";
|
||||
- o << " -t / --max-trace <n> Max length of stack trace before cropping\n";
|
||||
- o << " --gc-min-objects <n> Do not run garbage collector until this many\n";
|
||||
- o << " --gc-growth-trigger <n> Run garbage collector after this amount of object growth\n";
|
||||
- o << " --version Print version\n";
|
||||
- o << "Available options for specifying values of 'external' variables:\n";
|
||||
- o << "Provide the value as a string:\n";
|
||||
- o << " -V / --ext-str <var>[=<val>] If <val> is omitted, get from environment var <var>\n";
|
||||
- o << " --ext-str-file <var>=<file> Read the string from the file\n";
|
||||
- o << "Provide a value as Jsonnet code:\n";
|
||||
- o << " --ext-code <var>[=<code>] If <code> is omitted, get from environment var <var>\n";
|
||||
- o << " --ext-code-file <var>=<file> Read the code from the file\n";
|
||||
- o << "Available options for specifying values of 'top-level arguments':\n";
|
||||
- o << "Provide the value as a string:\n";
|
||||
- o << " -A / --tla-str <var>[=<val>] If <val> is omitted, get from environment var <var>\n";
|
||||
- o << " --tla-str-file <var>=<file> Read the string from the file\n";
|
||||
- o << "Provide a value as Jsonnet code:\n";
|
||||
- o << " --tla-code <var>[=<code>] If <code> is omitted, get from environment var <var>\n";
|
||||
- o << " --tla-code-file <var>=<file> Read the code from the file\n";
|
||||
- o << "Environment variables:\n";
|
||||
- o << "JSONNET_PATH is a colon (semicolon on Windows) separated list of directories added\n";
|
||||
- o << "in reverse order before the paths specified by --jpath (i.e. left-most wins)\n";
|
||||
- o << "E.g. JSONNET_PATH=a:b jsonnet -J c -J d is equivalent to:\n";
|
||||
- o << "JSONNET_PATH=d:c:a:b jsonnet\n";
|
||||
- o << "jsonnet -J b -J a -J c -J d\n";
|
||||
- o << "\n";
|
||||
- o << "In all cases:\n";
|
||||
- o << "<filename> can be - (stdin)\n";
|
||||
- o << "Multichar options are expanded e.g. -abc becomes -a -b -c.\n";
|
||||
- o << "The -- option suppresses option processing for subsequent arguments.\n";
|
||||
- o << "Note that since filenames and jsonnet programs can begin with -, it is advised to\n";
|
||||
- o << "use -- if the argument is unknown, e.g. jsonnet -- \"$FILENAME\".";
|
||||
- o << std::endl;
|
||||
-}
|
||||
-
|
||||
-/** Class for representing configuration read from command line flags. */
|
||||
-struct JsonnetConfig {
|
||||
- std::vector<std::string> inputFiles;
|
||||
- std::string outputFile;
|
||||
- bool filenameIsCode;
|
||||
-
|
||||
- // EVAL flags
|
||||
- bool evalMulti;
|
||||
- bool evalStream;
|
||||
- std::string evalMultiOutputDir;
|
||||
-
|
||||
- JsonnetConfig()
|
||||
- : filenameIsCode(false),
|
||||
- evalMulti(false),
|
||||
- evalStream(false)
|
||||
- {
|
||||
- }
|
||||
-};
|
||||
-
|
||||
-bool get_var_val(const std::string &var_val, std::string &var, std::string &val)
|
||||
-{
|
||||
- size_t eq_pos = var_val.find_first_of('=', 0);
|
||||
- if (eq_pos == std::string::npos) {
|
||||
- var = var_val;
|
||||
- const char *val_cstr = ::getenv(var.c_str());
|
||||
- if (val_cstr == nullptr) {
|
||||
- std::cerr << "ERROR: environment variable " << var << " was undefined." << std::endl;
|
||||
- return false;
|
||||
- }
|
||||
- val = val_cstr;
|
||||
- } else {
|
||||
- var = var_val.substr(0, eq_pos);
|
||||
- val = var_val.substr(eq_pos + 1, std::string::npos);
|
||||
- }
|
||||
- return true;
|
||||
-}
|
||||
-
|
||||
-bool get_var_file(const std::string &var_file, const std::string &imp, std::string &var, std::string &val)
|
||||
-{
|
||||
- size_t eq_pos = var_file.find_first_of('=', 0);
|
||||
- if (eq_pos == std::string::npos) {
|
||||
- std::cerr << "ERROR: argument not in form <var>=<file> \"" << var_file << "\"."
|
||||
- << std::endl;
|
||||
- return false;
|
||||
- }
|
||||
- var = var_file.substr(0, eq_pos);
|
||||
- const std::string path = var_file.substr(eq_pos + 1, std::string::npos);
|
||||
-
|
||||
- size_t b, e;
|
||||
- val.erase().append(imp).append(" @'");
|
||||
- // duplicate all the single quotes in @path to make a quoted string
|
||||
- for (b = 0; (e = path.find("'", b)) != std::string::npos; b = e + 1) {
|
||||
- val.append(path.substr(b, e - b + 1)).push_back('\'');
|
||||
+/** Writes output files for multiple file output */
|
||||
+bool write_multi_output_files(char *output, const std::string &output_dir, bool show_output_file_names) {
|
||||
+ // If multiple file output is used, then iterate over each string from
|
||||
+ // the sequence of strings returned by jsonnet_evaluate_snippet_multi,
|
||||
+ // construct pairs of filename and content, and write each output file.
|
||||
+ std::map<std::string, std::string> r;
|
||||
+ for (const char *c = output; *c != '\0';) {
|
||||
+ const char *filename = c;
|
||||
+ const char *c2 = c;
|
||||
+ while (*c2 != '\0') ++c2;
|
||||
+ ++c2;
|
||||
+ const char *json = c2;
|
||||
+ while (*c2 != '\0') ++c2;
|
||||
+ ++c2;
|
||||
+ c = c2;
|
||||
+ r[filename] = json;
|
||||
+ }
|
||||
+
|
||||
+ std::ostream *o;
|
||||
+ std::ofstream f;
|
||||
+
|
||||
+ o = &std::cout;
|
||||
+
|
||||
+ for (const auto &pair : r) {
|
||||
+ const std::string &new_content = pair.second;
|
||||
+ const std::string &filename = output_dir + pair.first;
|
||||
+ if (show_output_file_names) {
|
||||
+ (*o) << filename << std::endl;
|
||||
}
|
||||
- val.append(path.substr(b)).push_back('\'');
|
||||
-
|
||||
- return true;
|
||||
-}
|
||||
-
|
||||
-enum ArgStatus {
|
||||
- ARG_CONTINUE,
|
||||
- ARG_SUCCESS,
|
||||
- ARG_FAILURE,
|
||||
-};
|
||||
-
|
||||
-/** Parse the command line arguments, configuring the Jsonnet VM context and
|
||||
- * populating the JsonnetConfig.
|
||||
- */
|
||||
-static ArgStatus process_args(int argc, const char **argv, JsonnetConfig *config, JsonnetVm *vm)
|
||||
-{
|
||||
- auto args = simplify_args(argc, argv);
|
||||
- std::vector<std::string> remaining_args;
|
||||
-
|
||||
- unsigned i = 0;
|
||||
-
|
||||
- for (; i < args.size(); ++i) {
|
||||
- const std::string &arg = args[i];
|
||||
- if (arg == "-h" || arg == "--help") {
|
||||
- usage(std::cout);
|
||||
- return ARG_SUCCESS;
|
||||
- } else if (arg == "-v" || arg == "--version") {
|
||||
- version(std::cout);
|
||||
- return ARG_SUCCESS;
|
||||
- } else if (arg == "-e" || arg == "--exec") {
|
||||
- config->filenameIsCode = true;
|
||||
- } else if (arg == "-o" || arg == "--output-file") {
|
||||
- std::string output_file = next_arg(i, args);
|
||||
- if (output_file.length() == 0) {
|
||||
- std::cerr << "ERROR: -o argument was empty string" << std::endl;
|
||||
- return ARG_FAILURE;
|
||||
- }
|
||||
- config->outputFile = output_file;
|
||||
- } else if (arg == "--") {
|
||||
- // All subsequent args are not options.
|
||||
- while ((++i) < args.size())
|
||||
- remaining_args.push_back(args[i]);
|
||||
- break;
|
||||
- } else if (arg == "-s" || arg == "--max-stack") {
|
||||
- long l = strtol_check(next_arg(i, args));
|
||||
- if (l < 1) {
|
||||
- std::cerr << "ERROR: invalid --max-stack value: " << l << std::endl;
|
||||
- return ARG_FAILURE;
|
||||
- }
|
||||
- jsonnet_max_stack(vm, l);
|
||||
- } else if (arg == "-J" || arg == "--jpath") {
|
||||
- std::string dir = next_arg(i, args);
|
||||
- if (dir.length() == 0) {
|
||||
- std::cerr << "ERROR: -J argument was empty string" << std::endl;
|
||||
- return ARG_FAILURE;
|
||||
- }
|
||||
- if (dir[dir.length() - 1] != '/') {
|
||||
- dir += '/';
|
||||
- }
|
||||
- jsonnet_jpath_add(vm, dir.c_str());
|
||||
- } else if (arg == "-V" || arg == "--ext-str") {
|
||||
- std::string var, val;
|
||||
- if (!get_var_val(next_arg(i, args), var, val))
|
||||
- return ARG_FAILURE;
|
||||
- jsonnet_ext_var(vm, var.c_str(), val.c_str());
|
||||
- } else if (arg == "-E" || arg == "--var" || arg == "--env") {
|
||||
- // TODO(dcunnin): Delete this in a future release.
|
||||
- std::cerr << "WARNING: jsonnet eval -E, --var and --env are deprecated,"
|
||||
- << " please use -V or --ext-str." << std::endl;
|
||||
- std::string var, val;
|
||||
- if (!get_var_val(next_arg(i, args), var, val))
|
||||
- return ARG_FAILURE;
|
||||
- jsonnet_ext_var(vm, var.c_str(), val.c_str());
|
||||
- } else if (arg == "--ext-str-file") {
|
||||
- std::string var, val;
|
||||
- if (!get_var_file(next_arg(i, args), "importstr", var, val))
|
||||
- return ARG_FAILURE;
|
||||
- jsonnet_ext_code(vm, var.c_str(), val.c_str());
|
||||
- } else if (arg == "-F" || arg == "--file") {
|
||||
- // TODO(dcunnin): Delete this in a future release.
|
||||
- std::cerr << "WARNING: jsonnet eval -F and --file are deprecated,"
|
||||
- << " please use --ext-str-file." << std::endl;
|
||||
- std::string var, val;
|
||||
- if (!get_var_file(next_arg(i, args), "importstr", var, val))
|
||||
- return ARG_FAILURE;
|
||||
- jsonnet_ext_code(vm, var.c_str(), val.c_str());
|
||||
- } else if (arg == "--ext-code") {
|
||||
- std::string var, val;
|
||||
- if (!get_var_val(next_arg(i, args), var, val))
|
||||
- return ARG_FAILURE;
|
||||
- jsonnet_ext_code(vm, var.c_str(), val.c_str());
|
||||
- } else if (arg == "--code-var" || arg == "--code-env") {
|
||||
- // TODO(dcunnin): Delete this in a future release.
|
||||
- std::cerr << "WARNING: jsonnet eval --code-var and --code-env are deprecated,"
|
||||
- << " please use --ext-code." << std::endl;
|
||||
- std::string var, val;
|
||||
- if (!get_var_val(next_arg(i, args), var, val))
|
||||
- return ARG_FAILURE;
|
||||
- jsonnet_ext_code(vm, var.c_str(), val.c_str());
|
||||
- } else if (arg == "--ext-code-file") {
|
||||
- std::string var, val;
|
||||
- if (!get_var_file(next_arg(i, args), "import", var, val))
|
||||
- return ARG_FAILURE;
|
||||
- jsonnet_ext_code(vm, var.c_str(), val.c_str());
|
||||
- } else if (arg == "--code-file") {
|
||||
- // TODO(dcunnin): Delete this in a future release.
|
||||
- std::cerr << "WARNING: jsonnet eval --code-file is deprecated,"
|
||||
- << " please use --ext-code-file." << std::endl;
|
||||
- std::string var, val;
|
||||
- if (!get_var_file(next_arg(i, args), "import", var, val))
|
||||
- return ARG_FAILURE;
|
||||
- jsonnet_ext_code(vm, var.c_str(), val.c_str());
|
||||
- } else if (arg == "-A" || arg == "--tla-str") {
|
||||
- std::string var, val;
|
||||
- if (!get_var_val(next_arg(i, args), var, val))
|
||||
- return ARG_FAILURE;
|
||||
- jsonnet_tla_var(vm, var.c_str(), val.c_str());
|
||||
- } else if (arg == "--tla-str-file") {
|
||||
- std::string var, val;
|
||||
- if (!get_var_file(next_arg(i, args), "importstr", var, val))
|
||||
- return ARG_FAILURE;
|
||||
- jsonnet_tla_code(vm, var.c_str(), val.c_str());
|
||||
- } else if (arg == "--tla-code") {
|
||||
- std::string var, val;
|
||||
- if (!get_var_val(next_arg(i, args), var, val))
|
||||
- return ARG_FAILURE;
|
||||
- jsonnet_tla_code(vm, var.c_str(), val.c_str());
|
||||
- } else if (arg == "--tla-code-file") {
|
||||
- std::string var, val;
|
||||
- if (!get_var_file(next_arg(i, args), "import", var, val))
|
||||
- return ARG_FAILURE;
|
||||
- jsonnet_tla_code(vm, var.c_str(), val.c_str());
|
||||
-
|
||||
- } else if (arg == "--gc-min-objects") {
|
||||
- long l = strtol_check(next_arg(i, args));
|
||||
- if (l < 0) {
|
||||
- std::cerr << "ERROR: invalid --gc-min-objects value: " << l << std::endl;
|
||||
- return ARG_FAILURE;
|
||||
- }
|
||||
- jsonnet_gc_min_objects(vm, l);
|
||||
- } else if (arg == "-t" || arg == "--max-trace") {
|
||||
- long l = strtol_check(next_arg(i, args));
|
||||
- if (l < 0) {
|
||||
- std::cerr << "ERROR: invalid --max-trace value: " << l << std::endl;
|
||||
- return ARG_FAILURE;
|
||||
- }
|
||||
- jsonnet_max_trace(vm, l);
|
||||
- } else if (arg == "--gc-growth-trigger") {
|
||||
- std::string num = next_arg(i, args);
|
||||
- char *ep;
|
||||
- double v = std::strtod(num.c_str(), &ep);
|
||||
- if (*ep != '\0' || num.length() == 0) {
|
||||
- std::cerr << "ERROR: invalid number \"" << num << "\"" << std::endl;
|
||||
- return ARG_FAILURE;
|
||||
- }
|
||||
- if (v < 0) {
|
||||
- std::cerr << "ERROR: invalid --gc-growth-trigger \"" << num << "\""
|
||||
- << std::endl;
|
||||
- return ARG_FAILURE;
|
||||
- }
|
||||
- jsonnet_gc_growth_trigger(vm, v);
|
||||
- } else if (arg == "-m" || arg == "--multi") {
|
||||
- config->evalMulti = true;
|
||||
- std::string output_dir = next_arg(i, args);
|
||||
- if (output_dir.length() == 0) {
|
||||
- std::cerr << "ERROR: -m argument was empty string" << std::endl;
|
||||
- return ARG_FAILURE;
|
||||
- }
|
||||
- if (output_dir[output_dir.length() - 1] != '/') {
|
||||
- output_dir += '/';
|
||||
- }
|
||||
- config->evalMultiOutputDir = output_dir;
|
||||
- } else if (arg == "-y" || arg == "--yaml-stream") {
|
||||
- config->evalStream = true;
|
||||
- } else if (arg == "-S" || arg == "--string") {
|
||||
- jsonnet_string_output(vm, 1);
|
||||
- } else if (arg.length() > 1 && arg[0] == '-') {
|
||||
- std::cerr << "ERROR: unrecognized argument: " << arg << std::endl;
|
||||
- return ARG_FAILURE;
|
||||
- } else {
|
||||
- remaining_args.push_back(args[i]);
|
||||
+ {
|
||||
+ std::ifstream exists(filename.c_str());
|
||||
+ if (exists.good()) {
|
||||
+ std::string existing_content;
|
||||
+ existing_content.assign(std::istreambuf_iterator<char>(exists),
|
||||
+ std::istreambuf_iterator<char>());
|
||||
+ if (existing_content == new_content) {
|
||||
+ // Do not bump the timestamp on the file if its content is
|
||||
+ // the same. This may trigger other tools (e.g. make) to do
|
||||
+ // unnecessary work.
|
||||
+ continue;
|
||||
}
|
||||
+ }
|
||||
}
|
||||
-
|
||||
- const char *want = config->filenameIsCode ? "code" : "filename";
|
||||
- if (remaining_args.size() == 0) {
|
||||
- std::cerr << "ERROR: must give " << want << "\n" << std::endl;
|
||||
- usage(std::cerr);
|
||||
- return ARG_FAILURE;
|
||||
- }
|
||||
-
|
||||
- if (remaining_args.size() > 1) {
|
||||
- std::string filename = remaining_args[0];
|
||||
- std::cerr << "ERROR: only one " << want << " is allowed\n" << std::endl;
|
||||
- return ARG_FAILURE;
|
||||
- }
|
||||
- config->inputFiles = remaining_args;
|
||||
- return ARG_CONTINUE;
|
||||
-}
|
||||
-
|
||||
-/** Writes output files for multiple file output */
|
||||
-static bool write_multi_output_files(JsonnetVm *vm, char *output, const std::string &output_dir,
|
||||
- const std::string &output_file)
|
||||
-{
|
||||
- // If multiple file output is used, then iterate over each string from
|
||||
- // the sequence of strings returned by jsonnet_evaluate_snippet_multi,
|
||||
- // construct pairs of filename and content, and write each output file.
|
||||
- std::map<std::string, std::string> r;
|
||||
- for (const char *c = output; *c != '\0';) {
|
||||
- const char *filename = c;
|
||||
- const char *c2 = c;
|
||||
- while (*c2 != '\0')
|
||||
- ++c2;
|
||||
- ++c2;
|
||||
- const char *json = c2;
|
||||
- while (*c2 != '\0')
|
||||
- ++c2;
|
||||
- ++c2;
|
||||
- c = c2;
|
||||
- r[filename] = json;
|
||||
- }
|
||||
- jsonnet_realloc(vm, output, 0);
|
||||
-
|
||||
- std::ostream *o;
|
||||
std::ofstream f;
|
||||
-
|
||||
- if (output_file.empty()) {
|
||||
- o = &std::cout;
|
||||
- } else {
|
||||
- f.open(output_file.c_str());
|
||||
- if (!f.good()) {
|
||||
- std::string msg = "Writing to output file: " + output_file;
|
||||
- perror(msg.c_str());
|
||||
- return false;
|
||||
- }
|
||||
- o = &f;
|
||||
+ f.open(filename.c_str());
|
||||
+ if (!f.good()) {
|
||||
+ std::string msg = "Opening output file: " + filename;
|
||||
+ perror(msg.c_str());
|
||||
+ return false;
|
||||
+ }
|
||||
+ f << new_content;
|
||||
+ f.close();
|
||||
+ if (!f.good()) {
|
||||
+ std::string msg = "Writing to output file: " + filename;
|
||||
+ perror(msg.c_str());
|
||||
+ return false;
|
||||
}
|
||||
+ }
|
||||
|
||||
- for (const auto &pair : r) {
|
||||
- const std::string &new_content = pair.second;
|
||||
- const std::string &filename = output_dir + pair.first;
|
||||
- (*o) << filename << std::endl;
|
||||
- {
|
||||
- std::ifstream exists(filename.c_str());
|
||||
- if (exists.good()) {
|
||||
- std::string existing_content;
|
||||
- existing_content.assign(std::istreambuf_iterator<char>(exists),
|
||||
- std::istreambuf_iterator<char>());
|
||||
- if (existing_content == new_content) {
|
||||
- // Do not bump the timestamp on the file if its content is
|
||||
- // the same. This may trigger other tools (e.g. make) to do
|
||||
- // unnecessary work.
|
||||
- continue;
|
||||
- }
|
||||
- }
|
||||
- }
|
||||
- std::ofstream f;
|
||||
- f.open(filename.c_str());
|
||||
- if (!f.good()) {
|
||||
- std::string msg = "Opening output file: " + filename;
|
||||
- perror(msg.c_str());
|
||||
- return false;
|
||||
- }
|
||||
- f << new_content;
|
||||
- f.close();
|
||||
- if (!f.good()) {
|
||||
- std::string msg = "Writing to output file: " + filename;
|
||||
- perror(msg.c_str());
|
||||
- return false;
|
||||
- }
|
||||
- }
|
||||
+ std::cout.flush();
|
||||
|
||||
- if (output_file.empty()) {
|
||||
- std::cout.flush();
|
||||
- } else {
|
||||
- f.close();
|
||||
- if (!f.good()) {
|
||||
- std::string msg = "Writing to output file: " + output_file;
|
||||
- perror(msg.c_str());
|
||||
- return false;
|
||||
- }
|
||||
- }
|
||||
- return true;
|
||||
+ return true;
|
||||
}
|
||||
|
||||
/** Writes output files for YAML stream output */
|
||||
-static bool write_output_stream(JsonnetVm *vm, char *output, const std::string &output_file)
|
||||
-{
|
||||
- std::ostream *o;
|
||||
- std::ofstream f;
|
||||
-
|
||||
- if (output_file.empty()) {
|
||||
- o = &std::cout;
|
||||
- } else {
|
||||
- f.open(output_file.c_str());
|
||||
- if (!f.good()) {
|
||||
- std::string msg = "Writing to output file: " + output_file;
|
||||
- perror(msg.c_str());
|
||||
- return false;
|
||||
- }
|
||||
- o = &f;
|
||||
- }
|
||||
-
|
||||
- // If YAML stream output is used, then iterate over each string from
|
||||
- // the sequence of strings returned by jsonnet_evaluate_snippet_stream,
|
||||
- // and add the --- and ... as defined by the YAML spec.
|
||||
- std::vector<std::string> r;
|
||||
- for (const char *c = output; *c != '\0';) {
|
||||
- const char *json = c;
|
||||
- while (*c != '\0')
|
||||
- ++c;
|
||||
- ++c;
|
||||
- r.emplace_back(json);
|
||||
- }
|
||||
- jsonnet_realloc(vm, output, 0);
|
||||
- for (const auto &str : r) {
|
||||
- (*o) << "---\n";
|
||||
- (*o) << str;
|
||||
- }
|
||||
- if (r.size() > 0)
|
||||
- (*o) << "...\n";
|
||||
- o->flush();
|
||||
-
|
||||
- if (output_file.empty()) {
|
||||
- std::cout.flush();
|
||||
- } else {
|
||||
- f.close();
|
||||
- if (!f.good()) {
|
||||
- std::string msg = "Writing to output file: " + output_file;
|
||||
- perror(msg.c_str());
|
||||
- return false;
|
||||
- }
|
||||
+bool write_output_stream(char *output, const std::string &output_file) {
|
||||
+ std::ostream *o;
|
||||
+ std::ofstream f;
|
||||
+
|
||||
+ if (output_file.empty()) {
|
||||
+ o = &std::cout;
|
||||
+ } else {
|
||||
+ f.open(output_file.c_str());
|
||||
+ if (!f.good()) {
|
||||
+ std::string msg = "Writing to output file: " + output_file;
|
||||
+ perror(msg.c_str());
|
||||
+ return false;
|
||||
+ }
|
||||
+ o = &f;
|
||||
+ }
|
||||
+
|
||||
+ // If YAML stream output is used, then iterate over each string from
|
||||
+ // the sequence of strings returned by jsonnet_evaluate_snippet_stream,
|
||||
+ // and add the --- and ... as defined by the YAML spec.
|
||||
+ std::vector<std::string> r;
|
||||
+ for (const char *c = output; *c != '\0';) {
|
||||
+ const char *json = c;
|
||||
+ while (*c != '\0') ++c;
|
||||
+ ++c;
|
||||
+ r.emplace_back(json);
|
||||
+ }
|
||||
+
|
||||
+ for (const auto &str : r) {
|
||||
+ (*o) << "---\n";
|
||||
+ (*o) << str;
|
||||
+ }
|
||||
+ if (r.size() > 0) (*o) << "...\n";
|
||||
+ o->flush();
|
||||
+
|
||||
+ if (output_file.empty()) {
|
||||
+ std::cout.flush();
|
||||
+ } else {
|
||||
+ f.close();
|
||||
+ if (!f.good()) {
|
||||
+ std::string msg = "Writing to output file: " + output_file;
|
||||
+ perror(msg.c_str());
|
||||
+ return false;
|
||||
}
|
||||
+ }
|
||||
|
||||
- return true;
|
||||
-}
|
||||
-
|
||||
-int main(int argc, const char **argv)
|
||||
-{
|
||||
- try {
|
||||
- JsonnetVm *vm = jsonnet_make();
|
||||
- JsonnetConfig config;
|
||||
- if (const char *jsonnet_path_env = getenv("JSONNET_PATH")) {
|
||||
- std::list<std::string> jpath;
|
||||
- std::istringstream iss(jsonnet_path_env);
|
||||
- std::string path;
|
||||
- while (std::getline(iss, path, PATH_SEP)) {
|
||||
- jpath.push_front(path);
|
||||
- }
|
||||
- for (const std::string &path : jpath) {
|
||||
- jsonnet_jpath_add(vm, path.c_str());
|
||||
- }
|
||||
- }
|
||||
- ArgStatus arg_status = process_args(argc, argv, &config, vm);
|
||||
- if (arg_status != ARG_CONTINUE) {
|
||||
- jsonnet_destroy(vm);
|
||||
- return arg_status == ARG_SUCCESS ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||
- }
|
||||
-
|
||||
- // Evaluate input Jsonnet and handle any errors from Jsonnet VM.
|
||||
- int error;
|
||||
- char *output;
|
||||
- assert(config.inputFiles.size() == 1);
|
||||
-
|
||||
- // Read input file.
|
||||
- std::string input;
|
||||
- if (!read_input(config.filenameIsCode, &config.inputFiles[0], &input)) {
|
||||
- jsonnet_destroy(vm);
|
||||
- return EXIT_FAILURE;
|
||||
- }
|
||||
-
|
||||
- if (config.evalMulti) {
|
||||
- output = jsonnet_evaluate_snippet_multi(
|
||||
- vm, config.inputFiles[0].c_str(), input.c_str(), &error);
|
||||
- } else if (config.evalStream) {
|
||||
- output = jsonnet_evaluate_snippet_stream(
|
||||
- vm, config.inputFiles[0].c_str(), input.c_str(), &error);
|
||||
- } else {
|
||||
- output = jsonnet_evaluate_snippet(
|
||||
- vm, config.inputFiles[0].c_str(), input.c_str(), &error);
|
||||
- }
|
||||
-
|
||||
- if (error) {
|
||||
- std::cerr << output;
|
||||
- jsonnet_realloc(vm, output, 0);
|
||||
- jsonnet_destroy(vm);
|
||||
- return EXIT_FAILURE;
|
||||
- }
|
||||
-
|
||||
- // Write output JSON.
|
||||
- if (config.evalMulti) {
|
||||
- if (!write_multi_output_files(
|
||||
- vm, output, config.evalMultiOutputDir, config.outputFile)) {
|
||||
- jsonnet_destroy(vm);
|
||||
- return EXIT_FAILURE;
|
||||
- }
|
||||
- } else if (config.evalStream) {
|
||||
- if (!write_output_stream(vm, output, config.outputFile)) {
|
||||
- jsonnet_destroy(vm);
|
||||
- return EXIT_FAILURE;
|
||||
- }
|
||||
- } else {
|
||||
- bool successful = write_output_file(output, config.outputFile);
|
||||
- jsonnet_realloc(vm, output, 0);
|
||||
- if (!successful) {
|
||||
- jsonnet_destroy(vm);
|
||||
- return EXIT_FAILURE;
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- jsonnet_destroy(vm);
|
||||
- return EXIT_SUCCESS;
|
||||
-
|
||||
- } catch (const std::bad_alloc &) {
|
||||
- // Avoid further allocation attempts
|
||||
- fputs("Internal out-of-memory error (please report this)\n", stderr);
|
||||
- } catch (const std::exception &e) {
|
||||
- std::cerr << "Internal error (please report this): " << e.what() << std::endl;
|
||||
- } catch (...) {
|
||||
- std::cerr << "An unknown exception occurred (please report this)." << std::endl;
|
||||
- }
|
||||
- return EXIT_FAILURE;
|
||||
+ return true;
|
||||
}
|
76
oss-internship-2020/jsonnet/jsonnet_helper.cc
Normal file
76
oss-internship-2020/jsonnet/jsonnet_helper.cc
Normal file
|
@ -0,0 +1,76 @@
|
|||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// 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 "jsonnet_helper.h" // NOLINT(build/include)
|
||||
|
||||
#include <cstring>
|
||||
|
||||
struct JsonnetVm* c_jsonnet_make(void) {
|
||||
return jsonnet_make();
|
||||
}
|
||||
|
||||
void c_jsonnet_destroy(struct JsonnetVm* vm) { return jsonnet_destroy(vm); }
|
||||
|
||||
char* c_jsonnet_evaluate_snippet(struct JsonnetVm* vm, const char* filename,
|
||||
char* snippet, int* error) {
|
||||
return jsonnet_evaluate_snippet(vm, filename, snippet, error);
|
||||
}
|
||||
|
||||
char* c_jsonnet_evaluate_snippet_multi(struct JsonnetVm* vm,
|
||||
const char* filename,
|
||||
const char* snippet, int* error) {
|
||||
return jsonnet_evaluate_snippet_multi(vm, filename, snippet, error);
|
||||
}
|
||||
|
||||
char* c_jsonnet_evaluate_snippet_stream(struct JsonnetVm* vm,
|
||||
const char* filename,
|
||||
const char* snippet, int* error) {
|
||||
return jsonnet_evaluate_snippet_stream(vm, filename, snippet, error);
|
||||
}
|
||||
|
||||
char* c_read_input(bool filename_is_code, const char* filename) {
|
||||
std::string s_filename(filename);
|
||||
std::string s_input;
|
||||
bool check = read_input(filename_is_code, &s_filename, &s_input);
|
||||
char* c_input = strdup(s_input.c_str());
|
||||
if (check) return c_input;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void c_free_input(char* input) { free(input); }
|
||||
|
||||
bool c_write_output_file(const char* output, const char* output_file) {
|
||||
std::string s_output_file(output_file);
|
||||
return write_output_file(output, s_output_file);
|
||||
}
|
||||
|
||||
bool c_write_multi_output_files(char* output, char* output_dir,
|
||||
bool show_output_file_names) {
|
||||
std::string s_output_dir(output_dir);
|
||||
return write_multi_output_files(output, s_output_dir, show_output_file_names);
|
||||
}
|
||||
|
||||
bool c_write_output_stream(char* output, char* output_file) {
|
||||
std::string s_output_file(output_file);
|
||||
return write_output_stream(output, s_output_file);
|
||||
}
|
||||
|
||||
char* c_jsonnet_realloc(struct JsonnetVm* vm, char* str, size_t sz) {
|
||||
return jsonnet_realloc(vm, str, sz);
|
||||
}
|
||||
|
||||
char* c_jsonnet_fmt_snippet(struct JsonnetVm* vm, const char* filename,
|
||||
const char* snippet, int* error) {
|
||||
return jsonnet_fmt_snippet(vm, filename, snippet, error);
|
||||
}
|
66
oss-internship-2020/jsonnet/jsonnet_helper.h
Normal file
66
oss-internship-2020/jsonnet/jsonnet_helper.h
Normal file
|
@ -0,0 +1,66 @@
|
|||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// 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 JSONNET_HELPER_H_
|
||||
#define JSONNET_HELPER_H_
|
||||
|
||||
extern "C" {
|
||||
#include <libjsonnet.h> // NOLINT(build/include)
|
||||
#include <libjsonnet_fmt.h> // NOLINT(build/include)
|
||||
}
|
||||
|
||||
#include "jsonnet/cmd/utils.h" // NOLINT(build/include)
|
||||
|
||||
extern "C" struct JsonnetVm* c_jsonnet_make(void);
|
||||
|
||||
extern "C" void c_jsonnet_destroy(struct JsonnetVm* vm);
|
||||
|
||||
extern "C" char* c_jsonnet_evaluate_snippet(struct JsonnetVm* vm,
|
||||
const char* filename, char* snippet,
|
||||
int* error);
|
||||
|
||||
extern "C" char* c_jsonnet_evaluate_snippet_multi(struct JsonnetVm* vm,
|
||||
const char* filename,
|
||||
const char* snippet,
|
||||
int* error);
|
||||
|
||||
extern "C" char* c_jsonnet_evaluate_snippet_stream(struct JsonnetVm* vm,
|
||||
const char* filename,
|
||||
const char* snippet,
|
||||
int* error);
|
||||
|
||||
extern "C" char* c_read_input(bool filename_is_code, const char* filename);
|
||||
|
||||
extern "C" void c_free_input(char* input);
|
||||
|
||||
extern "C" bool c_write_output_file(const char* output,
|
||||
const char* output_file);
|
||||
|
||||
extern "C" char* c_jsonnet_realloc(struct JsonnetVm* vm, char* str, size_t sz);
|
||||
|
||||
extern "C" bool c_write_multi_output_files(char* output, char* output_dir,
|
||||
bool show_output_file_names);
|
||||
|
||||
bool write_multi_output_files(char* output, const std::string& output_dir,
|
||||
bool show_output_file_names);
|
||||
|
||||
extern "C" bool c_write_output_stream(char* output, char* output_file);
|
||||
|
||||
bool write_output_stream(char* output, const std::string& output_file);
|
||||
|
||||
extern "C" char* c_jsonnet_fmt_snippet(struct JsonnetVm* vm,
|
||||
const char* filename,
|
||||
const char* snippet, int* error);
|
||||
|
||||
#endif // JSONNET_HELPER_H_
|
42
oss-internship-2020/jsonnet/tests/CMakeLists.txt
Normal file
42
oss-internship-2020/jsonnet/tests/CMakeLists.txt
Normal file
|
@ -0,0 +1,42 @@
|
|||
# Copyright 2020 Google LLC
|
||||
#
|
||||
# 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(GoogleTest)
|
||||
|
||||
# We need to prepare convenient directories so the tests will be able to access them
|
||||
file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/tests/tests_input)
|
||||
file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/tests/tests_output)
|
||||
file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/tests/tests_expected_output)
|
||||
|
||||
add_custom_target(test_preparation ALL
|
||||
COMMAND cp ${PROJECT_SOURCE_DIR}/examples/jsonnet_codes/* ${PROJECT_BINARY_DIR}/tests/tests_input
|
||||
COMMAND cp ${PROJECT_SOURCE_DIR}/examples/jsonnet_codes_expected_output/* ${PROJECT_BINARY_DIR}/tests/tests_expected_output
|
||||
)
|
||||
|
||||
add_executable(tests
|
||||
${PROJECT_SOURCE_DIR}/headers/jsonnet_tests.h
|
||||
jsonnet_tests.cc
|
||||
jsonnet_tests_utils.cc
|
||||
)
|
||||
|
||||
target_include_directories(tests PUBLIC
|
||||
${PROJECT_SOURCE_DIR}/headers
|
||||
)
|
||||
|
||||
target_link_libraries(tests
|
||||
jsonnet_sapi sapi::sapi
|
||||
gtest gmock gtest_main
|
||||
)
|
||||
|
||||
gtest_discover_tests(tests)
|
113
oss-internship-2020/jsonnet/tests/jsonnet_tests.cc
Normal file
113
oss-internship-2020/jsonnet/tests/jsonnet_tests.cc
Normal file
|
@ -0,0 +1,113 @@
|
|||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// 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 "jsonnet_tests.h" // NOLINT(build/include)
|
||||
|
||||
namespace {
|
||||
|
||||
class JsonnetTest : public JsonnetTestHelper, public testing::Test {
|
||||
protected:
|
||||
void SetUp() override { TestSetUp(); }
|
||||
void TearDown() override { TestTearDown(); }
|
||||
};
|
||||
|
||||
// Basic test
|
||||
TEST_F(JsonnetTest, SetUp_TearDown) {
|
||||
ASSERT_FALSE(jsonnet_vm_was_used_);
|
||||
ASSERT_FALSE(input_was_read_);
|
||||
}
|
||||
|
||||
// One file evaluation to one file
|
||||
TEST_F(JsonnetTest, One_file_no_dependencies) {
|
||||
constexpr char kInputFile[] = "arith.jsonnet";
|
||||
constexpr char kOutputFile[] = "arith_output";
|
||||
constexpr char kOutputToRead[] = "tests_output/arith_output";
|
||||
constexpr char kOutputToExpect[] = "tests_expected_output/arith.golden";
|
||||
|
||||
Read_input(kInputFile);
|
||||
EvaluateJsonnetCode(kBase, true);
|
||||
WriteOutput(kOutputFile, kBase);
|
||||
|
||||
std::string produced_output = ReadOutput(kOutputToRead);
|
||||
std::string expected_output = ReadOutput(kOutputToExpect);
|
||||
|
||||
ASSERT_STREQ(produced_output.c_str(), expected_output.c_str());
|
||||
}
|
||||
|
||||
// One file evaluating to one file, dependent on some other files
|
||||
TEST_F(JsonnetTest, One_file_some_dependencies) {
|
||||
constexpr char kInputFile[] = "negroni.jsonnet";
|
||||
constexpr char kOutputFile[] = "negroni_output";
|
||||
constexpr char kOutputToRead[] = "tests_output/negroni_output";
|
||||
constexpr char kOutputToExpect[] = "tests_expected_output/negroni.golden";
|
||||
|
||||
ReadInput(kInputFile);
|
||||
EvaluateJsonnetCode(kBase, true);
|
||||
WriteOutput(kOutputFile, kBase);
|
||||
|
||||
const std::string produced_output = Read_output(kOutputToRead);
|
||||
const std::string expected_output = Read_output(kOutputToExpect);
|
||||
|
||||
ASSERT_STREQ(produced_output.c_str(), expected_output.c_str());
|
||||
}
|
||||
|
||||
// One file evaluating to two files
|
||||
TEST_F(JsonnetTest, Multiple_files) {
|
||||
constexpr char kInputFile[] = "multiple_files_example.jsonnet";
|
||||
constexpr char kOutputFile[] = "";
|
||||
constexpr char kOutputToRead1[] = "tests_output/first_file.json";
|
||||
constexpr char kOutputToRead2[] = "tests_output/second_file.json";
|
||||
constexpr char kOutputToExpect1[] = "tests_expected_output/first_file.json";
|
||||
constexpr char kOutputToExpect2[] = "tests_expected_output/second_file.json";
|
||||
|
||||
ReadInput(kInputFile);
|
||||
EvaluateJsonnetCode(kMultipleFiles, true);
|
||||
WriteOutput(kOutputFile, kMultipleFiles);
|
||||
|
||||
const std::string produced_output_1 = ReadOutput(kOutputToRead1);
|
||||
const std::string produced_output_2 = ReadOutput(kOutputToRead2);
|
||||
const std::string expected_output_1 = ReadOutput(kOutputToExpect1);
|
||||
const std::string expected_output_2 = ReadOutput(kOutputToExpect2);
|
||||
|
||||
ASSERT_STREQ(produced_output_1.c_str(), expected_output_1.c_str());
|
||||
ASSERT_STREQ(produced_output_2.c_str(), expected_output_2.c_str());
|
||||
}
|
||||
|
||||
// One file evaluating to yaml stream format
|
||||
TEST_F(JsonnetTest, Yaml_stream) {
|
||||
constexpr char kInputFile[] = "yaml_stream_example.jsonnet";
|
||||
constexpr char kOutputFile[] = "yaml_stream_example.yaml";
|
||||
constexpr char kOutputToRead[] = "tests_output/yaml_stream_example.yaml";
|
||||
constexpr char kOutputToExpect[] =
|
||||
"tests_expected_output/yaml_stream_example.yaml";
|
||||
|
||||
ReadInput(kInputFile);
|
||||
EvaluateJsonnetCode(kYamlStream, true);
|
||||
WriteOutput(kOutputFile, kYamlStream);
|
||||
|
||||
const std::string produced_output = ReadOutput(kOutputToRead);
|
||||
const std::string expected_output = ReadOutput(kOutputToExpect);
|
||||
|
||||
ASSERT_STREQ(produced_output.c_str(), expected_output.c_str());
|
||||
}
|
||||
|
||||
// One file depended on some other files not accessible by the sandbox
|
||||
TEST_F(JsonnetTest, Bad_evaluation) {
|
||||
constexpr char kInputFile[] = "imports.jsonnet";
|
||||
|
||||
ReadInput(kInputFile);
|
||||
EvaluateJsonnetCode(kBase, false);
|
||||
}
|
||||
|
||||
} // namespace
|
160
oss-internship-2020/jsonnet/tests/jsonnet_tests_utils.cc
Normal file
160
oss-internship-2020/jsonnet/tests/jsonnet_tests_utils.cc
Normal file
|
@ -0,0 +1,160 @@
|
|||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// 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 "jsonnet_tests.h" // NOLINT(build/include)
|
||||
|
||||
// Prepares what is needed to perform a test.
|
||||
void JsonnetTestHelper::TestSetUp() {
|
||||
// Get paths to where input and output is stored.
|
||||
char buffer[256];
|
||||
int error = readlink("/proc/self/exe", buffer, 256);
|
||||
ASSERT_GE(error, 0);
|
||||
|
||||
std::pair<absl::string_view, absl::string_view> parts_of_path =
|
||||
sandbox2::file::SplitPath(buffer);
|
||||
absl::string_view binary_path = parts_of_path.first;
|
||||
|
||||
std::string input_path =
|
||||
sandbox2::file::JoinPath(binary_path, "tests_input", "dummy_input");
|
||||
std::string output_path =
|
||||
sandbox2::file::JoinPath(binary_path, "tests_output", "dummy_input");
|
||||
|
||||
// Set up sandbox and api.
|
||||
sandbox_ = absl::make_unique<JsonnetBaseSandbox>(input_path, output_path);
|
||||
ASSERT_THAT(sandbox_->Init(), sapi::IsOk());
|
||||
api_ = absl::make_unique<JsonnetApi>(sandbox_.get());
|
||||
|
||||
// Initialize library's main structure.
|
||||
SAPI_ASSERT_OK_AND_ASSIGN(JsonnetVm * vm_ptr, api_->c_jsonnet_make());
|
||||
vm_ = absl::make_unique<sapi::v::RemotePtr>(vm_ptr);
|
||||
|
||||
jsonnet_vm_was_used_ = false;
|
||||
input_was_read_ = false;
|
||||
}
|
||||
|
||||
// Cleans up after a test.
|
||||
void JsonnetTestHelper::TestTearDown() {
|
||||
if (jsonnet_vm_was_used_) {
|
||||
SAPI_ASSERT_OK_AND_ASSIGN(char* result,
|
||||
api_->c_jsonnet_realloc(vm_.get(), output_.get(), 0));
|
||||
}
|
||||
ASSERT_THAT(api_->c_jsonnet_destroy(vm_.get()), sapi::IsOk());
|
||||
if (input_was_read_) {
|
||||
ASSERT_THAT(api_->c_free_input(input_.get()), sapi::IsOk());
|
||||
}
|
||||
}
|
||||
|
||||
// Reads input from file.
|
||||
void JsonnetTestHelper::ReadInput(const char* filename) {
|
||||
std::string in_file_in_sandboxee(std::string("/input/") +
|
||||
basename(const_cast<char*>(&filename[0])));
|
||||
input_filename_in_sandboxee_ = std::move(in_file_in_sandboxee);
|
||||
sapi::v::ConstCStr in_file_var(input_filename_in_sandboxee_.c_str());
|
||||
|
||||
SAPI_ASSERT_OK_AND_ASSIGN(char* input_ptr,
|
||||
api_->c_read_input(0, in_file_var.PtrBefore()));
|
||||
input_ = absl::make_unique<sapi::v::RemotePtr>(input_ptr);
|
||||
|
||||
input_was_read_ = true;
|
||||
}
|
||||
|
||||
// Evaluates jsonnet code.
|
||||
void JsonnetTestHelper::Evaluate_jsonnet_code(Evaluation type,
|
||||
bool expected_correct) {
|
||||
sapi::v::ConstCStr in_file_var(input_filename_in_sandboxee_.c_str());
|
||||
sapi::v::Int error;
|
||||
char* output_ptr;
|
||||
|
||||
switch (type) {
|
||||
case kBase: {
|
||||
SAPI_ASSERT_OK_AND_ASSIGN(output_ptr, api_->c_jsonnet_evaluate_snippet(
|
||||
vm_.get(), in_file_var.PtrBefore(),
|
||||
input_.get(), error.PtrAfter()));
|
||||
break;
|
||||
}
|
||||
|
||||
case kMultipleFiles: {
|
||||
SAPI_ASSERT_OK_AND_ASSIGN(output_ptr, api_->c_jsonnet_evaluate_snippet_multi(
|
||||
vm_.get(), in_file_var.PtrBefore(),
|
||||
input_.get(), error.PtrAfter()));
|
||||
break;
|
||||
}
|
||||
|
||||
case kYamlStream: {
|
||||
SAPI_ASSERT_OK_AND_ASSIGN(output_ptr, api_->c_jsonnet_evaluate_snippet_stream(
|
||||
vm_.get(), in_file_var.PtrBefore(),
|
||||
input_.get(), error.PtrAfter()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (expected_correct) {
|
||||
ASSERT_THAT(error.GetValue(), testing::Eq(0));
|
||||
} else {
|
||||
ASSERT_THAT(error.GetValue(), testing::Eq(1));
|
||||
}
|
||||
|
||||
output_ = absl::make_unique<sapi::v::RemotePtr>(output_ptr);
|
||||
|
||||
jsonnet_vm_was_used_ = true;
|
||||
}
|
||||
|
||||
// Writes output to file.
|
||||
void JsonnetTestHelper::WriteOutput(const char* filename_or_directory,
|
||||
Evaluation type) {
|
||||
bool success;
|
||||
|
||||
switch (type) {
|
||||
case kBase: {
|
||||
std::string out_file_in_sandboxee(
|
||||
std::string("/output/") +
|
||||
basename(const_cast<char*>(&filename_or_directory[0])));
|
||||
sapi::v::ConstCStr out_file_var(out_file_in_sandboxee.c_str());
|
||||
|
||||
SAPI_ASSERT_OK_AND_ASSIGN(
|
||||
success,
|
||||
api_->c_write_output_file(output_.get(), out_file_var.PtrBefore()));
|
||||
break;
|
||||
}
|
||||
case kMultipleFiles: {
|
||||
std::string out_file_in_sandboxee(std::string("/output/"));
|
||||
sapi::v::ConstCStr out_file_var(out_file_in_sandboxee.c_str());
|
||||
SAPI_ASSERT_OK_AND_ASSIGN(success,
|
||||
api_->c_write_multi_output_files(
|
||||
output_.get(), out_file_var.PtrBefore(), false));
|
||||
break;
|
||||
}
|
||||
|
||||
case kYamlStream: {
|
||||
std::string out_file_in_sandboxee(
|
||||
std::string("/output/") +
|
||||
basename(const_cast<char*>(&filename_or_directory[0])));
|
||||
sapi::v::ConstCStr out_file_var(out_file_in_sandboxee.c_str());
|
||||
SAPI_ASSERT_OK_AND_ASSIGN(
|
||||
success,
|
||||
api_->c_write_output_stream(output_.get(), out_file_var.PtrBefore()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ASSERT_THAT(success, testing::Eq(true));
|
||||
}
|
||||
|
||||
// Reads the output written to a file by library function / expected output
|
||||
std::string JsonnetTestHelper::ReadOutput(const char* filename) {
|
||||
std::ifstream input_stream(filename);
|
||||
std::string contents((std::istreambuf_iterator<char>(input_stream)),
|
||||
std::istreambuf_iterator<char>());
|
||||
return contents;
|
||||
}
|
3
oss-internship-2020/libarchive/.gitignore
vendored
Normal file
3
oss-internship-2020/libarchive/.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
build/
|
||||
.cache
|
||||
.vscode
|
61
oss-internship-2020/libarchive/CMakeLists.txt
Normal file
61
oss-internship-2020/libarchive/CMakeLists.txt
Normal file
|
@ -0,0 +1,61 @@
|
|||
# Copyright 2020 Google LLC
|
||||
#
|
||||
# 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.
|
||||
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
project(libarchive_sapi CXX)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED 17)
|
||||
|
||||
# Build SAPI library
|
||||
#set(SAPI_ROOT "" CACHE PATH "Path to the Sandboxed API source tree")
|
||||
set(SAPI_ROOT "/usr/local/google/home/amedar/internship/sandboxed-api" CACHE PATH "Path to the Sandboxed API source tree")
|
||||
|
||||
include(FetchContent)
|
||||
FetchContent_Declare(
|
||||
libarchive
|
||||
GIT_REPOSITORY https://github.com/libarchive/libarchive
|
||||
PATCH_COMMAND cd libarchive && patch < ${CMAKE_SOURCE_DIR}/patches/header.patch && patch < ${CMAKE_SOURCE_DIR}/patches/archive_virtual.patch
|
||||
)
|
||||
FetchContent_MakeAvailable(libarchive)
|
||||
|
||||
add_subdirectory("${SAPI_ROOT}"
|
||||
"${CMAKE_BINARY_DIR}/sandboxed-api-build"
|
||||
EXCLUDE_FROM_ALL
|
||||
)
|
||||
|
||||
file(STRINGS functions_to_sandbox.txt FUNCTIONS_LIST)
|
||||
|
||||
add_sapi_library(
|
||||
libarchive_sapi
|
||||
|
||||
FUNCTIONS ${FUNCTIONS_LIST}
|
||||
|
||||
INPUTS
|
||||
${CMAKE_BINARY_DIR}/_deps/libarchive-src/libarchive/archive.h
|
||||
${CMAKE_BINARY_DIR}/_deps/libarchive-src/libarchive/archive_entry.h
|
||||
|
||||
LIBRARY archive_static
|
||||
LIBRARY_NAME Libarchive
|
||||
NAMESPACE ""
|
||||
)
|
||||
|
||||
target_include_directories(libarchive_sapi INTERFACE
|
||||
"${PROJECT_BINARY_DIR}" # To find the generated SAPI header
|
||||
)
|
||||
|
||||
add_subdirectory(examples)
|
||||
add_subdirectory(test)
|
||||
|
48
oss-internship-2020/libarchive/README.md
Normal file
48
oss-internship-2020/libarchive/README.md
Normal file
|
@ -0,0 +1,48 @@
|
|||
# libarchive Sandboxed API
|
||||
|
||||
Sandboxed version of the [libarchive](https://www.libarchive.org/) minitar [example](https://github.com/libarchive/libarchive/blob/master/examples/minitar/minitar.c) using [Sandboxed API](https://github.com/google/sandboxed-api).
|
||||
|
||||
## Build
|
||||
|
||||
```
|
||||
mkdir -p build && cd build
|
||||
cmake .. -G Ninja
|
||||
cmake --build .
|
||||
```
|
||||
|
||||
The example binary file can be found at **build/examples/sapi_minitar** and the unit tests at **build/test/sapi_minitar_test**.
|
||||
|
||||
## Patches
|
||||
|
||||
The original libarchive code required patching since one of the custom types produced errors with libclang Python byndings. The patches are applied automatically during the build step and they do not modify the functionality of the library. The repository is also fetched automatically.
|
||||
|
||||
## Examples
|
||||
|
||||
In this project, the minitar example is sandboxed.
|
||||
The code is found in the **examples** directory and is structured as follows:
|
||||
- **sapi_minitar_main.cc** - ***main*** function of the minitar tool. This is mostly similar to the original example.
|
||||
- **sapi_minitar.h** and **sapi_minitar.cc** - The two main functions (***CreateArchive*** and ***ExtractArchive***) and other helper functions.
|
||||
- **sandbox.h** - Custom security policies, depending on the whether the user creates or extracts an archive.
|
||||
|
||||
On top of that, unit tests can be found in the **test/minitar_test.cc** file.
|
||||
|
||||
## Usage
|
||||
|
||||
The unit tests can be executed with `./build/test/sapi_minitar_test`.
|
||||
|
||||
The **sapi_minitar** command line tool can be used in the same way as the original example. It is also similar to the [tar](https://man7.org/linux/man-pages/man1/tar.1.html) command, only with fewer options:
|
||||
|
||||
`./build/examples/sapi_minitar -[options] [-f file] [files]`
|
||||
|
||||
The available options are:
|
||||
- *c* - Create archive.
|
||||
- *x* - Extract archive.
|
||||
- *t* - Extract archive but only print entries.
|
||||
- *p* - Preserve.
|
||||
- *v* - Verbose.
|
||||
- *j* or *y* - Compress with BZIP2.
|
||||
- *Z* - Default compression.
|
||||
- *z* - Compress with GZIP.
|
||||
|
||||
If no compression method is chosen (in the case of archive creation) the files will only be stored.
|
||||
|
43
oss-internship-2020/libarchive/examples/CMakeLists.txt
Normal file
43
oss-internship-2020/libarchive/examples/CMakeLists.txt
Normal file
|
@ -0,0 +1,43 @@
|
|||
# Copyright 2020 Google LLC
|
||||
#
|
||||
# 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.
|
||||
|
||||
add_library(sapi_minitar_lib STATIC
|
||||
sapi_minitar.cc
|
||||
sapi_minitar.h
|
||||
sandbox.h
|
||||
)
|
||||
|
||||
target_link_libraries(sapi_minitar_lib PUBLIC
|
||||
glog::glog
|
||||
libarchive_sapi
|
||||
sandbox2::executor
|
||||
sandbox2::fileops
|
||||
sandbox2::file_base
|
||||
sandbox2::util
|
||||
sandbox2::temp_file
|
||||
sapi::sapi
|
||||
)
|
||||
|
||||
target_include_directories(sapi_minitar_lib INTERFACE
|
||||
"${PROJECT_SOURCE_DIR}/examples"
|
||||
)
|
||||
|
||||
add_executable(sapi_minitar
|
||||
sapi_minitar_main.cc
|
||||
)
|
||||
|
||||
target_link_libraries(sapi_minitar PRIVATE
|
||||
sapi_minitar_lib
|
||||
)
|
||||
|
147
oss-internship-2020/libarchive/examples/sandbox.h
Normal file
147
oss-internship-2020/libarchive/examples/sandbox.h
Normal file
|
@ -0,0 +1,147 @@
|
|||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// 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 SAPI_LIBARCHIVE_EXAMPLES_SANDBOX_H
|
||||
#define SAPI_LIBARCHIVE_EXAMPLES_SANDBOX_H
|
||||
|
||||
#include <asm/unistd_64.h>
|
||||
#include <linux/fs.h>
|
||||
|
||||
#include "libarchive_sapi.sapi.h" // NOLINT(build/include)
|
||||
#include "sandboxed_api/sandbox2/util/bpf_helper.h"
|
||||
#include "sandboxed_api/sandbox2/util/fileops.h"
|
||||
|
||||
// When creating an archive, we need read permissions on each of the
|
||||
// file/directory added in the archive. Also, in order to create the archive, we
|
||||
// map "/output" with the basename of the archive. This way, the program can
|
||||
// create the file without having access to anything else.
|
||||
class SapiLibarchiveSandboxCreate : public LibarchiveSandbox {
|
||||
public:
|
||||
SapiLibarchiveSandboxCreate(const std::vector<std::string>& files,
|
||||
absl::string_view archive_path)
|
||||
: files_(files), archive_path_(archive_path) {}
|
||||
|
||||
private:
|
||||
std::unique_ptr<sandbox2::Policy> ModifyPolicy(
|
||||
sandbox2::PolicyBuilder*) override {
|
||||
sandbox2::PolicyBuilder policy =
|
||||
sandbox2::PolicyBuilder()
|
||||
.AddDirectoryAt(archive_path_, "/output", false)
|
||||
.AllowRead()
|
||||
.AllowWrite()
|
||||
.AllowOpen()
|
||||
.AllowSystemMalloc()
|
||||
.AllowGetIDs()
|
||||
.AllowSafeFcntl()
|
||||
.AllowStat()
|
||||
.AllowExit()
|
||||
.AllowSyscalls({
|
||||
__NR_futex,
|
||||
__NR_lseek,
|
||||
__NR_close,
|
||||
__NR_gettid,
|
||||
__NR_umask,
|
||||
__NR_utimensat,
|
||||
__NR_unlink,
|
||||
__NR_mkdir,
|
||||
__NR_fstatfs,
|
||||
__NR_socket,
|
||||
__NR_connect,
|
||||
__NR_flistxattr,
|
||||
__NR_recvmsg,
|
||||
__NR_getdents64,
|
||||
})
|
||||
// Allow ioctl only for FS_IOC_GETFLAGS.
|
||||
.AddPolicyOnSyscall(__NR_ioctl,
|
||||
{ARG(1), JEQ(FS_IOC_GETFLAGS, ALLOW)});
|
||||
|
||||
// We check whether the entry is a file or a directory.
|
||||
for (const auto& i : files_) {
|
||||
struct stat s;
|
||||
CHECK(stat(i.c_str(), &s) == 0) << "Could not stat " << i;
|
||||
if (S_ISDIR(s.st_mode)) {
|
||||
policy = policy.AddDirectory(i);
|
||||
} else {
|
||||
policy = policy.AddFile(i);
|
||||
}
|
||||
}
|
||||
|
||||
return policy.BuildOrDie();
|
||||
}
|
||||
|
||||
const std::vector<std::string> files_;
|
||||
absl::string_view archive_path_;
|
||||
};
|
||||
|
||||
// When an archive is extracted, the generated files/directories will be placed
|
||||
// relative to the current working directory. In order to add permissions to
|
||||
// this we create a temporary directory at every extraction. Then, we change the
|
||||
// directory of the sandboxed process to that directory and map it to the
|
||||
// current "real" working directory. This way the contents of the archived will
|
||||
// pe placed correctly without offering additional permission.
|
||||
class SapiLibarchiveSandboxExtract : public LibarchiveSandbox {
|
||||
public:
|
||||
SapiLibarchiveSandboxExtract(absl::string_view archive_path, int do_extract,
|
||||
absl::string_view tmp_dir)
|
||||
: archive_path_(archive_path),
|
||||
do_extract_(do_extract),
|
||||
tmp_dir_(tmp_dir) {}
|
||||
|
||||
private:
|
||||
void ModifyExecutor(sandbox2::Executor* executor) override {
|
||||
// If the user only wants to list the entries in the archive, we do
|
||||
// not need to worry about changing directories;
|
||||
if (do_extract_) {
|
||||
executor->set_cwd(std::string(tmp_dir_));
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<sandbox2::Policy> ModifyPolicy(
|
||||
sandbox2::PolicyBuilder*) override {
|
||||
sandbox2::PolicyBuilder policy = sandbox2::PolicyBuilder()
|
||||
.AllowRead()
|
||||
.AllowWrite()
|
||||
.AllowOpen()
|
||||
.AllowSystemMalloc()
|
||||
.AllowGetIDs()
|
||||
.AllowSafeFcntl()
|
||||
.AllowStat()
|
||||
.AllowExit()
|
||||
.AllowSyscalls({
|
||||
__NR_futex,
|
||||
__NR_lseek,
|
||||
__NR_close,
|
||||
__NR_gettid,
|
||||
__NR_umask,
|
||||
__NR_utimensat,
|
||||
__NR_unlink,
|
||||
__NR_mkdir,
|
||||
})
|
||||
.AddFile(archive_path_);
|
||||
|
||||
if (do_extract_) {
|
||||
// Get the real cwd and map it to the temporary directory in which
|
||||
// the sandboxed process takes place().
|
||||
std::string cwd = sandbox2::file_util::fileops::GetCWD();
|
||||
policy = policy.AddDirectoryAt(cwd, tmp_dir_, false);
|
||||
}
|
||||
return policy.BuildOrDie();
|
||||
}
|
||||
|
||||
absl::string_view archive_path_;
|
||||
absl::string_view tmp_dir_;
|
||||
const int do_extract_;
|
||||
};
|
||||
|
||||
#endif // SAPI_LIBARCHIVE_EXAMPLES_SANDBOX_H
|
540
oss-internship-2020/libarchive/examples/sapi_minitar.cc
Normal file
540
oss-internship-2020/libarchive/examples/sapi_minitar.cc
Normal file
|
@ -0,0 +1,540 @@
|
|||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// 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 "sapi_minitar.h" // NOLINT(build/include)
|
||||
|
||||
#include "absl/status/status.h"
|
||||
#include "sandboxed_api/sandbox2/util/path.h"
|
||||
#include "sandboxed_api/util/status_macros.h"
|
||||
|
||||
absl::Status CreateArchive(const char* initial_filename, int compress,
|
||||
const char** argv, bool verbose) {
|
||||
// We split the filename path into dirname and filename. To the filename we
|
||||
// prepend "/output/"" so that it will work with the security policy.
|
||||
std::string abs_path = MakeAbsolutePathAtCWD(std::string(initial_filename));
|
||||
auto [archive_path, filename_tmp] =
|
||||
std::move(sandbox2::file::SplitPath(abs_path));
|
||||
|
||||
std::string filename = sandbox2::file::JoinPath("/output/", filename_tmp);
|
||||
|
||||
std::vector<std::string> absolute_paths;
|
||||
sandbox2::util::CharPtrArrToVecString(const_cast<char* const*>(argv),
|
||||
&absolute_paths);
|
||||
|
||||
std::vector<std::string> relative_paths = absolute_paths;
|
||||
|
||||
std::transform(absolute_paths.begin(), absolute_paths.end(),
|
||||
absolute_paths.begin(), MakeAbsolutePathAtCWD);
|
||||
|
||||
std::transform(relative_paths.begin(), relative_paths.end(),
|
||||
relative_paths.begin(), sandbox2::file::CleanPath);
|
||||
// At this point, we have the relative and absolute paths (cleaned) saved
|
||||
// in vectors.
|
||||
|
||||
// Initialize sandbox and api objects.
|
||||
SapiLibarchiveSandboxCreate sandbox(absolute_paths, archive_path);
|
||||
SAPI_RETURN_IF_ERROR(sandbox.Init());
|
||||
LibarchiveApi api(&sandbox);
|
||||
|
||||
SAPI_ASSIGN_OR_RETURN(archive * ret_archive, api.archive_write_new());
|
||||
if (ret_archive == nullptr) {
|
||||
return absl::FailedPreconditionError("Failed to create write archive");
|
||||
}
|
||||
|
||||
// Treat the pointer as remote. There is no need to copy the data
|
||||
// to the client process.
|
||||
sapi::v::RemotePtr a(ret_archive);
|
||||
|
||||
int rc;
|
||||
std::string msg;
|
||||
|
||||
// switch (compress) {
|
||||
// case 'j':
|
||||
// case 'y':
|
||||
if (compress == 'j' || compress == 'y') {
|
||||
SAPI_ASSIGN_OR_RETURN(rc, api.archive_write_add_filter_bzip2(&a));
|
||||
if (rc != ARCHIVE_OK) {
|
||||
return absl::FailedPreconditionError(
|
||||
"Unexpected result from write_add_filter_bzip2 call");
|
||||
}
|
||||
// break;
|
||||
} else if (compress == 'Z') {
|
||||
// case 'Z':
|
||||
SAPI_ASSIGN_OR_RETURN(rc, api.archive_write_add_filter_compress(&a));
|
||||
if (rc != ARCHIVE_OK) {
|
||||
return absl::FailedPreconditionError(
|
||||
"Unexpected result from write_add_filter_compress call");
|
||||
}
|
||||
// break;
|
||||
} else if (compress == 'z') {
|
||||
// case 'z':
|
||||
SAPI_ASSIGN_OR_RETURN(rc, api.archive_write_add_filter_gzip(&a));
|
||||
if (rc != ARCHIVE_OK) {
|
||||
return absl::FailedPreconditionError(
|
||||
"Unexpected result from write_add_filter_gzip call");
|
||||
}
|
||||
// break;
|
||||
} else {
|
||||
// default:
|
||||
SAPI_ASSIGN_OR_RETURN(rc, api.archive_write_add_filter_none(&a));
|
||||
if (rc != ARCHIVE_OK) {
|
||||
return absl::FailedPreconditionError(
|
||||
"Unexpected result from write_add_filter_none call");
|
||||
}
|
||||
// break;
|
||||
}
|
||||
|
||||
SAPI_ASSIGN_OR_RETURN(rc, api.archive_write_set_format_ustar(&a));
|
||||
if (rc != ARCHIVE_OK) {
|
||||
return absl::FailedPreconditionError(
|
||||
"Unexpected result from write_set_format_ustar call");
|
||||
}
|
||||
|
||||
const char* filename_ptr = filename.data();
|
||||
if (filename_ptr != nullptr && strcmp(filename_ptr, "-") == 0) {
|
||||
filename_ptr = nullptr;
|
||||
}
|
||||
|
||||
SAPI_ASSIGN_OR_RETURN(rc, api.archive_write_open_filename(
|
||||
&a, sapi::v::ConstCStr(filename_ptr).PtrBefore()));
|
||||
if (rc != ARCHIVE_OK) {
|
||||
return absl::FailedPreconditionError(
|
||||
"Unexpected result from write_open_filename call");
|
||||
}
|
||||
|
||||
int file_idx = 0;
|
||||
|
||||
// We can directly use the vectors defined before.
|
||||
for (int file_idx = 0; file_idx < absolute_paths.size(); ++file_idx) {
|
||||
SAPI_ASSIGN_OR_RETURN(ret_archive, api.archive_read_disk_new());
|
||||
if (ret_archive == nullptr) {
|
||||
return absl::FailedPreconditionError(
|
||||
"Failed to create read_disk archive");
|
||||
}
|
||||
|
||||
sapi::v::RemotePtr disk(ret_archive);
|
||||
|
||||
SAPI_ASSIGN_OR_RETURN(rc, api.archive_read_disk_set_standard_lookup(&disk));
|
||||
if (rc != ARCHIVE_OK) {
|
||||
return absl::FailedPreconditionError(
|
||||
"Unexpected result from read_disk_set_standard_lookup call");
|
||||
}
|
||||
|
||||
// We use the absolute path first.
|
||||
SAPI_ASSIGN_OR_RETURN(
|
||||
rc,
|
||||
api.archive_read_disk_open(
|
||||
&disk,
|
||||
sapi::v::ConstCStr(absolute_paths[file_idx].c_str()).PtrBefore()));
|
||||
if (rc != ARCHIVE_OK) {
|
||||
SAPI_ASSIGN_OR_RETURN(msg, CheckStatusAndGetString(
|
||||
api.archive_error_string(&disk), sandbox));
|
||||
return absl::FailedPreconditionError(msg);
|
||||
}
|
||||
|
||||
while (true) {
|
||||
archive_entry* ret_archive_entry;
|
||||
SAPI_ASSIGN_OR_RETURN(ret_archive_entry, api.archive_entry_new());
|
||||
|
||||
if (ret_archive_entry == nullptr) {
|
||||
return absl::FailedPreconditionError("Failed to create archive_entry");
|
||||
}
|
||||
|
||||
sapi::v::RemotePtr entry(ret_archive_entry);
|
||||
|
||||
SAPI_ASSIGN_OR_RETURN(rc, api.archive_read_next_header2(&disk, &entry));
|
||||
|
||||
if (rc == ARCHIVE_EOF) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (rc != ARCHIVE_OK) {
|
||||
SAPI_ASSIGN_OR_RETURN(msg, CheckStatusAndGetString(
|
||||
api.archive_error_string(&disk), sandbox));
|
||||
return absl::FailedPreconditionError(msg);
|
||||
}
|
||||
|
||||
SAPI_ASSIGN_OR_RETURN(rc, api.archive_read_disk_descend(&disk));
|
||||
if (rc != ARCHIVE_OK) {
|
||||
return absl::FailedPreconditionError("read_disk_descend call failed");
|
||||
}
|
||||
|
||||
// After using the absolute path before, we now need to add the pathname
|
||||
// to the archive entry. This would help store the files by their relative
|
||||
// paths(similar to the usual tar command).
|
||||
// However, in the case where a directory is added to the archive,
|
||||
// all of the files inside of it are added as well so we replace the
|
||||
// absolute path prefix with the relative one.
|
||||
// Example:
|
||||
// we add the folder "test_files" which becomes
|
||||
// "/absolute/path/test_files" and the files inside of it will become
|
||||
// similar to "/absolute/path/test_files/file1"
|
||||
// which we then change to "test_files/file1" so that it is relative.
|
||||
SAPI_ASSIGN_OR_RETURN(
|
||||
std::string path_name,
|
||||
CheckStatusAndGetString(api.archive_entry_pathname(&entry), sandbox));
|
||||
|
||||
path_name.replace(path_name.begin(),
|
||||
path_name.begin() + absolute_paths[file_idx].length(),
|
||||
relative_paths[file_idx]);
|
||||
|
||||
// On top of those changes, we need to remove leading '/' characters
|
||||
// and also remove everything up to the last occurrence of '../'.
|
||||
size_t found = path_name.find_first_not_of("/");
|
||||
if (found != std::string::npos) {
|
||||
path_name.erase(path_name.begin(), path_name.begin() + found);
|
||||
}
|
||||
|
||||
// Search either for the last '/../' or check if
|
||||
// the path has '../' in the beginning.
|
||||
found = path_name.rfind("/../");
|
||||
if (found != std::string::npos) {
|
||||
path_name = path_name.substr(found + 4);
|
||||
} else if (path_name.substr(0, 3) == "../") {
|
||||
path_name = path_name.substr(3);
|
||||
}
|
||||
|
||||
SAPI_RETURN_IF_ERROR(api.archive_entry_set_pathname(
|
||||
&entry, sapi::v::ConstCStr(path_name.c_str()).PtrBefore()));
|
||||
|
||||
if (verbose) {
|
||||
SAPI_ASSIGN_OR_RETURN(msg, CheckStatusAndGetString(
|
||||
api.archive_entry_pathname(&entry), sandbox));
|
||||
std::cout << msg << std::endl;
|
||||
}
|
||||
|
||||
SAPI_ASSIGN_OR_RETURN(rc, api.archive_write_header(&a, &entry));
|
||||
|
||||
if (rc < ARCHIVE_OK) {
|
||||
SAPI_ASSIGN_OR_RETURN(msg, CheckStatusAndGetString(
|
||||
api.archive_error_string(&a), sandbox));
|
||||
std::cout << msg << std::endl;
|
||||
}
|
||||
if (rc == ARCHIVE_FATAL) {
|
||||
return absl::FailedPreconditionError(
|
||||
"Unexpected result from write_header call");
|
||||
}
|
||||
|
||||
// In the following section, the calls (read, archive_write_data) are done
|
||||
// on the sandboxed process since we do not need to transfer the data in
|
||||
// the client process.
|
||||
if (rc > ARCHIVE_FAILED) {
|
||||
SAPI_ASSIGN_OR_RETURN(
|
||||
msg, CheckStatusAndGetString(api.archive_entry_sourcepath(&entry),
|
||||
sandbox));
|
||||
int fd = open(msg.c_str(), O_RDONLY);
|
||||
if (fd < 0) {
|
||||
return absl::FailedPreconditionError("Could not open file");
|
||||
}
|
||||
|
||||
sapi::v::Fd sapi_fd(fd);
|
||||
sapi::v::Int read_ret;
|
||||
sapi::v::Array<char> buff(kBuffSize);
|
||||
sapi::v::UInt ssize(kBuffSize);
|
||||
|
||||
// We allocate the buffer remotely and then we can simply use the
|
||||
// remote pointer(with PtrNone).
|
||||
// This allows us to keep the data in the remote process without always
|
||||
// transferring the memory.
|
||||
SAPI_RETURN_IF_ERROR(sandbox.Allocate(&buff, true));
|
||||
|
||||
// We can use sapi methods that help us with file descriptors.
|
||||
SAPI_RETURN_IF_ERROR(sandbox.TransferToSandboxee(&sapi_fd));
|
||||
|
||||
SAPI_RETURN_IF_ERROR(
|
||||
sandbox.Call("read", &read_ret, &sapi_fd, buff.PtrNone(), &ssize));
|
||||
|
||||
while (read_ret.GetValue() > 0) {
|
||||
SAPI_ASSIGN_OR_RETURN(rc, api.archive_write_data(&a, buff.PtrNone(),
|
||||
read_ret.GetValue()));
|
||||
|
||||
SAPI_RETURN_IF_ERROR(sandbox.Call("read", &read_ret, &sapi_fd,
|
||||
buff.PtrNone(), &ssize));
|
||||
}
|
||||
// sapi_fd variable goes out of scope here so both the local and the
|
||||
// remote file descriptors are closed.
|
||||
}
|
||||
SAPI_RETURN_IF_ERROR(api.archive_entry_free(&entry));
|
||||
}
|
||||
|
||||
SAPI_ASSIGN_OR_RETURN(rc, api.archive_read_close(&disk));
|
||||
if (rc != ARCHIVE_OK) {
|
||||
return absl::FailedPreconditionError(
|
||||
"Unexpected result from read_close call");
|
||||
}
|
||||
|
||||
SAPI_ASSIGN_OR_RETURN(rc, api.archive_read_free(&disk));
|
||||
if (rc != ARCHIVE_OK) {
|
||||
return absl::FailedPreconditionError(
|
||||
"Unexpected result from read_free call");
|
||||
}
|
||||
}
|
||||
|
||||
SAPI_ASSIGN_OR_RETURN(rc, api.archive_write_close(&a));
|
||||
if (rc != ARCHIVE_OK) {
|
||||
return absl::FailedPreconditionError(
|
||||
"Unexpected result from write_close call");
|
||||
}
|
||||
|
||||
SAPI_ASSIGN_OR_RETURN(rc, api.archive_write_free(&a));
|
||||
if (rc != ARCHIVE_OK) {
|
||||
return absl::FailedPreconditionError(
|
||||
"Unexpected result from write_free call");
|
||||
}
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
absl::Status ExtractArchive(const char* filename, int do_extract, int flags,
|
||||
bool verbose) {
|
||||
std::string tmp_dir;
|
||||
if (do_extract) {
|
||||
SAPI_ASSIGN_OR_RETURN(tmp_dir, CreateTempDirAtCWD());
|
||||
}
|
||||
|
||||
// We can use a struct like this in order to delete the temporary
|
||||
// directory that was created earlier whenever the function ends.
|
||||
struct ExtractTempDirectoryCleanup {
|
||||
ExtractTempDirectoryCleanup(const std::string& dir) : dir_(dir) {}
|
||||
~ExtractTempDirectoryCleanup() {
|
||||
sandbox2::file_util::fileops::DeleteRecursively(dir_);
|
||||
}
|
||||
|
||||
private:
|
||||
std::string dir_;
|
||||
};
|
||||
|
||||
// We should only delete it if the do_extract flag is true which
|
||||
// means that this struct is instantiated only in that case.
|
||||
auto cleanup_ptr =
|
||||
do_extract ? absl::make_unique<ExtractTempDirectoryCleanup>(tmp_dir)
|
||||
: nullptr;
|
||||
|
||||
std::string filename_absolute = MakeAbsolutePathAtCWD(filename);
|
||||
|
||||
// Initialize sandbox and api objects.
|
||||
SapiLibarchiveSandboxExtract sandbox(filename_absolute, do_extract, tmp_dir);
|
||||
SAPI_RETURN_IF_ERROR(sandbox.Init());
|
||||
LibarchiveApi api(&sandbox);
|
||||
|
||||
SAPI_ASSIGN_OR_RETURN(archive * ret_archive, api.archive_read_new());
|
||||
if (ret_archive == nullptr) {
|
||||
return absl::FailedPreconditionError("Failed to create read archive");
|
||||
}
|
||||
|
||||
sapi::v::RemotePtr a(ret_archive);
|
||||
|
||||
SAPI_ASSIGN_OR_RETURN(ret_archive, api.archive_write_disk_new());
|
||||
if (ret_archive == nullptr) {
|
||||
return absl::FailedPreconditionError("Failed to create write disk archive");
|
||||
}
|
||||
|
||||
sapi::v::RemotePtr ext(ret_archive);
|
||||
|
||||
int rc;
|
||||
std::string msg;
|
||||
|
||||
SAPI_ASSIGN_OR_RETURN(rc, api.archive_write_disk_set_options(&ext, flags));
|
||||
if (rc != ARCHIVE_OK) {
|
||||
return absl::FailedPreconditionError(
|
||||
"Unexpected result from write_disk_set_options call");
|
||||
}
|
||||
|
||||
SAPI_ASSIGN_OR_RETURN(rc, api.archive_read_support_filter_bzip2(&a));
|
||||
if (rc != ARCHIVE_OK) {
|
||||
return absl::FailedPreconditionError(
|
||||
"Unexpected result from read_support_filter_bzip2 call");
|
||||
}
|
||||
|
||||
SAPI_ASSIGN_OR_RETURN(rc, api.archive_read_support_filter_gzip(&a));
|
||||
if (rc != ARCHIVE_OK) {
|
||||
return absl::FailedPreconditionError(
|
||||
"Unexpected result from read_suppport_filter_gzip call");
|
||||
}
|
||||
|
||||
SAPI_ASSIGN_OR_RETURN(rc, api.archive_read_support_filter_compress(&a));
|
||||
if (rc != ARCHIVE_OK) {
|
||||
return absl::FailedPreconditionError(
|
||||
"Unexpected result from read_support_filter_compress call");
|
||||
}
|
||||
|
||||
SAPI_ASSIGN_OR_RETURN(rc, api.archive_read_support_format_tar(&a));
|
||||
if (rc != ARCHIVE_OK) {
|
||||
return absl::FailedPreconditionError(
|
||||
"Unexpected result fromread_support_format_tar call");
|
||||
}
|
||||
|
||||
SAPI_ASSIGN_OR_RETURN(rc, api.archive_read_support_format_cpio(&a));
|
||||
if (rc != ARCHIVE_OK) {
|
||||
return absl::FailedPreconditionError(
|
||||
"Unexpected result from read_support_format_tar call");
|
||||
}
|
||||
|
||||
SAPI_ASSIGN_OR_RETURN(rc, api.archive_write_disk_set_standard_lookup(&ext));
|
||||
if (rc != ARCHIVE_OK) {
|
||||
return absl::FailedPreconditionError(
|
||||
"Unexpected result from write_disk_set_standard_lookup call");
|
||||
}
|
||||
|
||||
const char* filename_ptr = filename_absolute.c_str();
|
||||
if (filename_ptr != nullptr && strcmp(filename_ptr, "-") == 0) {
|
||||
filename_ptr = nullptr;
|
||||
}
|
||||
|
||||
// The entries are saved with a relative path so they are all created
|
||||
// relative to the current working directory.
|
||||
SAPI_ASSIGN_OR_RETURN(
|
||||
rc, api.archive_read_open_filename(
|
||||
&a, sapi::v::ConstCStr(filename_ptr).PtrBefore(), kBlockSize));
|
||||
if (rc != ARCHIVE_OK) {
|
||||
SAPI_ASSIGN_OR_RETURN(
|
||||
msg, CheckStatusAndGetString(api.archive_error_string(&a), sandbox));
|
||||
return absl::FailedPreconditionError(msg);
|
||||
}
|
||||
|
||||
while (true) {
|
||||
sapi::v::IntBase<archive_entry*> entry_ptr_tmp(0);
|
||||
|
||||
SAPI_ASSIGN_OR_RETURN(
|
||||
rc, api.archive_read_next_header(&a, entry_ptr_tmp.PtrAfter()));
|
||||
|
||||
if (rc == ARCHIVE_EOF) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (rc != ARCHIVE_OK) {
|
||||
SAPI_ASSIGN_OR_RETURN(
|
||||
msg, CheckStatusAndGetString(api.archive_error_string(&a), sandbox));
|
||||
return absl::FailedPreconditionError(msg);
|
||||
}
|
||||
|
||||
sapi::v::RemotePtr entry(entry_ptr_tmp.GetValue());
|
||||
|
||||
if (verbose && do_extract) {
|
||||
std::cout << "x ";
|
||||
}
|
||||
|
||||
if (verbose || !do_extract) {
|
||||
SAPI_ASSIGN_OR_RETURN(msg, CheckStatusAndGetString(
|
||||
api.archive_entry_pathname(&entry), sandbox));
|
||||
std::cout << msg << std::endl;
|
||||
}
|
||||
|
||||
if (do_extract) {
|
||||
SAPI_ASSIGN_OR_RETURN(rc, api.archive_write_header(&ext, &entry));
|
||||
|
||||
if (rc != ARCHIVE_OK) {
|
||||
SAPI_ASSIGN_OR_RETURN(msg, CheckStatusAndGetString(
|
||||
api.archive_error_string(&a), sandbox));
|
||||
std::cout << msg << std::endl;
|
||||
} else {
|
||||
SAPI_ASSIGN_OR_RETURN(rc, CopyData(&a, &ext, api, sandbox));
|
||||
if (rc != ARCHIVE_OK) {
|
||||
return absl::FailedPreconditionError(
|
||||
"Failed to copy data between archive structs.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SAPI_ASSIGN_OR_RETURN(rc, api.archive_read_close(&a));
|
||||
if (rc != ARCHIVE_OK) {
|
||||
return absl::FailedPreconditionError(
|
||||
"Unexpected value from read_close call");
|
||||
}
|
||||
|
||||
SAPI_ASSIGN_OR_RETURN(rc, api.archive_read_free(&a));
|
||||
if (rc != ARCHIVE_OK) {
|
||||
return absl::FailedPreconditionError(
|
||||
"Unexpected result from read_free call");
|
||||
}
|
||||
|
||||
SAPI_ASSIGN_OR_RETURN(rc, api.archive_write_close(&ext));
|
||||
if (rc != ARCHIVE_OK) {
|
||||
return absl::FailedPreconditionError(
|
||||
"Unexpected result from write_close call");
|
||||
}
|
||||
|
||||
SAPI_ASSIGN_OR_RETURN(rc, api.archive_write_free(&ext));
|
||||
if (rc != ARCHIVE_OK) {
|
||||
return absl::FailedPreconditionError(
|
||||
"Unexpected result from write_free call");
|
||||
}
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
absl::StatusOr<int> CopyData(sapi::v::RemotePtr* ar, sapi::v::RemotePtr* aw,
|
||||
LibarchiveApi& api,
|
||||
SapiLibarchiveSandboxExtract& sandbox) {
|
||||
int rc;
|
||||
std::string msg;
|
||||
|
||||
sapi::v::IntBase<archive_entry*> buff_ptr_tmp(0);
|
||||
sapi::v::ULLong size;
|
||||
sapi::v::SLLong offset;
|
||||
|
||||
while (true) {
|
||||
SAPI_ASSIGN_OR_RETURN(
|
||||
rc, api.archive_read_data_block(ar, buff_ptr_tmp.PtrAfter(),
|
||||
size.PtrAfter(), offset.PtrAfter()));
|
||||
|
||||
if (rc == ARCHIVE_EOF) {
|
||||
return ARCHIVE_OK;
|
||||
}
|
||||
if (rc != ARCHIVE_OK) {
|
||||
SAPI_ASSIGN_OR_RETURN(
|
||||
msg, CheckStatusAndGetString(api.archive_error_string(ar), sandbox));
|
||||
std::cout << msg << std::endl;
|
||||
return rc;
|
||||
}
|
||||
|
||||
sapi::v::RemotePtr buff(buff_ptr_tmp.GetValue());
|
||||
|
||||
SAPI_ASSIGN_OR_RETURN(rc, api.archive_write_data_block(
|
||||
aw, &buff, size.GetValue(), offset.GetValue()));
|
||||
|
||||
if (rc != ARCHIVE_OK) {
|
||||
SAPI_ASSIGN_OR_RETURN(
|
||||
msg, CheckStatusAndGetString(api.archive_error_string(ar), sandbox));
|
||||
std::cout << msg << std::endl;
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string MakeAbsolutePathAtCWD(const std::string& path) {
|
||||
std::string result = sandbox2::file_util::fileops::MakeAbsolute(
|
||||
path, sandbox2::file_util::fileops::GetCWD());
|
||||
CHECK(result != "") << "Could not create absolute path for: " << path;
|
||||
return sandbox2::file::CleanPath(result);
|
||||
}
|
||||
|
||||
absl::StatusOr<std::string> CheckStatusAndGetString(
|
||||
const absl::StatusOr<char*>& status, LibarchiveSandbox& sandbox) {
|
||||
SAPI_ASSIGN_OR_RETURN(char* str, status);
|
||||
if (str == nullptr) {
|
||||
return absl::FailedPreconditionError("Could not get string from archive");
|
||||
}
|
||||
return sandbox.GetCString(sapi::v::RemotePtr(str));
|
||||
}
|
||||
|
||||
absl::StatusOr<std::string> CreateTempDirAtCWD() {
|
||||
std::string cwd = sandbox2::file_util::fileops::GetCWD();
|
||||
CHECK(!cwd.empty()) << "Could not get current working directory";
|
||||
cwd.append("/");
|
||||
|
||||
SAPI_ASSIGN_OR_RETURN(std::string result, sandbox2::CreateTempDir(cwd));
|
||||
return result;
|
||||
}
|
63
oss-internship-2020/libarchive/examples/sapi_minitar.h
Normal file
63
oss-internship-2020/libarchive/examples/sapi_minitar.h
Normal file
|
@ -0,0 +1,63 @@
|
|||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// 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 SAPI_LIBARCHIVE_EXAMPLES_MINITAR_H
|
||||
#define SAPI_LIBARCHIVE_EXAMPLES_MINITAR_H
|
||||
|
||||
#include <archive.h>
|
||||
#include <archive_entry.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "libarchive_sapi.sapi.h" // NOLINT(build/include)
|
||||
#include "sandbox.h" // NOLINT(build/include)
|
||||
#include "sandboxed_api/sandbox2/util.h"
|
||||
#include "sandboxed_api/sandbox2/util/path.h"
|
||||
#include "sandboxed_api/sandbox2/util/temp_file.h"
|
||||
|
||||
// Creates an archive file at the given filename.
|
||||
absl::Status CreateArchive(const char* filename, int compress,
|
||||
const char** argv, bool verbose = true);
|
||||
|
||||
// Extracts an archive file. If do_extract is true, the files will
|
||||
// be created relative to the current working directory. If do_extract
|
||||
// is false then the function will just print the entries of the archive.
|
||||
absl::Status ExtractArchive(const char* filename, int do_extract, int flags,
|
||||
bool verbose = true);
|
||||
|
||||
// This function is only called from the "extract function". It is still
|
||||
// isolated in order to not modify the code structure as much.
|
||||
absl::StatusOr<int> CopyData(sapi::v::RemotePtr* ar, sapi::v::RemotePtr* aw,
|
||||
LibarchiveApi& api,
|
||||
SapiLibarchiveSandboxExtract& sandbox);
|
||||
|
||||
inline constexpr size_t kBlockSize = 10240;
|
||||
inline constexpr size_t kBuffSize = 16384;
|
||||
|
||||
// Converts one string to an absolute path by prepending the current
|
||||
// working directory to the relative path.
|
||||
// The path is also cleaned at the end.
|
||||
std::string MakeAbsolutePathAtCWD(const std::string& path);
|
||||
|
||||
// This function takes a status as argument and after checking the status
|
||||
// it transfers the string. This is used mostly with archive_error_string
|
||||
// and other library functions that return a char*.
|
||||
absl::StatusOr<std::string> CheckStatusAndGetString(
|
||||
const absl::StatusOr<char*>& status, LibarchiveSandbox& sandbox);
|
||||
|
||||
// Creates a temporary directory in the current working directory and
|
||||
// returns the path. This is used in the extract function where the sandboxed
|
||||
// process changes the current working directory to this temporary directory.
|
||||
absl::StatusOr<std::string> CreateTempDirAtCWD();
|
||||
|
||||
#endif // SAPI_LIBARCHIVE_EXAMPLES_MINITAR_H
|
130
oss-internship-2020/libarchive/examples/sapi_minitar_main.cc
Normal file
130
oss-internship-2020/libarchive/examples/sapi_minitar_main.cc
Normal file
|
@ -0,0 +1,130 @@
|
|||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// 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.
|
||||
|
||||
// This file contains the main function from the original minitar example:
|
||||
// https://github.com/libarchive/libarchive/blob/master/examples/minitar/minitar.c
|
||||
// Most of the logic is the same, it was only simplified a bit since this is
|
||||
// only used for the command line tool.
|
||||
// No sandboxing takes place in this function.
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "sapi_minitar.h" // NOLINT(build/include)
|
||||
|
||||
static void PrintUsage() {
|
||||
/* Many program options depend on compile options. */
|
||||
const char* m =
|
||||
"Usage: minitar [-"
|
||||
"c"
|
||||
"j"
|
||||
"tvx"
|
||||
"y"
|
||||
"Z"
|
||||
"z"
|
||||
"] [-f file] [file]\n";
|
||||
|
||||
std::cout << m << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
int main(int unused_argc, const char** argv) {
|
||||
google::InitGoogleLogging(argv[0]);
|
||||
const char* filename = nullptr;
|
||||
int compress;
|
||||
int flags;
|
||||
int mode;
|
||||
int opt;
|
||||
|
||||
mode = 'x';
|
||||
int verbose = 0;
|
||||
compress = '\0';
|
||||
flags = ARCHIVE_EXTRACT_TIME;
|
||||
|
||||
while (*++argv != nullptr && **argv == '-') {
|
||||
const char* p = *argv + 1;
|
||||
|
||||
while ((opt = *p++) != '\0') {
|
||||
switch (opt) {
|
||||
case 'c':
|
||||
mode = opt;
|
||||
break;
|
||||
case 'f':
|
||||
if (*p != '\0')
|
||||
filename = p;
|
||||
else
|
||||
filename = *++argv;
|
||||
p += strlen(p);
|
||||
break;
|
||||
case 'j':
|
||||
compress = opt;
|
||||
break;
|
||||
case 'p':
|
||||
flags |= ARCHIVE_EXTRACT_PERM;
|
||||
flags |= ARCHIVE_EXTRACT_ACL;
|
||||
flags |= ARCHIVE_EXTRACT_FFLAGS;
|
||||
break;
|
||||
case 't':
|
||||
mode = opt;
|
||||
break;
|
||||
case 'v':
|
||||
verbose++;
|
||||
break;
|
||||
case 'x':
|
||||
mode = opt;
|
||||
break;
|
||||
case 'y':
|
||||
compress = opt;
|
||||
break;
|
||||
case 'Z':
|
||||
compress = opt;
|
||||
break;
|
||||
case 'z':
|
||||
compress = opt;
|
||||
break;
|
||||
default:
|
||||
PrintUsage();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
absl::Status status;
|
||||
switch (mode) {
|
||||
case 'c':
|
||||
status = CreateArchive(filename, compress, argv, verbose);
|
||||
if (!status.ok()) {
|
||||
LOG(ERROR) << "Archive creation failed with message: "
|
||||
<< status.message();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
break;
|
||||
case 't':
|
||||
status = ExtractArchive(filename, 0, flags, verbose);
|
||||
if (!status.ok()) {
|
||||
LOG(ERROR) << "Archive extraction failed with message: "
|
||||
<< status.message();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
break;
|
||||
case 'x':
|
||||
status = ExtractArchive(filename, 1, flags, verbose);
|
||||
if (!status.ok()) {
|
||||
LOG(ERROR) << "Archive extraction failed with message: "
|
||||
<< status.message();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
37
oss-internship-2020/libarchive/functions_to_sandbox.txt
Normal file
37
oss-internship-2020/libarchive/functions_to_sandbox.txt
Normal file
|
@ -0,0 +1,37 @@
|
|||
archive_entry_free
|
||||
archive_entry_new
|
||||
archive_entry_pathname
|
||||
archive_entry_sourcepath
|
||||
archive_error_string
|
||||
archive_read_close
|
||||
archive_read_data_block
|
||||
archive_read_disk_descend
|
||||
archive_read_disk_new
|
||||
archive_read_disk_open
|
||||
archive_read_disk_set_standard_lookup
|
||||
archive_read_free
|
||||
archive_read_new
|
||||
archive_read_next_header
|
||||
archive_read_next_header2
|
||||
archive_read_open_filename
|
||||
archive_read_support_filter_bzip2
|
||||
archive_read_support_filter_compress
|
||||
archive_read_support_filter_gzip
|
||||
archive_read_support_format_cpio
|
||||
archive_read_support_format_tar
|
||||
archive_write_add_filter_bzip2
|
||||
archive_write_add_filter_compress
|
||||
archive_write_add_filter_gzip
|
||||
archive_write_add_filter_none
|
||||
archive_write_close
|
||||
archive_write_data
|
||||
archive_write_data_block
|
||||
archive_write_disk_new
|
||||
archive_write_disk_set_options
|
||||
archive_write_disk_set_standard_lookup
|
||||
archive_write_free
|
||||
archive_write_header
|
||||
archive_write_new
|
||||
archive_write_open_filename
|
||||
archive_write_set_format_ustar
|
||||
archive_entry_set_pathname
|
18
oss-internship-2020/libarchive/patches/archive_virtual.patch
Normal file
18
oss-internship-2020/libarchive/patches/archive_virtual.patch
Normal file
|
@ -0,0 +1,18 @@
|
|||
--- archive_virtual.c 2020-09-11 16:39:07.158014139 +0000
|
||||
+++ archive_virtual2.c 2020-09-11 16:39:50.842107856 +0000
|
||||
@@ -124,13 +124,13 @@
|
||||
return ((a->vtable->archive_write_finish_entry)(a));
|
||||
}
|
||||
|
||||
-la_ssize_t
|
||||
+int
|
||||
archive_write_data(struct archive *a, const void *buff, size_t s)
|
||||
{
|
||||
return ((a->vtable->archive_write_data)(a, buff, s));
|
||||
}
|
||||
|
||||
-la_ssize_t
|
||||
+int
|
||||
archive_write_data_block(struct archive *a, const void *buff, size_t s,
|
||||
la_int64_t o)
|
||||
{
|
16
oss-internship-2020/libarchive/patches/header.patch
Normal file
16
oss-internship-2020/libarchive/patches/header.patch
Normal file
|
@ -0,0 +1,16 @@
|
|||
--- archive.h 2020-09-11 14:23:21.758842500 +0000
|
||||
+++ archive2.h 2020-09-11 14:20:27.310494460 +0000
|
||||
@@ -840,11 +840,11 @@
|
||||
*/
|
||||
__LA_DECL int archive_write_header(struct archive *,
|
||||
struct archive_entry *);
|
||||
-__LA_DECL la_ssize_t archive_write_data(struct archive *,
|
||||
+__LA_DECL int archive_write_data(struct archive *,
|
||||
const void *, size_t);
|
||||
|
||||
/* This interface is currently only available for archive_write_disk handles. */
|
||||
-__LA_DECL la_ssize_t archive_write_data_block(struct archive *,
|
||||
+__LA_DECL int archive_write_data_block(struct archive *,
|
||||
const void *, size_t, la_int64_t);
|
||||
|
||||
__LA_DECL int archive_write_finish_entry(struct archive *);
|
29
oss-internship-2020/libarchive/test/CMakeLists.txt
Normal file
29
oss-internship-2020/libarchive/test/CMakeLists.txt
Normal file
|
@ -0,0 +1,29 @@
|
|||
# Copyright 2020 Google LLC
|
||||
#
|
||||
# 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(GoogleTest)
|
||||
enable_testing()
|
||||
|
||||
add_executable(sapi_minitar_test
|
||||
minitar_test.cc
|
||||
)
|
||||
|
||||
target_link_libraries(sapi_minitar_test PRIVATE
|
||||
sapi_minitar_lib
|
||||
gtest
|
||||
sapi::test_main
|
||||
)
|
||||
|
||||
gtest_discover_tests(sapi_minitar_test)
|
||||
|
309
oss-internship-2020/libarchive/test/minitar_test.cc
Normal file
309
oss-internship-2020/libarchive/test/minitar_test.cc
Normal file
|
@ -0,0 +1,309 @@
|
|||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// 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 <fstream>
|
||||
|
||||
#include "sapi_minitar.h" // NOLINT(build/include)
|
||||
#include "gtest/gtest.h"
|
||||
#include "sandboxed_api/sandbox2/util/path.h"
|
||||
#include "sandboxed_api/util/status_matchers.h"
|
||||
|
||||
using ::sandbox2::file::JoinPath;
|
||||
using ::sapi::IsOk;
|
||||
using ::testing::Eq;
|
||||
using ::testing::IsTrue;
|
||||
using ::testing::StrEq;
|
||||
|
||||
using ::sandbox2::file_util::fileops::Exists;
|
||||
using ::sandbox2::util::VecStringToCharPtrArr;
|
||||
|
||||
namespace {
|
||||
|
||||
// We will use a fixture class for testing which allows us to override the
|
||||
// SetUp and TearDown functions. Also, data that needs to be initialized
|
||||
// or destroyed only once (the test files and directories) will be handled
|
||||
// in the SetUpTestSuite and TearDownTestSuite functions which are executed
|
||||
// only once.
|
||||
// All of the testing data will be placed in a temporary directory and each
|
||||
// test will have it's own temporary directory. At the end of each test
|
||||
// and all of the tests, the temporary data is deleted.
|
||||
class MiniTarTest : public ::testing::Test {
|
||||
protected:
|
||||
// Before running the tests, we create a temporary directory which will
|
||||
// store generated files and directories used for testing.
|
||||
// The directory will look as follows:
|
||||
// -file1
|
||||
// -dir1 - file2
|
||||
// - dir2 - file3
|
||||
static void SetUpTestSuite() {
|
||||
absl::StatusOr<std::string> tmp_status = CreateTempDirAtCWD();
|
||||
ASSERT_THAT(tmp_status, IsOk());
|
||||
data_dir_ = new std::string(std::move(tmp_status).value());
|
||||
|
||||
init_wd_ = new std::string(sandbox2::file_util::fileops::GetCWD());
|
||||
ASSERT_THAT(Exists(data_dir_, false), IsTrue())
|
||||
<< "Test data directory was not created";
|
||||
ASSERT_THAT(chdir(data_dir_.data()), Eq(0))
|
||||
<< "Could not chdir into test data directory";
|
||||
|
||||
CreateAndWriteToFile(kFile1);
|
||||
ASSERT_THAT(mkdir(kDir1.data(), 0755), Eq(0)) << "Could not create dir1";
|
||||
CreateAndWriteToFile(kFile2);
|
||||
ASSERT_THAT(mkdir(kDir2.data(), 0755), Eq(0)) << "Could not create dir2";
|
||||
CreateAndWriteToFile(kFile3);
|
||||
|
||||
test_count_ = 0;
|
||||
}
|
||||
|
||||
static void TearDownTestSuite() {
|
||||
// The tests have the data directory as their working directory at the end
|
||||
// so we move to the initial working directory in order to not delete the
|
||||
// directory that we are inside of.
|
||||
ASSERT_THAT(chdir(init_wd_->data()), Eq(0))
|
||||
<< "Could not chdir into initial working directory";
|
||||
EXPECT_THAT(sandbox2::file_util::fileops::DeleteRecursively(*data_dir_),
|
||||
IsTrue)
|
||||
<< "Error during test data deletion";
|
||||
delete init_wd_;
|
||||
delete data_dir_;
|
||||
}
|
||||
|
||||
void SetUp() override {
|
||||
// We use a unique id based on test count to make sure that files created
|
||||
// during tests do not overlap.
|
||||
id_ = "test" + std::to_string(test_count_);
|
||||
|
||||
absl::StatusOr<std::string> tmp_status = CreateTempDirAtCWD();
|
||||
ASSERT_THAT(tmp_status, IsOk());
|
||||
tmp_dir_ = tmp_status.value();
|
||||
|
||||
ASSERT_THAT(Exists(tmp_dir_, false), IsTrue)
|
||||
<< "Could not create test specific temporary directory";
|
||||
ASSERT_THAT(chdir(data_dir_->data()), Eq(0))
|
||||
<< "Could not chdir into test data directory";
|
||||
}
|
||||
|
||||
void TearDown() override {
|
||||
// Move to another directory before deleting the temporary folder.
|
||||
ASSERT_THAT(chdir(data_dir_->data()), Eq(0))
|
||||
<< "Could not chdir into test data directory";
|
||||
|
||||
EXPECT_THAT(sandbox2::file_util::fileops::DeleteRecursively(tmp_dir_),
|
||||
IsTrue)
|
||||
<< "Error during test temporary directory deletion";
|
||||
++test_count_;
|
||||
}
|
||||
|
||||
// Creates the file specified and writes the same filename.
|
||||
// This is done in order to not have completely empty files for the
|
||||
// archiving step.
|
||||
static void CreateAndWriteToFile(absl::string_view file) {
|
||||
std::ofstream fin(file.data());
|
||||
ASSERT_THAT(fin.is_open(), IsTrue()) << "Could not create" << file;
|
||||
fin << file;
|
||||
fin.close();
|
||||
}
|
||||
|
||||
// Checks if the files exists and if the contents are correct.
|
||||
// In these tests, each file contains the relative path from the test
|
||||
// directory.
|
||||
// Example: dir1/dir2/file3 will contain dir1/dir2/file3.
|
||||
// What the files contain does not matter as much, the only important thing
|
||||
// is that they are not empty so we can check if the contents are preserved.
|
||||
static void CheckFile(const std::string& file) {
|
||||
ASSERT_THAT(Exists(file, false), IsTrue()) << "Could not find " << file;
|
||||
std::ifstream fin(file);
|
||||
ASSERT_THAT(fin.is_open(), IsTrue()) << "Error when opening " << file;
|
||||
|
||||
std::string file_contents((std::istreambuf_iterator<char>(fin)),
|
||||
std::istreambuf_iterator<char>());
|
||||
|
||||
EXPECT_THAT(file_contents, StrEq(file))
|
||||
<< "Contents of " << file << " are different after extraction";
|
||||
fin.close();
|
||||
}
|
||||
|
||||
static int test_count_;
|
||||
static std::string* data_dir_;
|
||||
static std::string* init_wd_;
|
||||
std::string tmp_dir_;
|
||||
std::string id_;
|
||||
|
||||
static constexpr absl::string_view kFile1 = "file1";
|
||||
static constexpr absl::string_view kFile2 = "dir1/file2";
|
||||
static constexpr absl::string_view kFile3 = "dir1/dir2/file3";
|
||||
static constexpr absl::string_view kDir1 = "dir1";
|
||||
static constexpr absl::string_view kDir2 = "dir1/dir2";
|
||||
};
|
||||
|
||||
int MiniTarTest::test_count_;
|
||||
std::string* MiniTarTest::data_dir_;
|
||||
std::string* MiniTarTest::init_wd_;
|
||||
|
||||
// The tests have the following pattern:
|
||||
// 1) From inside the test data directory, call the create function with
|
||||
// different arguments.
|
||||
// 2) Move to the test specific temporary directory created during the
|
||||
// set up phase.
|
||||
// 3) Extract the archive created at step 1.
|
||||
// 4) Check that the files in the archive have been extracted correctly
|
||||
// by first checking if they exist and then checking if the content is the
|
||||
// same as in the original file.
|
||||
TEST_F(MiniTarTest, TestFileSimple) {
|
||||
std::vector<std::string> v = {kFile1.data()};
|
||||
|
||||
ASSERT_THAT(CreateArchive(id_.data(), 0, VecStringToCharPtrArr(v), false),
|
||||
IsOk());
|
||||
|
||||
ASSERT_THAT(chdir(tmp_dir_.data()), Eq(0))
|
||||
<< "Could not chdir into test data directory";
|
||||
|
||||
ASSERT_THAT(ExtractArchive(JoinPath(*data_dir_, id_).data(), 1, 0, false),
|
||||
IsOk());
|
||||
|
||||
CheckFile(std::string(kFile1));
|
||||
}
|
||||
|
||||
TEST_F(MiniTarTest, TestMultipleFiles) {
|
||||
std::vector<std::string> v = {kFile1.data(), kFile2.data(), kFile3.data()};
|
||||
ASSERT_THAT(CreateArchive(id_.data(), 0, VecStringToCharPtrArr(v), false),
|
||||
IsOk());
|
||||
ASSERT_THAT(Exists(id_.data(), false), IsTrue())
|
||||
<< "Archive file was not created";
|
||||
|
||||
ASSERT_THAT(chdir(tmp_dir_.data()), Eq(0))
|
||||
<< "Could not chdir into test data directory";
|
||||
|
||||
ASSERT_THAT(ExtractArchive(JoinPath(*data_dir_, id_).data(), 1, 0, false),
|
||||
IsOk());
|
||||
|
||||
CheckFile(std::string(kFile1));
|
||||
CheckFile(std::string(kFile2));
|
||||
CheckFile(std::string(kFile3));
|
||||
}
|
||||
|
||||
TEST_F(MiniTarTest, TestDirectorySimple) {
|
||||
std::vector<std::string> v = {kDir2.data()};
|
||||
ASSERT_THAT(CreateArchive(id_.data(), 0, VecStringToCharPtrArr(v), false),
|
||||
IsOk());
|
||||
|
||||
ASSERT_THAT(chdir(tmp_dir_.data()), Eq(0))
|
||||
<< "Could not chdir into test data directory";
|
||||
|
||||
ASSERT_THAT(ExtractArchive(JoinPath(*data_dir_, id_).data(), 1, 0, false),
|
||||
IsOk());
|
||||
|
||||
CheckFile(std::string(kFile3));
|
||||
}
|
||||
|
||||
TEST_F(MiniTarTest, TestDirectoryNested) {
|
||||
std::vector<std::string> v = {kDir1.data()};
|
||||
ASSERT_THAT(CreateArchive(id_.data(), 0, VecStringToCharPtrArr(v), false),
|
||||
IsOk());
|
||||
|
||||
ASSERT_THAT(chdir(tmp_dir_.data()), Eq(0))
|
||||
<< "Could not chdir into test data directory";
|
||||
|
||||
ASSERT_THAT(ExtractArchive(JoinPath(*data_dir_, id_).data(), 1, 0, false),
|
||||
IsOk());
|
||||
|
||||
CheckFile(std::string(kFile2));
|
||||
CheckFile(std::string(kFile3));
|
||||
}
|
||||
|
||||
TEST_F(MiniTarTest, TestComplex) {
|
||||
std::vector<std::string> v = {kFile1.data(), kDir1.data()};
|
||||
ASSERT_THAT(CreateArchive(id_.data(), 0, VecStringToCharPtrArr(v), false),
|
||||
IsOk());
|
||||
|
||||
ASSERT_THAT(chdir(tmp_dir_.data()), Eq(0))
|
||||
<< "Could not chdir into test data directory";
|
||||
|
||||
ASSERT_THAT(ExtractArchive(JoinPath(*data_dir_, id_).data(), 1, 0, false),
|
||||
IsOk());
|
||||
|
||||
CheckFile(std::string(kFile1));
|
||||
CheckFile(std::string(kFile2));
|
||||
CheckFile(std::string(kFile3));
|
||||
}
|
||||
|
||||
TEST_F(MiniTarTest, TestCompress) {
|
||||
std::vector<std::string> v = {kFile1.data(), kDir1.data()};
|
||||
int compress = 'Z';
|
||||
ASSERT_THAT(
|
||||
CreateArchive(id_.data(), compress, VecStringToCharPtrArr(v), false),
|
||||
IsOk());
|
||||
|
||||
ASSERT_THAT(chdir(tmp_dir_.data()), Eq(0))
|
||||
<< "Could not chdir into test data directory";
|
||||
ASSERT_THAT(ExtractArchive(JoinPath(*data_dir_, id_).data(), 1, 0, false),
|
||||
IsOk());
|
||||
|
||||
CheckFile(std::string(kFile1));
|
||||
CheckFile(std::string(kFile2));
|
||||
CheckFile(std::string(kFile3));
|
||||
}
|
||||
|
||||
TEST_F(MiniTarTest, TestGZIP) {
|
||||
std::vector<std::string> v = {kFile1.data(), kDir1.data()};
|
||||
int compress = 'z';
|
||||
ASSERT_THAT(
|
||||
CreateArchive(id_.data(), compress, VecStringToCharPtrArr(v), false),
|
||||
IsOk());
|
||||
|
||||
ASSERT_THAT(chdir(tmp_dir_.data()), Eq(0))
|
||||
<< "Could not chdir into test data directory";
|
||||
ASSERT_THAT(ExtractArchive(JoinPath(*data_dir_, id_).data(), 1, 0, false),
|
||||
IsOk());
|
||||
|
||||
CheckFile(std::string(kFile1));
|
||||
CheckFile(std::string(kFile2));
|
||||
CheckFile(std::string(kFile3));
|
||||
}
|
||||
|
||||
TEST_F(MiniTarTest, TestBZIP2) {
|
||||
std::vector<std::string> v = {kFile1.data(), kDir1.data()};
|
||||
int compress = 'j';
|
||||
ASSERT_THAT(
|
||||
CreateArchive(id_.data(), compress, VecStringToCharPtrArr(v), false),
|
||||
IsOk());
|
||||
|
||||
ASSERT_THAT(chdir(tmp_dir_.data()), Eq(0))
|
||||
<< "Could not chdir into test data directory";
|
||||
ASSERT_THAT(ExtractArchive(JoinPath(*data_dir_, id_).data(), 1, 0, false),
|
||||
IsOk());
|
||||
|
||||
CheckFile(std::string(kFile1));
|
||||
CheckFile(std::string(kFile2));
|
||||
CheckFile(std::string(kFile3));
|
||||
}
|
||||
|
||||
TEST_F(MiniTarTest, TestPaths) {
|
||||
// These should be equivalent to kFile1 and kDir1 after cleaning.
|
||||
std::vector<std::string> v = {JoinPath("a/b/../../c/../", kFile1).data(),
|
||||
JoinPath("d/../e/././///../", kDir1).data()};
|
||||
ASSERT_THAT(CreateArchive(id_.data(), 0, VecStringToCharPtrArr(v), false),
|
||||
IsOk());
|
||||
|
||||
ASSERT_THAT(chdir(tmp_dir_.data()), Eq(0))
|
||||
<< "Could not chdir into test data directory";
|
||||
ASSERT_THAT(ExtractArchive(JoinPath(*data_dir_, id_).data(), 1, 0, false),
|
||||
IsOk());
|
||||
|
||||
CheckFile(std::string(kFile1));
|
||||
CheckFile(std::string(kFile2));
|
||||
CheckFile(std::string(kFile3));
|
||||
}
|
||||
|
||||
} // namespace
|
3
oss-internship-2020/lodepng/.gitignore
vendored
Normal file
3
oss-internship-2020/lodepng/.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
build/
|
||||
.clang-format
|
||||
.cache
|
80
oss-internship-2020/lodepng/CMakeLists.txt
Normal file
80
oss-internship-2020/lodepng/CMakeLists.txt
Normal file
|
@ -0,0 +1,80 @@
|
|||
# Copyright 2020 Google LLC
|
||||
#
|
||||
# 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.
|
||||
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
project(lodepng_sapi CXX)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED 17)
|
||||
|
||||
# Apply the patches to the header file.
|
||||
add_custom_command(
|
||||
OUTPUT "${PROJECT_BINARY_DIR}/lodepng/lodepng.h" "${PROJECT_BINARY_DIR}/lodepng/lodepng.cpp"
|
||||
COMMENT "Applying patch to header file."
|
||||
COMMAND cp -r "${PROJECT_SOURCE_DIR}/lodepng" "${PROJECT_BINARY_DIR}/"
|
||||
COMMAND cp "${PROJECT_SOURCE_DIR}/patches/header.patch" "${PROJECT_BINARY_DIR}/lodepng/"
|
||||
COMMAND cd "${PROJECT_BINARY_DIR}/lodepng" && patch < header.patch
|
||||
)
|
||||
|
||||
# Build static library.
|
||||
add_library(lodepng STATIC
|
||||
"${PROJECT_BINARY_DIR}/lodepng/lodepng.cpp"
|
||||
"${PROJECT_BINARY_DIR}/lodepng/lodepng.h"
|
||||
)
|
||||
|
||||
target_include_directories(lodepng PUBLIC "${PROJECT_BINARY_DIR}/lodepng")
|
||||
|
||||
# Build SAPI library
|
||||
set(SAPI_ROOT "" CACHE PATH "Path to the Sandboxed API source tree")
|
||||
|
||||
add_subdirectory("${SAPI_ROOT}"
|
||||
"${CMAKE_BINARY_DIR}/sandboxed-api-build"
|
||||
EXCLUDE_FROM_ALL
|
||||
)
|
||||
|
||||
add_sapi_library(
|
||||
lodepng_sapi
|
||||
|
||||
FUNCTIONS
|
||||
lodepng_decode_memory
|
||||
lodepng_decode32
|
||||
lodepng_decode24
|
||||
|
||||
lodepng_decode_file
|
||||
lodepng_decode32_file
|
||||
lodepng_decode24_file
|
||||
|
||||
lodepng_encode_memory
|
||||
lodepng_encode32
|
||||
lodepng_encode24
|
||||
|
||||
lodepng_encode_file
|
||||
lodepng_encode32_file
|
||||
lodepng_encode24_file
|
||||
|
||||
lodepng_save_file
|
||||
lodepng_load_file
|
||||
|
||||
INPUTS "${PROJECT_BINARY_DIR}/lodepng/lodepng.h"
|
||||
LIBRARY lodepng
|
||||
LIBRARY_NAME Lodepng
|
||||
NAMESPACE ""
|
||||
)
|
||||
|
||||
target_include_directories(lodepng_sapi INTERFACE
|
||||
"${PROJECT_BINARY_DIR}" # To find the generated SAPI header
|
||||
)
|
||||
|
||||
add_subdirectory(examples)
|
42
oss-internship-2020/lodepng/README.md
Normal file
42
oss-internship-2020/lodepng/README.md
Normal file
|
@ -0,0 +1,42 @@
|
|||
# LodePNG Sandboxed API
|
||||
|
||||
Sandboxed version of the [LodePNG](https://github.com/lvandeve/lodepng) library, using [Sandboxed API](https://github.com/google/sandboxed-api)
|
||||
|
||||
## Details
|
||||
|
||||
With Sandboxed API, many of the library's functions can be sandboxed. However, they need the `extern "C"` keyword defined so that name mangling does not happen, which is why a patch that adds it is used. The only differences are found in the header file. An alternative to this is to define another library that wraps every needed function, specifying the required keyword.
|
||||
|
||||
Even if many of the functions from the library can be sandboxed, there are some that are not supported (those which have `std::vector` parameters, overloaded functions etc.). If you really need these functions, a solution is to implement a custom library that wraps around these functions in order to make them compatible.
|
||||
|
||||
## Patches
|
||||
|
||||
In the **patches** folder there is a patch file that adds `extern "C"` to the required functions in the header file in order to sandbox them. This patch is applied automatically during the build phase.
|
||||
|
||||
## Build
|
||||
|
||||
First, run `git submodule update --init --recursive` to update submodules.
|
||||
After this, run the following commands:
|
||||
|
||||
`mkdir -p build && cd build`
|
||||
|
||||
`cmake .. -G Ninja`
|
||||
|
||||
`cmake --build .`
|
||||
|
||||
|
||||
The example binary files can be found in `build/examples`.
|
||||
|
||||
## Examples
|
||||
|
||||
The code found in the **examples** folder features a basic use case of the library. An image is generated, encoded into a file and then decoded to check that the values are the same. The encoding part was based on [this example](https://github.com/lvandeve/lodepng/blob/master/examples/example_encode.c) while decoding was based on [this](https://github.com/lvandeve/lodepng/blob/master/examples/example_decode.c).
|
||||
|
||||
This example code is structured as:
|
||||
- `main_unsandboxed.cc` - unsandboxed example
|
||||
- `main_sandboxed.cc` - sandboxed version of the example
|
||||
- `main_unit_test.cc` - tests(using [Google Test](https://github.com/google/googletest)).
|
||||
|
||||
On top of those files, there are other files used by all three of the examples:
|
||||
- `sandbox.h` - custom sandbox policy
|
||||
- `helpers.h` and `helpers.cc` - constants and functions used in the main files.
|
||||
|
||||
The executables generated from these files will create a temporary directory in the current working path. Inside that directory the two generated **png** files will be created. At the end, the directory is deleted. If those programs do not stop midway or return a failure code, then everything works fine.
|
70
oss-internship-2020/lodepng/examples/CMakeLists.txt
Normal file
70
oss-internship-2020/lodepng/examples/CMakeLists.txt
Normal file
|
@ -0,0 +1,70 @@
|
|||
# Copyright 2020 Google LLC
|
||||
#
|
||||
# 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.
|
||||
|
||||
# Build the unsandboxed main
|
||||
add_executable(lodepng_unsandboxed
|
||||
main_unsandboxed.cc
|
||||
helpers.cc
|
||||
)
|
||||
|
||||
target_link_libraries(lodepng_unsandboxed PRIVATE
|
||||
lodepng
|
||||
sapi::sapi
|
||||
sandbox2::temp_file
|
||||
sandbox2::file_base
|
||||
sandbox2::fileops
|
||||
glog::glog
|
||||
)
|
||||
|
||||
# Build the sandboxed main
|
||||
add_executable(lodepng_sandboxed
|
||||
main_sandboxed.cc
|
||||
sandbox.h
|
||||
helpers.cc
|
||||
)
|
||||
|
||||
target_link_libraries(lodepng_sandboxed PRIVATE
|
||||
lodepng_sapi
|
||||
sapi::sapi
|
||||
sandbox2::temp_file
|
||||
sandbox2::fileops
|
||||
sapi::vars
|
||||
sapi::status
|
||||
glog::glog
|
||||
)
|
||||
|
||||
# Build the unit tests
|
||||
include(GoogleTest)
|
||||
enable_testing()
|
||||
|
||||
add_executable(main_unit_test
|
||||
main_unit_test.cc
|
||||
helpers.cc
|
||||
)
|
||||
|
||||
target_link_libraries(main_unit_test PRIVATE
|
||||
lodepng_sapi
|
||||
absl::memory
|
||||
absl::strings
|
||||
absl::time
|
||||
glog::glog
|
||||
sapi::flags
|
||||
sapi::sapi
|
||||
sandbox2::temp_file
|
||||
sandbox2::fileops
|
||||
sapi::status
|
||||
sapi::test_main
|
||||
sapi::vars
|
||||
)
|
||||
gtest_discover_tests(main_unit_test)
|
43
oss-internship-2020/lodepng/examples/helpers.cc
Normal file
43
oss-internship-2020/lodepng/examples/helpers.cc
Normal file
|
@ -0,0 +1,43 @@
|
|||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// 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 "helpers.h" // NOLINT(build/include)
|
||||
|
||||
#include "sandboxed_api/sandbox2/util/temp_file.h"
|
||||
|
||||
std::vector<uint8_t> GenerateValues() {
|
||||
std::vector<uint8_t> image;
|
||||
image.reserve(kImgLen);
|
||||
|
||||
for (int y = 0; y < kHeight; ++y) {
|
||||
for (int x = 0; x < kWidth; ++x) {
|
||||
image.push_back(255 * !(x & y));
|
||||
image.push_back(x ^ y);
|
||||
image.push_back(x | y);
|
||||
image.push_back(255);
|
||||
}
|
||||
}
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
std::string CreateTempDirAtCWD() {
|
||||
std::string cwd = sandbox2::file_util::fileops::GetCWD();
|
||||
CHECK(!cwd.empty()) << "Could not get current working directory";
|
||||
cwd.append("/");
|
||||
|
||||
absl::StatusOr<std::string> result = sandbox2::CreateTempDir(cwd);
|
||||
CHECK(result.ok()) << "Could not create temporary directory";
|
||||
return result.value();
|
||||
}
|
39
oss-internship-2020/lodepng/examples/helpers.h
Normal file
39
oss-internship-2020/lodepng/examples/helpers.h
Normal file
|
@ -0,0 +1,39 @@
|
|||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// 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 LODEPNG_EXAMPLES_HELPERS_H_
|
||||
#define LODEPNG_EXAMPLES_HELPERS_H_
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
#include <glog/logging.h>
|
||||
#include "sandboxed_api/sandbox2/util/fileops.h"
|
||||
#include "sandboxed_api/sandbox2/util/temp_file.h"
|
||||
|
||||
inline constexpr size_t kWidth = 512;
|
||||
inline constexpr size_t kHeight = 512;
|
||||
inline constexpr size_t kImgLen = kWidth * kHeight * 4;
|
||||
|
||||
// Returns a vector that contains values used for testing.
|
||||
// This part of code is taken from
|
||||
// https://github.com/lvandeve/lodepng/blob/master/examples/example_encode.c#L96-L104.
|
||||
// The generated image contains square fractals.
|
||||
std::vector<uint8_t> GenerateValues();
|
||||
|
||||
// Creates a temporary directory in the current working directory and returns
|
||||
// the path.
|
||||
std::string CreateTempDirAtCWD();
|
||||
|
||||
#endif // LODEPNG_EXAMPLES_HELPERS_H_
|
193
oss-internship-2020/lodepng/examples/main_sandboxed.cc
Normal file
193
oss-internship-2020/lodepng/examples/main_sandboxed.cc
Normal file
|
@ -0,0 +1,193 @@
|
|||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// 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 <iostream>
|
||||
|
||||
#include <glog/logging.h>
|
||||
#include "helpers.h" // NOLINT(build/include)
|
||||
#include "sandbox.h" // NOLINT(build/include)
|
||||
|
||||
void EncodeDecodeOneStep(SapiLodepngSandbox& sandbox, LodepngApi& api) {
|
||||
// Generate the values.
|
||||
std::vector<uint8_t> image = GenerateValues();
|
||||
|
||||
// Encode the image.
|
||||
sapi::v::Array<uint8_t> sapi_image(kImgLen);
|
||||
CHECK(std::copy(image.begin(), image.end(), sapi_image.GetData()))
|
||||
<< "Could not copy values";
|
||||
|
||||
sapi::v::ConstCStr sapi_filename("/output/out_generated1.png");
|
||||
|
||||
absl::StatusOr<unsigned int> result = api.lodepng_encode32_file(
|
||||
sapi_filename.PtrBefore(), sapi_image.PtrBefore(), kWidth, kHeight);
|
||||
|
||||
CHECK(result.ok()) << "encode32_file call failed";
|
||||
CHECK(!result.value()) << "Unexpected result from encode32_file call";
|
||||
|
||||
// After the image has been encoded, decode it to check that the
|
||||
// pixel values are the same.
|
||||
sapi::v::UInt sapi_width, sapi_height;
|
||||
sapi::v::IntBase<uint8_t*> sapi_image_ptr(0);
|
||||
|
||||
result = api.lodepng_decode32_file(
|
||||
sapi_image_ptr.PtrBoth(), sapi_width.PtrBoth(), sapi_height.PtrBoth(),
|
||||
sapi_filename.PtrBefore());
|
||||
|
||||
CHECK(result.ok()) << "decode32_file call failes";
|
||||
CHECK(!result.value()) << "Unexpected result from decode32_file call";
|
||||
|
||||
CHECK(sapi_width.GetValue() == kWidth) << "Widths differ";
|
||||
CHECK(sapi_height.GetValue() == kHeight) << "Heights differ";
|
||||
|
||||
// The pixels have been allocated inside the sandboxed process
|
||||
// memory, so we need to transfer them to this process.
|
||||
// Transferring the memory has the following steps:
|
||||
// 1) define an array with the required length.
|
||||
// 2) set the remote pointer for the array to specify where the memory
|
||||
// that will be transferred is located.
|
||||
// 3) transfer the memory to this process (this step is why we need
|
||||
// the pointer and the length).
|
||||
sapi::v::Array<uint8_t> sapi_pixels(kImgLen);
|
||||
sapi_pixels.SetRemote(sapi_image_ptr.GetValue());
|
||||
|
||||
CHECK(sandbox.TransferFromSandboxee(&sapi_pixels).ok())
|
||||
<< "Error during transfer from sandboxee";
|
||||
|
||||
// Now, we can compare the values.
|
||||
CHECK(absl::equal(image.begin(), image.end(), sapi_pixels.GetData(),
|
||||
sapi_pixels.GetData() + kImgLen))
|
||||
<< "Values differ";
|
||||
|
||||
// Free the memory allocated inside the sandbox.
|
||||
CHECK(sandbox.GetRpcChannel()->Free(sapi_image_ptr.GetValue()).ok())
|
||||
<< "Could not free memory inside sandboxed process";
|
||||
}
|
||||
|
||||
void EncodeDecodeTwoSteps(SapiLodepngSandbox& sandbox, LodepngApi& api) {
|
||||
// Generate the values.
|
||||
std::vector<uint8_t> image = GenerateValues();
|
||||
|
||||
// Encode the image into memory first.
|
||||
sapi::v::Array<uint8_t> sapi_image(kImgLen);
|
||||
CHECK(std::copy(image.begin(), image.end(), sapi_image.GetData()))
|
||||
<< "Could not copy values";
|
||||
|
||||
sapi::v::ConstCStr sapi_filename("/output/out_generated2.png");
|
||||
|
||||
sapi::v::ULLong sapi_pngsize;
|
||||
sapi::v::IntBase<uint8_t*> sapi_png_ptr(0);
|
||||
|
||||
// Encode it into memory.
|
||||
absl::StatusOr<unsigned int> result =
|
||||
api.lodepng_encode32(sapi_png_ptr.PtrBoth(), sapi_pngsize.PtrBoth(),
|
||||
sapi_image.PtrBefore(), kWidth, kHeight);
|
||||
|
||||
CHECK(result.ok()) << "encode32 call failed";
|
||||
CHECK(!result.value()) << "Unexpected result from encode32 call";
|
||||
|
||||
// The new array (pointed to by sapi_png_ptr) is allocated
|
||||
// inside the sandboxed process so we need to transfer it to this
|
||||
// process.
|
||||
sapi::v::Array<uint8_t> sapi_png_array(sapi_pngsize.GetValue());
|
||||
sapi_png_array.SetRemote(sapi_png_ptr.GetValue());
|
||||
|
||||
CHECK(sandbox.TransferFromSandboxee(&sapi_png_array).ok())
|
||||
<< "Error during transfer from sandboxee";
|
||||
|
||||
// Write the image into the file (from memory).
|
||||
result =
|
||||
api.lodepng_save_file(sapi_png_array.PtrBefore(), sapi_pngsize.GetValue(),
|
||||
sapi_filename.PtrBefore());
|
||||
|
||||
CHECK(result.ok()) << "save_file call failed";
|
||||
CHECK(!result.value()) << "Unexpected result from save_file call";
|
||||
|
||||
// Now, decode the image using the 2 steps in order to compare the values.
|
||||
sapi::v::UInt sapi_width, sapi_height;
|
||||
sapi::v::IntBase<uint8_t*> sapi_png_ptr2(0);
|
||||
sapi::v::ULLong sapi_pngsize2;
|
||||
|
||||
// Load the file in memory.
|
||||
result =
|
||||
api.lodepng_load_file(sapi_png_ptr2.PtrBoth(), sapi_pngsize2.PtrBoth(),
|
||||
sapi_filename.PtrBefore());
|
||||
|
||||
CHECK(result.ok()) << "load_file call failed";
|
||||
CHECK(!result.value()) << "Unexpected result from load_file call";
|
||||
|
||||
CHECK(sapi_pngsize.GetValue() == sapi_pngsize2.GetValue())
|
||||
<< "Png sizes differ";
|
||||
|
||||
// Transfer the png array.
|
||||
sapi::v::Array<uint8_t> sapi_png_array2(sapi_pngsize2.GetValue());
|
||||
sapi_png_array2.SetRemote(sapi_png_ptr2.GetValue());
|
||||
|
||||
CHECK(sandbox.TransferFromSandboxee(&sapi_png_array2).ok())
|
||||
<< "Error during transfer from sandboxee";
|
||||
|
||||
// After the file is loaded, decode it so we have access to the values
|
||||
// directly.
|
||||
sapi::v::IntBase<uint8_t*> sapi_png_ptr3(0);
|
||||
result = api.lodepng_decode32(
|
||||
sapi_png_ptr3.PtrBoth(), sapi_width.PtrBoth(), sapi_height.PtrBoth(),
|
||||
sapi_png_array2.PtrBefore(), sapi_pngsize2.GetValue());
|
||||
|
||||
CHECK(result.ok()) << "decode32 call failed";
|
||||
CHECK(!result.value()) << "Unexpected result from decode32 call";
|
||||
|
||||
CHECK(sapi_width.GetValue() == kWidth) << "Widths differ";
|
||||
CHECK(sapi_height.GetValue() == kHeight) << "Heights differ";
|
||||
|
||||
// Transfer the pixels so they can be used here.
|
||||
sapi::v::Array<uint8_t> sapi_pixels(kImgLen);
|
||||
sapi_pixels.SetRemote(sapi_png_ptr3.GetValue());
|
||||
|
||||
CHECK(sandbox.TransferFromSandboxee(&sapi_pixels).ok())
|
||||
<< "Error during transfer from sandboxee";
|
||||
|
||||
// Compare the values.
|
||||
CHECK(absl::equal(image.begin(), image.end(), sapi_pixels.GetData(),
|
||||
sapi_pixels.GetData() + kImgLen))
|
||||
<< "Values differ";
|
||||
|
||||
// Free the memory allocated inside the sandbox.
|
||||
CHECK(sandbox.GetRpcChannel()->Free(sapi_png_ptr.GetValue()).ok())
|
||||
<< "Could not free memory inside sandboxed process";
|
||||
CHECK(sandbox.GetRpcChannel()->Free(sapi_png_ptr2.GetValue()).ok())
|
||||
<< "Could not free memory inside sandboxed process";
|
||||
CHECK(sandbox.GetRpcChannel()->Free(sapi_png_ptr3.GetValue()).ok())
|
||||
<< "Could not free memory inside sandboxed process";
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
google::InitGoogleLogging(argv[0]);
|
||||
|
||||
const std::string images_path = CreateTempDirAtCWD();
|
||||
CHECK(sandbox2::file_util::fileops::Exists(images_path, false))
|
||||
<< "Temporary directory does not exist";
|
||||
|
||||
SapiLodepngSandbox sandbox(images_path);
|
||||
CHECK(sandbox.Init().ok()) << "Error during sandbox initialization";
|
||||
|
||||
LodepngApi api(&sandbox);
|
||||
|
||||
EncodeDecodeOneStep(sandbox, api);
|
||||
EncodeDecodeTwoSteps(sandbox, api);
|
||||
|
||||
if (sandbox2::file_util::fileops::DeleteRecursively(images_path)) {
|
||||
LOG(WARNING) << "Temporary folder could not be deleted";
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
213
oss-internship-2020/lodepng/examples/main_unit_test.cc
Normal file
213
oss-internship-2020/lodepng/examples/main_unit_test.cc
Normal file
|
@ -0,0 +1,213 @@
|
|||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// 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 "helpers.h" // NOLINT(build/include)
|
||||
#include "sandbox.h" // NOLINT(build/include)
|
||||
#include "gtest/gtest.h"
|
||||
#include "sandboxed_api/util/status_matchers.h"
|
||||
|
||||
using ::sapi::IsOk;
|
||||
using ::testing::Eq;
|
||||
using ::testing::IsTrue;
|
||||
using ::testing::NotNull;
|
||||
|
||||
namespace {
|
||||
|
||||
TEST(HelpersTest, CreateTempDirAtCWD) {
|
||||
const std::string images_path = CreateTempDirAtCWD();
|
||||
ASSERT_THAT(sandbox2::file_util::fileops::Exists(images_path, false),
|
||||
IsTrue())
|
||||
<< "Temporary directory does not exist";
|
||||
|
||||
EXPECT_THAT(sandbox2::file_util::fileops::DeleteRecursively(images_path),
|
||||
IsTrue())
|
||||
<< "Temporary directory could not be deleted";
|
||||
}
|
||||
|
||||
TEST(HelpersTest, GenerateValues) {
|
||||
EXPECT_THAT(GenerateValues().size(), Eq(kImgLen));
|
||||
}
|
||||
|
||||
TEST(LodePngTest, Init) {
|
||||
const std::string images_path = CreateTempDirAtCWD();
|
||||
ASSERT_THAT(sandbox2::file_util::fileops::Exists(images_path, false),
|
||||
IsTrue())
|
||||
<< "Temporary directory does not exist";
|
||||
|
||||
SapiLodepngSandbox sandbox(images_path);
|
||||
ASSERT_THAT(sandbox.Init(), IsOk()) << "Error during sandbox init";
|
||||
|
||||
EXPECT_THAT(sandbox2::file_util::fileops::DeleteRecursively(images_path),
|
||||
IsTrue())
|
||||
<< "Temporary directory could not be deleted";
|
||||
}
|
||||
|
||||
// Generate an image, encode it, decode it and compare the pixels with the
|
||||
// initial values.
|
||||
TEST(LodePngTest, EncodeDecodeOneStep) {
|
||||
const std::string images_path = CreateTempDirAtCWD();
|
||||
ASSERT_THAT(sandbox2::file_util::fileops::Exists(images_path, false),
|
||||
IsTrue())
|
||||
<< "Temporary directory does not exist";
|
||||
|
||||
SapiLodepngSandbox sandbox(images_path);
|
||||
ASSERT_THAT(sandbox.Init(), IsOk()) << "Error during sandbox initialization";
|
||||
LodepngApi api(&sandbox);
|
||||
|
||||
std::vector<uint8_t> image = GenerateValues();
|
||||
|
||||
sapi::v::Array<uint8_t> sapi_image(kImgLen);
|
||||
EXPECT_THAT(std::copy(image.begin(), image.end(), sapi_image.GetData()),
|
||||
IsTrue())
|
||||
<< "Could not copy values";
|
||||
|
||||
sapi::v::ConstCStr sapi_filename("/output/out_generated1.png");
|
||||
|
||||
SAPI_ASSERT_OK_AND_ASSIGN(
|
||||
unsigned int result,
|
||||
api.lodepng_encode32_file(sapi_filename.PtrBefore(),
|
||||
sapi_image.PtrBefore(), kWidth, kHeight));
|
||||
|
||||
ASSERT_THAT(result, Eq(0)) << "Unexpected result from encode32_file call";
|
||||
|
||||
sapi::v::UInt sapi_width, sapi_height;
|
||||
sapi::v::IntBase<uint8_t*> sapi_image_ptr(0);
|
||||
|
||||
SAPI_ASSERT_OK_AND_ASSIGN(result,
|
||||
api.lodepng_decode32_file(
|
||||
sapi_image_ptr.PtrBoth(), sapi_width.PtrBoth(),
|
||||
sapi_height.PtrBoth(), sapi_filename.PtrBefore()));
|
||||
|
||||
ASSERT_THAT(result, Eq(0)) << "Unexpected result from decode32_file call";
|
||||
|
||||
EXPECT_THAT(sapi_width.GetValue(), Eq(kWidth)) << "Widths differ";
|
||||
EXPECT_THAT(sapi_height.GetValue(), Eq(kHeight)) << "Heights differ";
|
||||
|
||||
sapi::v::Array<uint8_t> sapi_pixels(kImgLen);
|
||||
sapi_pixels.SetRemote(sapi_image_ptr.GetValue());
|
||||
|
||||
ASSERT_THAT(sandbox.TransferFromSandboxee(&sapi_pixels), IsOk())
|
||||
<< "Error during transfer from sandboxee";
|
||||
|
||||
EXPECT_THAT(absl::equal(image.begin(), image.end(), sapi_pixels.GetData(),
|
||||
sapi_pixels.GetData() + kImgLen),
|
||||
IsTrue())
|
||||
<< "Values differ";
|
||||
|
||||
EXPECT_THAT(sandbox.GetRpcChannel()->Free(sapi_image_ptr.GetValue()), IsOk())
|
||||
<< "Could not free memory inside sandboxed process";
|
||||
|
||||
EXPECT_THAT(sandbox2::file_util::fileops::DeleteRecursively(images_path),
|
||||
IsTrue())
|
||||
<< "Temporary directory could not be deleted";
|
||||
}
|
||||
|
||||
// Similar to the previous test, only that we use encoding by saving the data in
|
||||
// memory and then writing it to the file and decoding by first decoding in
|
||||
// memory and then getting the actual pixel values.
|
||||
TEST(LodePngTest, EncodeDecodeTwoSteps) {
|
||||
const std::string images_path = CreateTempDirAtCWD();
|
||||
ASSERT_THAT(sandbox2::file_util::fileops::Exists(images_path, false),
|
||||
IsTrue())
|
||||
<< "Temporary directory does not exist";
|
||||
|
||||
SapiLodepngSandbox sandbox(images_path);
|
||||
ASSERT_THAT(sandbox.Init(), IsOk()) << "Error during sandbox init";
|
||||
LodepngApi api(&sandbox);
|
||||
|
||||
std::vector<uint8_t> image = GenerateValues();
|
||||
|
||||
sapi::v::Array<uint8_t> sapi_image(kImgLen);
|
||||
EXPECT_THAT(std::copy(image.begin(), image.end(), sapi_image.GetData()),
|
||||
IsTrue())
|
||||
<< "Could not copy values";
|
||||
|
||||
sapi::v::ConstCStr sapi_filename("/output/out_generated2.png");
|
||||
|
||||
sapi::v::ULLong sapi_pngsize;
|
||||
sapi::v::IntBase<uint8_t*> sapi_png_ptr(0);
|
||||
|
||||
SAPI_ASSERT_OK_AND_ASSIGN(
|
||||
unsigned int result,
|
||||
api.lodepng_encode32(sapi_png_ptr.PtrBoth(), sapi_pngsize.PtrBoth(),
|
||||
sapi_image.PtrBefore(), kWidth, kHeight));
|
||||
|
||||
ASSERT_THAT(result, Eq(0)) << "Unexpected result from encode32 call";
|
||||
|
||||
sapi::v::Array<uint8_t> sapi_png_array(sapi_pngsize.GetValue());
|
||||
sapi_png_array.SetRemote(sapi_png_ptr.GetValue());
|
||||
|
||||
ASSERT_THAT(sandbox.TransferFromSandboxee(&sapi_png_array), IsOk())
|
||||
<< "Error during transfer from sandboxee";
|
||||
|
||||
SAPI_ASSERT_OK_AND_ASSIGN(
|
||||
result,
|
||||
api.lodepng_save_file(sapi_png_array.PtrBefore(), sapi_pngsize.GetValue(),
|
||||
sapi_filename.PtrBefore()));
|
||||
|
||||
ASSERT_THAT(result, Eq(0)) << "Unexpected result from save_file call";
|
||||
|
||||
sapi::v::UInt sapi_width, sapi_height;
|
||||
sapi::v::IntBase<uint8_t*> sapi_png_ptr2(0);
|
||||
sapi::v::ULLong sapi_pngsize2;
|
||||
|
||||
SAPI_ASSERT_OK_AND_ASSIGN(
|
||||
result,
|
||||
api.lodepng_load_file(sapi_png_ptr2.PtrBoth(), sapi_pngsize2.PtrBoth(),
|
||||
sapi_filename.PtrBefore()));
|
||||
|
||||
ASSERT_THAT(result, Eq(0)) << "Unexpected result from load_file call";
|
||||
|
||||
EXPECT_THAT(sapi_pngsize.GetValue(), Eq(sapi_pngsize2.GetValue()))
|
||||
<< "Png sizes differ";
|
||||
|
||||
sapi::v::Array<uint8_t> sapi_png_array2(sapi_pngsize2.GetValue());
|
||||
sapi_png_array2.SetRemote(sapi_png_ptr2.GetValue());
|
||||
|
||||
ASSERT_THAT(sandbox.TransferFromSandboxee(&sapi_png_array2), IsOk())
|
||||
<< "Error during transfer from sandboxee";
|
||||
|
||||
sapi::v::IntBase<uint8_t*> sapi_png_ptr3(0);
|
||||
SAPI_ASSERT_OK_AND_ASSIGN(
|
||||
result,
|
||||
api.lodepng_decode32(sapi_png_ptr3.PtrBoth(), sapi_width.PtrBoth(),
|
||||
sapi_height.PtrBoth(), sapi_png_array2.PtrBefore(),
|
||||
sapi_pngsize2.GetValue()));
|
||||
|
||||
ASSERT_THAT(result, Eq(0)) << "Unexpected result from decode32 call";
|
||||
|
||||
EXPECT_THAT(sapi_width.GetValue(), Eq(kWidth)) << "Widths differ";
|
||||
EXPECT_THAT(sapi_height.GetValue(), Eq(kHeight)) << "Heights differ";
|
||||
|
||||
sapi::v::Array<uint8_t> sapi_pixels(kImgLen);
|
||||
sapi_pixels.SetRemote(sapi_png_ptr3.GetValue());
|
||||
|
||||
ASSERT_THAT(sandbox.TransferFromSandboxee(&sapi_pixels), IsOk())
|
||||
<< "Error during transfer from sandboxee";
|
||||
|
||||
EXPECT_THAT(absl::equal(image.begin(), image.end(), sapi_pixels.GetData(),
|
||||
sapi_pixels.GetData() + kImgLen),
|
||||
IsTrue())
|
||||
<< "Values differ";
|
||||
|
||||
EXPECT_THAT(sandbox.GetRpcChannel()->Free(sapi_png_ptr.GetValue()), IsOk());
|
||||
EXPECT_THAT(sandbox.GetRpcChannel()->Free(sapi_png_ptr2.GetValue()), IsOk());
|
||||
EXPECT_THAT(sandbox.GetRpcChannel()->Free(sapi_png_ptr3.GetValue()), IsOk());
|
||||
|
||||
EXPECT_THAT(sandbox2::file_util::fileops::DeleteRecursively(images_path),
|
||||
IsTrue())
|
||||
<< "Temporary directory could not be deleted";
|
||||
}
|
||||
|
||||
} // namespace
|
116
oss-internship-2020/lodepng/examples/main_unsandboxed.cc
Normal file
116
oss-internship-2020/lodepng/examples/main_unsandboxed.cc
Normal file
|
@ -0,0 +1,116 @@
|
|||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// 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 <iostream>
|
||||
|
||||
#include <glog/logging.h>
|
||||
#include "helpers.h" // NOLINT(build/include)
|
||||
#include "lodepng.h" // NOLINT(build/include)
|
||||
#include "sandboxed_api/sandbox2/util/fileops.h"
|
||||
#include "sandboxed_api/sandbox2/util/path.h"
|
||||
|
||||
void EncodeDecodeOneStep(const std::string& images_path) {
|
||||
// Generate the values.
|
||||
std::vector<uint8_t> image = GenerateValues();
|
||||
|
||||
// Encode the image.
|
||||
const std::string filename =
|
||||
sandbox2::file::JoinPath(images_path, "/out_generated1.png");
|
||||
unsigned int result =
|
||||
lodepng_encode32_file(filename.c_str(), image.data(), kWidth, kHeight);
|
||||
|
||||
CHECK(!result) << "Unexpected result from encode32_file call";
|
||||
|
||||
// After the image has been encoded, decode it to check that the
|
||||
// pixel values are the same.
|
||||
unsigned int width, height;
|
||||
uint8_t* image2 = 0;
|
||||
|
||||
result = lodepng_decode32_file(&image2, &width, &height, filename.c_str());
|
||||
|
||||
CHECK(!result) << "Unexpected result from decode32_file call";
|
||||
|
||||
CHECK(width == kWidth) << "Widths differ";
|
||||
CHECK(height == kHeight) << "Heights differ";
|
||||
|
||||
// Now, we can compare the values.
|
||||
CHECK(absl::equal(image.begin(), image.end(), image2, image2 + kImgLen))
|
||||
<< "Values differ";
|
||||
|
||||
free(image2);
|
||||
}
|
||||
|
||||
void EncodeDecodeTwoSteps(const std::string& images_path) {
|
||||
// Generate the values.
|
||||
std::vector<uint8_t> image = GenerateValues();
|
||||
|
||||
// Encode the image into memory first.
|
||||
const std::string filename =
|
||||
sandbox2::file::JoinPath(images_path, "/out_generated2.png");
|
||||
uint8_t* png;
|
||||
size_t pngsize;
|
||||
|
||||
unsigned int result =
|
||||
lodepng_encode32(&png, &pngsize, image.data(), kWidth, kHeight);
|
||||
|
||||
CHECK(!result) << "Unexpected result from encode32 call";
|
||||
|
||||
// Write the image into the file (from memory).
|
||||
result = lodepng_save_file(png, pngsize, filename.c_str());
|
||||
|
||||
CHECK(!result) << "Unexpected result from save_file call";
|
||||
|
||||
// Now, decode the image using the 2 steps in order to compare the values.
|
||||
unsigned int width, height;
|
||||
uint8_t* png2;
|
||||
size_t pngsize2;
|
||||
|
||||
// Load the file in memory.
|
||||
result = lodepng_load_file(&png2, &pngsize2, filename.c_str());
|
||||
|
||||
CHECK(!result) << "Unexpected result from load_file call";
|
||||
CHECK(pngsize == pngsize2) << "Png sizes differ";
|
||||
|
||||
uint8_t* image2;
|
||||
result = lodepng_decode32(&image2, &width, &height, png2, pngsize2);
|
||||
|
||||
CHECK(!result) << "Unexpected result from decode32 call";
|
||||
CHECK(width == kWidth) << "Widths differ";
|
||||
CHECK(height == kHeight) << "Heights differ";
|
||||
|
||||
// Compare the values.
|
||||
CHECK(absl::equal(image.begin(), image.end(), image2, image2 + kImgLen))
|
||||
<< "Values differ";
|
||||
|
||||
free(png);
|
||||
free(png2);
|
||||
free(image2);
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
google::InitGoogleLogging(argv[0]);
|
||||
|
||||
const std::string images_path = CreateTempDirAtCWD();
|
||||
CHECK(sandbox2::file_util::fileops::Exists(images_path, false))
|
||||
<< "Temporary directory does not exist";
|
||||
|
||||
EncodeDecodeOneStep(images_path);
|
||||
EncodeDecodeTwoSteps(images_path);
|
||||
|
||||
if (sandbox2::file_util::fileops::DeleteRecursively(images_path)) {
|
||||
LOG(WARNING) << "Temporary folder could not be deleted";
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
49
oss-internship-2020/lodepng/examples/sandbox.h
Normal file
49
oss-internship-2020/lodepng/examples/sandbox.h
Normal file
|
@ -0,0 +1,49 @@
|
|||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// 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 LODEPNG_EXAMPLES_SANDBOX_H_
|
||||
#define LODEPNG_EXAMPLES_SANDBOX_H_
|
||||
|
||||
#include <syscall.h>
|
||||
|
||||
#include "lodepng_sapi.sapi.h" // NOLINT(build/include)
|
||||
|
||||
class SapiLodepngSandbox : public LodepngSandbox {
|
||||
public:
|
||||
explicit SapiLodepngSandbox(const std::string& images_path)
|
||||
: images_path_(images_path) {}
|
||||
|
||||
private:
|
||||
std::unique_ptr<sandbox2::Policy> ModifyPolicy(
|
||||
sandbox2::PolicyBuilder*) override {
|
||||
return sandbox2::PolicyBuilder()
|
||||
.AllowRead()
|
||||
.AllowWrite()
|
||||
.AllowOpen()
|
||||
.AllowSystemMalloc()
|
||||
.AllowExit()
|
||||
.AllowStat()
|
||||
.AddDirectoryAt(images_path_, "/output/", /*is_ro=*/false)
|
||||
.AllowSyscalls({
|
||||
__NR_futex,
|
||||
__NR_lseek,
|
||||
__NR_close,
|
||||
})
|
||||
.BuildOrDie();
|
||||
}
|
||||
|
||||
const std::string images_path_;
|
||||
};
|
||||
|
||||
#endif // LODEPNG_EXAMPLES_SANDBOX__
|
86
oss-internship-2020/lodepng/patches/header.patch
Normal file
86
oss-internship-2020/lodepng/patches/header.patch
Normal file
|
@ -0,0 +1,86 @@
|
|||
--- lodepng.h 2020-09-11 08:41:22.280259945 +0000
|
||||
+++ lodepng2.h 2020-09-11 08:45:17.134266042 +0000
|
||||
@@ -89,6 +89,8 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
+
|
||||
+
|
||||
#ifdef LODEPNG_COMPILE_CPP
|
||||
#include <vector>
|
||||
#include <string>
|
||||
@@ -126,6 +128,9 @@
|
||||
bitdepth: the desired bit depth for the raw output image. See explanation on PNG color types.
|
||||
Return value: LodePNG error code (0 means no error).
|
||||
*/
|
||||
+
|
||||
+extern "C" {
|
||||
+
|
||||
unsigned lodepng_decode_memory(unsigned char** out, unsigned* w, unsigned* h,
|
||||
const unsigned char* in, size_t insize,
|
||||
LodePNGColorType colortype, unsigned bitdepth);
|
||||
@@ -154,10 +159,12 @@
|
||||
/*Same as lodepng_decode_file, but always decodes to 24-bit RGB raw image.*/
|
||||
unsigned lodepng_decode24_file(unsigned char** out, unsigned* w, unsigned* h,
|
||||
const char* filename);
|
||||
+
|
||||
#endif /*LODEPNG_COMPILE_DISK*/
|
||||
#endif /*LODEPNG_COMPILE_DECODER*/
|
||||
|
||||
|
||||
+
|
||||
#ifdef LODEPNG_COMPILE_ENCODER
|
||||
/*
|
||||
Converts raw pixel data into a PNG image in memory. The colortype and bitdepth
|
||||
@@ -204,6 +211,9 @@
|
||||
/*Same as lodepng_encode_file, but always encodes from 24-bit RGB raw image.*/
|
||||
unsigned lodepng_encode24_file(const char* filename,
|
||||
const unsigned char* image, unsigned w, unsigned h);
|
||||
+
|
||||
+}
|
||||
+
|
||||
#endif /*LODEPNG_COMPILE_DISK*/
|
||||
#endif /*LODEPNG_COMPILE_ENCODER*/
|
||||
|
||||
@@ -219,6 +229,8 @@
|
||||
unsigned decode(std::vector<unsigned char>& out, unsigned& w, unsigned& h,
|
||||
const std::vector<unsigned char>& in,
|
||||
LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8);
|
||||
+
|
||||
+
|
||||
#ifdef LODEPNG_COMPILE_DISK
|
||||
/*
|
||||
Converts PNG file from disk to raw pixel data in memory.
|
||||
@@ -251,6 +263,7 @@
|
||||
unsigned encode(const std::string& filename,
|
||||
const std::vector<unsigned char>& in, unsigned w, unsigned h,
|
||||
LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8);
|
||||
+
|
||||
#endif /* LODEPNG_COMPILE_DISK */
|
||||
#endif /* LODEPNG_COMPILE_ENCODER */
|
||||
} /* namespace lodepng */
|
||||
@@ -318,6 +331,7 @@
|
||||
|
||||
extern const LodePNGCompressSettings lodepng_default_compress_settings;
|
||||
void lodepng_compress_settings_init(LodePNGCompressSettings* settings);
|
||||
+
|
||||
#endif /*LODEPNG_COMPILE_ENCODER*/
|
||||
|
||||
#ifdef LODEPNG_COMPILE_PNG
|
||||
@@ -943,6 +957,8 @@
|
||||
#endif /*LODEPNG_COMPILE_ZLIB*/
|
||||
|
||||
#ifdef LODEPNG_COMPILE_DISK
|
||||
+
|
||||
+extern "C" {
|
||||
/*
|
||||
Load a file from disk into buffer. The function allocates the out buffer, and
|
||||
after usage you should free it.
|
||||
@@ -962,6 +978,7 @@
|
||||
return value: error code (0 means ok)
|
||||
*/
|
||||
unsigned lodepng_save_file(const unsigned char* buffer, size_t buffersize, const char* filename);
|
||||
+}
|
||||
#endif /*LODEPNG_COMPILE_DISK*/
|
||||
|
||||
#ifdef LODEPNG_COMPILE_CPP
|
|
@ -1 +0,0 @@
|
|||
Subproject commit 65c8f577d2f057e80040e98958eae80ca76c6b94
|
|
@ -1 +0,0 @@
|
|||
Subproject commit 74d7261be17cf659d5930d4830609406bd7553e3
|
|
@ -201,7 +201,7 @@ absl::Status Sandbox::Init() {
|
|||
ModifyExecutor(executor.get());
|
||||
|
||||
s2_ = absl::make_unique<sandbox2::Sandbox2>(std::move(executor),
|
||||
std::move(s2p));
|
||||
std::move(s2p), CreateNotifier());
|
||||
auto res = s2_->RunAsync();
|
||||
|
||||
comms_ = s2_->comms();
|
||||
|
|
|
@ -141,6 +141,9 @@ class Sandbox {
|
|||
// Modifies the Executor object if needed.
|
||||
virtual void ModifyExecutor(sandbox2::Executor* executor) {}
|
||||
|
||||
// Provides a custom notifier for sandboxee events. May return nullptr.
|
||||
virtual std::unique_ptr<sandbox2::Notify> CreateNotifier() { return nullptr; }
|
||||
|
||||
// Exits the sandboxee.
|
||||
void Exit() const;
|
||||
|
||||
|
|
|
@ -54,7 +54,7 @@ absl::StatusOr<std::unique_ptr<Buffer>> Buffer::CreateFromFd(int fd) {
|
|||
|
||||
// Creates a new Buffer of the specified size, backed by a temporary file that
|
||||
// will be immediately deleted.
|
||||
absl::StatusOr<std::unique_ptr<Buffer>> Buffer::CreateWithSize(int64_t size) {
|
||||
absl::StatusOr<std::unique_ptr<Buffer>> Buffer::CreateWithSize(size_t size) {
|
||||
int fd;
|
||||
if (!util::CreateMemFd(&fd)) {
|
||||
return absl::InternalError("Could not create buffer temp file");
|
||||
|
|
|
@ -41,7 +41,7 @@ class Buffer final {
|
|||
|
||||
// Creates a new Buffer of the specified size, backed by a temporary file that
|
||||
// will be immediately deleted.
|
||||
static absl::StatusOr<std::unique_ptr<Buffer>> CreateWithSize(int64_t size);
|
||||
static absl::StatusOr<std::unique_ptr<Buffer>> CreateWithSize(size_t size);
|
||||
|
||||
// Returns a pointer to the buffer, which is read/write.
|
||||
uint8_t* data() const { return buf_; }
|
||||
|
|
|
@ -20,8 +20,6 @@
|
|||
|
||||
namespace sandbox2 {
|
||||
|
||||
const char kForkServerDisableEnv[] = "SANDBOX2_NOFORKSERVER";
|
||||
|
||||
pid_t ForkClient::SendRequest(const ForkRequest& request, int exec_fd,
|
||||
int comms_fd, int user_ns_fd, pid_t* init_pid) {
|
||||
// Acquire the channel ownership for this request (transaction).
|
||||
|
|
|
@ -17,34 +17,35 @@
|
|||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "absl/base/attributes.h"
|
||||
#include "absl/base/thread_annotations.h"
|
||||
#include "absl/synchronization/mutex.h"
|
||||
|
||||
namespace sandbox2 {
|
||||
|
||||
// Envvar indicating that this process should not start the fork-server.
|
||||
ABSL_CONST_INIT extern const char kForkServerDisableEnv[];
|
||||
constexpr inline char kForkServerDisableEnv[] = "SANDBOX2_NOFORKSERVER";
|
||||
|
||||
class Comms;
|
||||
class ForkRequest;
|
||||
|
||||
class ForkClient {
|
||||
public:
|
||||
explicit ForkClient(Comms* comms) : comms_(comms) {}
|
||||
|
||||
ForkClient(const ForkClient&) = delete;
|
||||
ForkClient& operator=(const ForkClient&) = delete;
|
||||
|
||||
explicit ForkClient(Comms* comms) : comms_(comms) {}
|
||||
|
||||
// Sends the fork request over the supplied Comms channel.
|
||||
pid_t SendRequest(const ForkRequest& request, int exec_fd, int comms_fd,
|
||||
int user_ns_fd = -1, pid_t* init_pid = nullptr);
|
||||
|
||||
private:
|
||||
// Comms channel connecting with the ForkServer. Not owned by the object.
|
||||
Comms* comms_;
|
||||
Comms* comms_ ABSL_GUARDED_BY(comms_mutex_);
|
||||
// Mutex locking transactions (requests) over the Comms channel.
|
||||
absl::Mutex comms_mutex_;
|
||||
};
|
||||
|
||||
} // namespace sandbox2
|
||||
|
||||
#endif // SANDBOXED_API_SANDBOX2_FORK_CLIENT_H_
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include <memory>
|
||||
|
||||
#include "absl/base/attributes.h"
|
||||
#include "absl/status/statusor.h"
|
||||
#include "absl/strings/escaping.h"
|
||||
#include "absl/strings/numbers.h"
|
||||
#include "absl/strings/str_cat.h"
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
|
||||
#include "absl/base/internal/endian.h"
|
||||
#include "absl/status/status.h"
|
||||
#include "absl/status/statusor.h"
|
||||
#include "absl/strings/match.h"
|
||||
#include "absl/strings/str_cat.h"
|
||||
#include "sandboxed_api/sandbox2/util.h"
|
||||
|
|
|
@ -59,9 +59,9 @@ bool GeneratorASTVisitor::VisitFunctionDecl(clang::FunctionDecl* decl) {
|
|||
options_.function_names.count(ToStringView(decl->getName())) > 0)) {
|
||||
functions_.push_back(decl);
|
||||
|
||||
CollectRelatedTypes(decl->getDeclaredReturnType(), &types_);
|
||||
collector_.CollectRelatedTypes(decl->getDeclaredReturnType());
|
||||
for (const clang::ParmVarDecl* param : decl->parameters()) {
|
||||
CollectRelatedTypes(param->getType(), &types_);
|
||||
collector_.CollectRelatedTypes(param->getType());
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
@ -75,7 +75,7 @@ void GeneratorASTConsumer::HandleTranslationUnit(clang::ASTContext& context) {
|
|||
"AST traversal exited early");
|
||||
}
|
||||
|
||||
for (clang::QualType qual : visitor_.types_) {
|
||||
for (clang::QualType qual : visitor_.collector_.collected()) {
|
||||
emitter_.CollectType(qual);
|
||||
}
|
||||
for (clang::FunctionDecl* func : visitor_.functions_) {
|
||||
|
|
|
@ -65,8 +65,9 @@ class GeneratorASTVisitor
|
|||
private:
|
||||
friend class GeneratorASTConsumer;
|
||||
|
||||
TypeCollector collector_;
|
||||
|
||||
std::vector<clang::FunctionDecl*> functions_;
|
||||
QualTypeSet types_;
|
||||
|
||||
const GeneratorOptions& options_;
|
||||
};
|
||||
|
|
|
@ -30,10 +30,15 @@ bool IsFunctionReferenceType(clang::QualType qual) {
|
|||
|
||||
} // namespace
|
||||
|
||||
void CollectRelatedTypes(clang::QualType qual, QualTypeSet* types) {
|
||||
void TypeCollector::CollectRelatedTypes(clang::QualType qual) {
|
||||
if (seen_.contains(qual)) {
|
||||
return;
|
||||
}
|
||||
seen_.insert(qual);
|
||||
|
||||
if (const auto* typedef_type = qual->getAs<clang::TypedefType>()) {
|
||||
CollectRelatedTypes(typedef_type->getDecl()->getUnderlyingType(), types);
|
||||
types->insert(qual);
|
||||
CollectRelatedTypes(typedef_type->getDecl()->getUnderlyingType());
|
||||
collected_.insert(qual);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -43,26 +48,26 @@ void CollectRelatedTypes(clang::QualType qual, QualTypeSet* types) {
|
|||
->getAs<clang::FunctionProtoType>()) {
|
||||
// Note: Do not add the function type itself, as this will always be a
|
||||
// pointer argument. We only need to collect all its related types.
|
||||
CollectRelatedTypes(function_type->getReturnType(), types);
|
||||
CollectRelatedTypes(function_type->getReturnType());
|
||||
for (const clang::QualType& param : function_type->getParamTypes()) {
|
||||
CollectRelatedTypes(param, types);
|
||||
CollectRelatedTypes(param);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (IsPointerOrReference(qual)) {
|
||||
clang::QualType pointee = qual->getPointeeType();
|
||||
while (IsPointerOrReference(pointee)) {
|
||||
clang::QualType pointee = qual;
|
||||
do {
|
||||
pointee = pointee->getPointeeType();
|
||||
}
|
||||
CollectRelatedTypes(pointee, types);
|
||||
} while (IsPointerOrReference(pointee));
|
||||
CollectRelatedTypes(pointee);
|
||||
return;
|
||||
}
|
||||
|
||||
// C array with specified constant size (i.e. int a[42])?
|
||||
if (const clang::ArrayType* array_type = qual->getAsArrayTypeUnsafe()) {
|
||||
CollectRelatedTypes(array_type->getElementType(), types);
|
||||
CollectRelatedTypes(array_type->getElementType());
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -71,19 +76,19 @@ void CollectRelatedTypes(clang::QualType qual, QualTypeSet* types) {
|
|||
// Collect the underlying integer type of enum classes as well, as it may
|
||||
// be a typedef.
|
||||
if (const clang::EnumDecl* decl = enum_type->getDecl(); decl->isFixed()) {
|
||||
CollectRelatedTypes(decl->getIntegerType(), types);
|
||||
CollectRelatedTypes(decl->getIntegerType());
|
||||
}
|
||||
}
|
||||
types->insert(qual);
|
||||
collected_.insert(qual);
|
||||
return;
|
||||
}
|
||||
|
||||
if (const auto* record_type = qual->getAs<clang::RecordType>()) {
|
||||
const clang::RecordDecl* decl = record_type->getDecl();
|
||||
for (const clang::FieldDecl* field : decl->fields()) {
|
||||
CollectRelatedTypes(field->getType(), types);
|
||||
CollectRelatedTypes(field->getType());
|
||||
}
|
||||
types->insert(qual);
|
||||
collected_.insert(qual);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,20 +41,29 @@ inline bool IsPointerOrReference(clang::QualType qual) {
|
|||
qual->isLValueReferenceType() || qual->isRValueReferenceType();
|
||||
}
|
||||
|
||||
// Computes the transitive closure of all types that a type depends on. Those
|
||||
// are types that need to be declared before a declaration of the type denoted
|
||||
// by the qual parameter is valid. For example, given
|
||||
// struct SubStruct { bool truth_value; };
|
||||
// struct AggregateStruct {
|
||||
// int int_member;
|
||||
// SubStruct struct_member;
|
||||
// };
|
||||
//
|
||||
// calling this function on the type "AggregateStruct" yields these types:
|
||||
// int
|
||||
// SubStruct
|
||||
// bool
|
||||
void CollectRelatedTypes(clang::QualType qual, QualTypeSet* types);
|
||||
class TypeCollector {
|
||||
public:
|
||||
// Computes the transitive closure of all types that a type depends on. Those
|
||||
// are types that need to be declared before a declaration of the type denoted
|
||||
// by the qual parameter is valid. For example, given
|
||||
// struct SubStruct { bool truth_value; };
|
||||
// struct AggregateStruct {
|
||||
// int int_member;
|
||||
// SubStruct struct_member;
|
||||
// };
|
||||
//
|
||||
// calling this function on the type "AggregateStruct" yields these types:
|
||||
// int
|
||||
// SubStruct
|
||||
// bool
|
||||
void CollectRelatedTypes(clang::QualType qual);
|
||||
|
||||
QualTypeSet& collected() { return collected_; }
|
||||
|
||||
private:
|
||||
QualTypeSet collected_;
|
||||
QualTypeSet seen_;
|
||||
};
|
||||
|
||||
// Maps a qualified type to a fully qualified SAPI-compatible type name. This
|
||||
// is used for the generated code that invokes the actual function call RPC.
|
||||
|
|
|
@ -492,7 +492,6 @@ class Function(object):
|
|||
self._tu = tu
|
||||
self.cursor = cursor # type: cindex.Index
|
||||
self.name = cursor.spelling # type: Text
|
||||
self.mangled_name = cursor.mangled_name # type: Text
|
||||
self.result = ReturnType(self, cursor.result_type)
|
||||
self.original_definition = '{} {}'.format(
|
||||
cursor.result_type.spelling, self.cursor.displayname) # type: Text
|
||||
|
@ -542,7 +541,7 @@ class Function(object):
|
|||
|
||||
def is_mangled(self):
|
||||
# type: () -> bool
|
||||
return self.name != self.mangled_name
|
||||
return self.cursor.mangled_name != self.cursor.spelling
|
||||
|
||||
def __hash__(self):
|
||||
# type: () -> int
|
||||
|
@ -550,7 +549,7 @@ class Function(object):
|
|||
|
||||
def __eq__(self, other):
|
||||
# type: (Function) -> bool
|
||||
return self.mangled_name == other.mangled_name
|
||||
return self.cursor.mangled_name == other.cursor.mangled_name
|
||||
|
||||
|
||||
class _TranslationUnit(object):
|
||||
|
|
|
@ -832,7 +832,7 @@ class CodeAnalysisTest(parameterized.TestCase):
|
|||
functions = tu.get_functions()
|
||||
self.assertLen(functions, 2)
|
||||
|
||||
mangled_names = [f.mangled_name for f in functions]
|
||||
mangled_names = [f.cursor.mangled_name for f in functions]
|
||||
self.assertSameElements(mangled_names, ['sum', '_Z3sumif'])
|
||||
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "absl/base/macros.h"
|
||||
#include "absl/status/status.h"
|
||||
#include "absl/strings/str_cat.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "sandboxed_api/rpcchannel.h"
|
||||
#include "sandboxed_api/var_abstract.h"
|
||||
#include "sandboxed_api/var_pointable.h"
|
||||
|
@ -143,8 +144,9 @@ class Array : public Var, public Pointable {
|
|||
// buffer is owned by the class, and is mutable.
|
||||
class CStr : public Array<char> {
|
||||
public:
|
||||
explicit CStr(char* cstr) : Array<char>(strlen(cstr) + 1) {
|
||||
std::copy(cstr, cstr + GetNElem(), GetData());
|
||||
explicit CStr(absl::string_view cstr) : Array<char>(cstr.size() + 1) {
|
||||
std::copy(cstr.begin(), cstr.end(), GetData());
|
||||
GetData()[cstr.size()] = '\0';
|
||||
}
|
||||
|
||||
std::string ToString() const final {
|
||||
|
|
Loading…
Reference in New Issue
Block a user