mirror of
https://github.com/google/sandboxed-api.git
synced 2024-03-22 13:11:30 +08:00
241 lines
8.3 KiB
C++
241 lines
8.3 KiB
C++
|
// Copyright 2022 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
|
||
|
//
|
||
|
// https://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 <iostream>
|
||
|
#include <string>
|
||
|
|
||
|
#include "../sandboxed.h"
|
||
|
|
||
|
static const size_t kFileMaxSize = 1024 * 1024 * 1024; // 1GB
|
||
|
|
||
|
std::streamsize GetStreamSize(std::ifstream& stream) {
|
||
|
stream.seekg(0, std::ios_base::end);
|
||
|
std::streamsize ssize = stream.tellg();
|
||
|
stream.seekg(0, std::ios_base::beg);
|
||
|
|
||
|
return ssize;
|
||
|
}
|
||
|
|
||
|
absl::Status CompressInMemory(ZstdApi& api, std::ifstream& instream,
|
||
|
std::ofstream& outstream, int level) {
|
||
|
std::streamsize ssize = GetStreamSize(instream);
|
||
|
sapi::v::Array<uint8_t> inbuf(ssize);
|
||
|
instream.read(reinterpret_cast<char*>(inbuf.GetData()), ssize);
|
||
|
if (instream.gcount() != ssize) {
|
||
|
return absl::UnavailableError("Unable to read file");
|
||
|
}
|
||
|
|
||
|
SAPI_ASSIGN_OR_RETURN(size_t size, api.ZSTD_compressBound(inbuf.GetSize()));
|
||
|
sapi::v::Array<uint8_t> outbuf(size);
|
||
|
|
||
|
SAPI_ASSIGN_OR_RETURN(
|
||
|
size_t outsize,
|
||
|
api.ZSTD_compress(outbuf.PtrAfter(), size, inbuf.PtrBefore(),
|
||
|
inbuf.GetSize(), level));
|
||
|
SAPI_ASSIGN_OR_RETURN(int iserr, api.ZSTD_isError(outsize))
|
||
|
if (iserr) {
|
||
|
return absl::UnavailableError("Unable to compress file");
|
||
|
}
|
||
|
|
||
|
outstream.write(reinterpret_cast<char*>(outbuf.GetData()), outsize);
|
||
|
if (!outstream.good()) {
|
||
|
return absl::UnavailableError("Unable to write file");
|
||
|
}
|
||
|
|
||
|
return absl::OkStatus();
|
||
|
}
|
||
|
|
||
|
absl::Status DecompressInMemory(ZstdApi& api, std::ifstream& instream,
|
||
|
std::ofstream& outstream) {
|
||
|
int iserr;
|
||
|
std::streamsize ssize = GetStreamSize(instream);
|
||
|
sapi::v::Array<uint8_t> inbuf(ssize);
|
||
|
instream.read(reinterpret_cast<char*>(inbuf.GetData()), ssize);
|
||
|
if (instream.gcount() != ssize) {
|
||
|
return absl::UnavailableError("Unable to read file");
|
||
|
}
|
||
|
|
||
|
SAPI_ASSIGN_OR_RETURN(size_t size, api.ZSTD_getFrameContentSize(
|
||
|
inbuf.PtrBefore(), inbuf.GetSize()));
|
||
|
if (size > kFileMaxSize) {
|
||
|
return absl::UnavailableError("File to large");
|
||
|
}
|
||
|
SAPI_ASSIGN_OR_RETURN(iserr, api.ZSTD_isError(size));
|
||
|
if (iserr) {
|
||
|
return absl::UnavailableError("Unable to decompress file");
|
||
|
}
|
||
|
sapi::v::Array<uint8_t> outbuf(size);
|
||
|
|
||
|
SAPI_ASSIGN_OR_RETURN(
|
||
|
size_t desize, api.ZSTD_decompress(outbuf.PtrAfter(), size,
|
||
|
inbuf.PtrBefore(), inbuf.GetSize()));
|
||
|
SAPI_ASSIGN_OR_RETURN(iserr, api.ZSTD_isError(desize));
|
||
|
if (iserr) {
|
||
|
return absl::UnavailableError("Unable to decompress file");
|
||
|
}
|
||
|
|
||
|
outstream.write(reinterpret_cast<char*>(outbuf.GetData()), desize);
|
||
|
if (!outstream.good()) {
|
||
|
return absl::UnavailableError("Unable to write file");
|
||
|
}
|
||
|
|
||
|
return absl::OkStatus();
|
||
|
}
|
||
|
|
||
|
absl::Status CompressStream(ZstdApi& api, std::ifstream& instream,
|
||
|
std::ofstream& outstream, int level) {
|
||
|
int iserr;
|
||
|
|
||
|
// Create necessary buffers.
|
||
|
SAPI_ASSIGN_OR_RETURN(size_t inbuf_size, api.ZSTD_CStreamInSize());
|
||
|
SAPI_ASSIGN_OR_RETURN(size_t outbuf_size, api.ZSTD_CStreamOutSize());
|
||
|
sapi::v::Array<uint8_t> inbuf(inbuf_size);
|
||
|
sapi::v::Array<uint8_t> outbuf(outbuf_size);
|
||
|
|
||
|
if (!api.GetSandbox()->Allocate(&inbuf).ok() ||
|
||
|
!api.GetSandbox()->Allocate(&outbuf).ok()) {
|
||
|
return absl::UnavailableError("Unable to allocate buffors");
|
||
|
}
|
||
|
|
||
|
// Create Zstd context.
|
||
|
SAPI_ASSIGN_OR_RETURN(ZSTD_DCtx * dctx, api.ZSTD_createDCtx());
|
||
|
sapi::v::RemotePtr rdctx(dctx);
|
||
|
|
||
|
SAPI_ASSIGN_OR_RETURN(iserr, api.ZSTD_CCtx_setParameter(
|
||
|
&rdctx, ZSTD_c_compressionLevel, level));
|
||
|
if (!iserr) {
|
||
|
return absl::UnavailableError("Unable to set parameter");
|
||
|
}
|
||
|
SAPI_ASSIGN_OR_RETURN(
|
||
|
iserr, api.ZSTD_CCtx_setParameter(&rdctx, ZSTD_c_checksumFlag, 1));
|
||
|
if (!iserr) {
|
||
|
return absl::UnavailableError("Unable to set parameter");
|
||
|
}
|
||
|
|
||
|
// Compress.
|
||
|
while (instream) {
|
||
|
instream.read(reinterpret_cast<char*>(inbuf.GetData()), inbuf_size);
|
||
|
|
||
|
if (!api.GetSandbox()->TransferToSandboxee(&inbuf).ok()) {
|
||
|
return absl::UnavailableError("Unable to transfer data");
|
||
|
}
|
||
|
|
||
|
sapi::v::Struct<ZSTD_inBuffer_s> struct_in;
|
||
|
struct_in.mutable_data()->src = static_cast<uint8_t*>(inbuf.GetRemote());
|
||
|
struct_in.mutable_data()->pos = 0;
|
||
|
struct_in.mutable_data()->size = instream.gcount();
|
||
|
|
||
|
ZSTD_EndDirective mode = ZSTD_e_continue;
|
||
|
if (instream.gcount() < inbuf_size) {
|
||
|
mode = ZSTD_e_end;
|
||
|
}
|
||
|
|
||
|
bool isdone = false;
|
||
|
while (!isdone) {
|
||
|
sapi::v::Struct<ZSTD_outBuffer_s> struct_out;
|
||
|
struct_out.mutable_data()->dst = static_cast<uint8_t*>(outbuf.GetRemote());
|
||
|
struct_out.mutable_data()->pos = 0;
|
||
|
struct_out.mutable_data()->size = outbuf.GetSize();
|
||
|
|
||
|
SAPI_ASSIGN_OR_RETURN(size_t remaining, api.ZSTD_compressStream2(
|
||
|
&rdctx, struct_out.PtrBoth(),
|
||
|
struct_in.PtrBoth(), mode));
|
||
|
SAPI_ASSIGN_OR_RETURN(int iserr, api.ZSTD_isError(remaining))
|
||
|
if (iserr) {
|
||
|
return absl::UnavailableError("Unable to decompress file");
|
||
|
}
|
||
|
|
||
|
if (!api.GetSandbox()->TransferFromSandboxee(&outbuf).ok()) {
|
||
|
return absl::UnavailableError("Unable to transfer data from");
|
||
|
}
|
||
|
outstream.write(reinterpret_cast<char*>(outbuf.GetData()),
|
||
|
struct_out.mutable_data()->pos);
|
||
|
if (!outstream.good()) {
|
||
|
return absl::UnavailableError("Unable to write file");
|
||
|
}
|
||
|
|
||
|
if (mode == ZSTD_e_continue) {
|
||
|
isdone = (struct_in.mutable_data()->pos == instream.gcount());
|
||
|
} else {
|
||
|
isdone = (remaining == 0);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
api.ZSTD_freeDCtx(&rdctx).IgnoreError();
|
||
|
|
||
|
return absl::OkStatus();
|
||
|
}
|
||
|
|
||
|
absl::Status DecompressStream(ZstdApi& api, std::ifstream& instream,
|
||
|
std::ofstream& outstream) {
|
||
|
// Create necessary buffers.
|
||
|
SAPI_ASSIGN_OR_RETURN(size_t inbuf_size, api.ZSTD_CStreamInSize());
|
||
|
SAPI_ASSIGN_OR_RETURN(size_t outbuf_size, api.ZSTD_CStreamOutSize());
|
||
|
sapi::v::Array<uint8_t> inbuf(inbuf_size);
|
||
|
sapi::v::Array<uint8_t> outbuf(outbuf_size);
|
||
|
|
||
|
if (!api.GetSandbox()->Allocate(&inbuf).ok() ||
|
||
|
!api.GetSandbox()->Allocate(&outbuf).ok()) {
|
||
|
return absl::UnavailableError("Unable to allocate buffors");
|
||
|
}
|
||
|
|
||
|
// Create Zstd context.
|
||
|
SAPI_ASSIGN_OR_RETURN(ZSTD_DCtx * dctx, api.ZSTD_createDCtx());
|
||
|
sapi::v::RemotePtr rdctx(dctx);
|
||
|
|
||
|
// Decompress.
|
||
|
while (instream) {
|
||
|
instream.read(reinterpret_cast<char*>(inbuf.GetData()), inbuf_size);
|
||
|
|
||
|
if (!api.GetSandbox()->TransferToSandboxee(&inbuf).ok()) {
|
||
|
return absl::UnavailableError("Unable to transfer data");
|
||
|
}
|
||
|
|
||
|
sapi::v::Struct<ZSTD_inBuffer_s> struct_in;
|
||
|
*struct_in.mutable_data() = {static_cast<uint8_t*>(inbuf.GetRemote()),
|
||
|
(size_t)instream.gcount(), 0};
|
||
|
|
||
|
bool isdone = false;
|
||
|
while (struct_in.mutable_data()->pos < instream.gcount()) {
|
||
|
sapi::v::Struct<ZSTD_outBuffer_s> struct_out;
|
||
|
*struct_out.mutable_data() = {static_cast<uint8_t*>(outbuf.GetRemote()),
|
||
|
(size_t)outbuf.GetSize(), 0};
|
||
|
|
||
|
SAPI_ASSIGN_OR_RETURN(
|
||
|
size_t ret, api.ZSTD_decompressStream(&rdctx, struct_out.PtrBoth(),
|
||
|
struct_in.PtrBoth()));
|
||
|
SAPI_ASSIGN_OR_RETURN(int iserr, api.ZSTD_isError(ret))
|
||
|
if (iserr) {
|
||
|
return absl::UnavailableError("Unable to decompress file");
|
||
|
}
|
||
|
|
||
|
if (!api.GetSandbox()->TransferFromSandboxee(&outbuf).ok()) {
|
||
|
return absl::UnavailableError("Unable to transfer data from");
|
||
|
}
|
||
|
|
||
|
outstream.write(reinterpret_cast<char*>(outbuf.GetData()),
|
||
|
struct_out.mutable_data()->pos);
|
||
|
if (!outstream.good()) {
|
||
|
return absl::UnavailableError("Unable to write file");
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
api.ZSTD_freeDCtx(&rdctx).IgnoreError();
|
||
|
|
||
|
return absl::OkStatus();
|
||
|
}
|