1*ec63e07aSXin Li // Copyright 2022 Google LLC
2*ec63e07aSXin Li //
3*ec63e07aSXin Li // Licensed under the Apache License, Version 2.0 (the "License");
4*ec63e07aSXin Li // you may not use this file except in compliance with the License.
5*ec63e07aSXin Li // You may obtain a copy of the License at
6*ec63e07aSXin Li //
7*ec63e07aSXin Li // https://www.apache.org/licenses/LICENSE-2.0
8*ec63e07aSXin Li //
9*ec63e07aSXin Li // Unless required by applicable law or agreed to in writing, software
10*ec63e07aSXin Li // distributed under the License is distributed on an "AS IS" BASIS,
11*ec63e07aSXin Li // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*ec63e07aSXin Li // See the License for the specific language governing permissions and
13*ec63e07aSXin Li // limitations under the License.
14*ec63e07aSXin Li
15*ec63e07aSXin Li #include <fstream>
16*ec63e07aSXin Li #include <iostream>
17*ec63e07aSXin Li #include <string>
18*ec63e07aSXin Li
19*ec63e07aSXin Li #include "contrib/zstd/sandboxed.h"
20*ec63e07aSXin Li
21*ec63e07aSXin Li constexpr size_t kFileMaxSize = 1024 * 1024 * 1024; // 1GB
22*ec63e07aSXin Li
GetStreamSize(std::ifstream & stream)23*ec63e07aSXin Li std::streamsize GetStreamSize(std::ifstream& stream) {
24*ec63e07aSXin Li stream.seekg(0, std::ios_base::end);
25*ec63e07aSXin Li std::streamsize ssize = stream.tellg();
26*ec63e07aSXin Li stream.seekg(0, std::ios_base::beg);
27*ec63e07aSXin Li
28*ec63e07aSXin Li return ssize;
29*ec63e07aSXin Li }
30*ec63e07aSXin Li
CompressInMemory(ZstdApi & api,std::ifstream & in_stream,std::ofstream & out_stream,int level)31*ec63e07aSXin Li absl::Status CompressInMemory(ZstdApi& api, std::ifstream& in_stream,
32*ec63e07aSXin Li std::ofstream& out_stream, int level) {
33*ec63e07aSXin Li std::streamsize ssize = GetStreamSize(in_stream);
34*ec63e07aSXin Li sapi::v::Array<uint8_t> inbuf(ssize);
35*ec63e07aSXin Li in_stream.read(reinterpret_cast<char*>(inbuf.GetData()), ssize);
36*ec63e07aSXin Li if (in_stream.gcount() != ssize) {
37*ec63e07aSXin Li return absl::UnavailableError("Unable to read file");
38*ec63e07aSXin Li }
39*ec63e07aSXin Li
40*ec63e07aSXin Li SAPI_ASSIGN_OR_RETURN(size_t size, api.ZSTD_compressBound(inbuf.GetSize()));
41*ec63e07aSXin Li sapi::v::Array<uint8_t> outbuf(size);
42*ec63e07aSXin Li
43*ec63e07aSXin Li SAPI_ASSIGN_OR_RETURN(
44*ec63e07aSXin Li size_t outsize,
45*ec63e07aSXin Li api.ZSTD_compress(outbuf.PtrAfter(), size, inbuf.PtrBefore(),
46*ec63e07aSXin Li inbuf.GetSize(), level));
47*ec63e07aSXin Li SAPI_ASSIGN_OR_RETURN(int iserr, api.ZSTD_isError(outsize));
48*ec63e07aSXin Li if (iserr) {
49*ec63e07aSXin Li return absl::UnavailableError("Unable to compress file");
50*ec63e07aSXin Li }
51*ec63e07aSXin Li
52*ec63e07aSXin Li out_stream.write(reinterpret_cast<char*>(outbuf.GetData()), outsize);
53*ec63e07aSXin Li if (!out_stream.good()) {
54*ec63e07aSXin Li return absl::UnavailableError("Unable to write file");
55*ec63e07aSXin Li }
56*ec63e07aSXin Li
57*ec63e07aSXin Li return absl::OkStatus();
58*ec63e07aSXin Li }
59*ec63e07aSXin Li
DecompressInMemory(ZstdApi & api,std::ifstream & in_stream,std::ofstream & out_stream)60*ec63e07aSXin Li absl::Status DecompressInMemory(ZstdApi& api, std::ifstream& in_stream,
61*ec63e07aSXin Li std::ofstream& out_stream) {
62*ec63e07aSXin Li int iserr;
63*ec63e07aSXin Li std::streamsize ssize = GetStreamSize(in_stream);
64*ec63e07aSXin Li sapi::v::Array<uint8_t> inbuf(ssize);
65*ec63e07aSXin Li in_stream.read(reinterpret_cast<char*>(inbuf.GetData()), ssize);
66*ec63e07aSXin Li if (in_stream.gcount() != ssize) {
67*ec63e07aSXin Li return absl::UnavailableError("Unable to read file");
68*ec63e07aSXin Li }
69*ec63e07aSXin Li
70*ec63e07aSXin Li SAPI_ASSIGN_OR_RETURN(size_t size, api.ZSTD_getFrameContentSize(
71*ec63e07aSXin Li inbuf.PtrBefore(), inbuf.GetSize()));
72*ec63e07aSXin Li if (size > kFileMaxSize) {
73*ec63e07aSXin Li return absl::UnavailableError("File to large");
74*ec63e07aSXin Li }
75*ec63e07aSXin Li SAPI_ASSIGN_OR_RETURN(iserr, api.ZSTD_isError(size));
76*ec63e07aSXin Li if (iserr) {
77*ec63e07aSXin Li return absl::UnavailableError("Unable to decompress file");
78*ec63e07aSXin Li }
79*ec63e07aSXin Li sapi::v::Array<uint8_t> outbuf(size);
80*ec63e07aSXin Li
81*ec63e07aSXin Li SAPI_ASSIGN_OR_RETURN(size_t desize,
82*ec63e07aSXin Li api.ZSTD_decompress(outbuf.PtrAfter(), size,
83*ec63e07aSXin Li inbuf.PtrNone(), inbuf.GetSize()));
84*ec63e07aSXin Li SAPI_ASSIGN_OR_RETURN(iserr, api.ZSTD_isError(desize));
85*ec63e07aSXin Li if (iserr) {
86*ec63e07aSXin Li return absl::UnavailableError("Unable to decompress file");
87*ec63e07aSXin Li }
88*ec63e07aSXin Li
89*ec63e07aSXin Li out_stream.write(reinterpret_cast<char*>(outbuf.GetData()), desize);
90*ec63e07aSXin Li if (!out_stream.good()) {
91*ec63e07aSXin Li return absl::UnavailableError("Unable to write file");
92*ec63e07aSXin Li }
93*ec63e07aSXin Li
94*ec63e07aSXin Li return absl::OkStatus();
95*ec63e07aSXin Li }
96*ec63e07aSXin Li
CompressStream(ZstdApi & api,std::ifstream & in_stream,std::ofstream & out_stream,int level)97*ec63e07aSXin Li absl::Status CompressStream(ZstdApi& api, std::ifstream& in_stream,
98*ec63e07aSXin Li std::ofstream& out_stream, int level) {
99*ec63e07aSXin Li int iserr;
100*ec63e07aSXin Li
101*ec63e07aSXin Li // Create necessary buffers.
102*ec63e07aSXin Li SAPI_ASSIGN_OR_RETURN(size_t inbuf_size, api.ZSTD_CStreamInSize());
103*ec63e07aSXin Li SAPI_ASSIGN_OR_RETURN(size_t outbuf_size, api.ZSTD_CStreamOutSize());
104*ec63e07aSXin Li sapi::v::Array<uint8_t> inbuf(inbuf_size);
105*ec63e07aSXin Li sapi::v::Array<uint8_t> outbuf(outbuf_size);
106*ec63e07aSXin Li
107*ec63e07aSXin Li if (!api.GetSandbox()->Allocate(&inbuf).ok() ||
108*ec63e07aSXin Li !api.GetSandbox()->Allocate(&outbuf).ok()) {
109*ec63e07aSXin Li return absl::UnavailableError("Unable to allocate buffors");
110*ec63e07aSXin Li }
111*ec63e07aSXin Li
112*ec63e07aSXin Li // Create Zstd context.
113*ec63e07aSXin Li SAPI_ASSIGN_OR_RETURN(ZSTD_CCtx * cctx, api.ZSTD_createCCtx());
114*ec63e07aSXin Li sapi::v::RemotePtr rcctx(cctx);
115*ec63e07aSXin Li
116*ec63e07aSXin Li SAPI_ASSIGN_OR_RETURN(iserr, api.ZSTD_CCtx_setParameter(
117*ec63e07aSXin Li &rcctx, ZSTD_c_compressionLevel, level));
118*ec63e07aSXin Li SAPI_ASSIGN_OR_RETURN(iserr, api.ZSTD_isError(iserr));
119*ec63e07aSXin Li if (iserr) {
120*ec63e07aSXin Li return absl::UnavailableError("Unable to set parameter");
121*ec63e07aSXin Li }
122*ec63e07aSXin Li SAPI_ASSIGN_OR_RETURN(
123*ec63e07aSXin Li iserr, api.ZSTD_CCtx_setParameter(&rcctx, ZSTD_c_checksumFlag, 1));
124*ec63e07aSXin Li SAPI_ASSIGN_OR_RETURN(iserr, api.ZSTD_isError(iserr));
125*ec63e07aSXin Li if (iserr) {
126*ec63e07aSXin Li return absl::UnavailableError("Unable to set parameter");
127*ec63e07aSXin Li }
128*ec63e07aSXin Li
129*ec63e07aSXin Li // Compress.
130*ec63e07aSXin Li while (in_stream) {
131*ec63e07aSXin Li in_stream.read(reinterpret_cast<char*>(inbuf.GetData()), inbuf_size);
132*ec63e07aSXin Li
133*ec63e07aSXin Li if (!api.GetSandbox()->TransferToSandboxee(&inbuf).ok()) {
134*ec63e07aSXin Li return absl::UnavailableError("Unable to transfer data");
135*ec63e07aSXin Li }
136*ec63e07aSXin Li
137*ec63e07aSXin Li sapi::v::Struct<ZSTD_inBuffer_s> struct_in;
138*ec63e07aSXin Li struct_in.mutable_data()->src = static_cast<uint8_t*>(inbuf.GetRemote());
139*ec63e07aSXin Li struct_in.mutable_data()->pos = 0;
140*ec63e07aSXin Li struct_in.mutable_data()->size = in_stream.gcount();
141*ec63e07aSXin Li
142*ec63e07aSXin Li ZSTD_EndDirective mode = ZSTD_e_continue;
143*ec63e07aSXin Li if (in_stream.gcount() < inbuf_size) {
144*ec63e07aSXin Li mode = ZSTD_e_end;
145*ec63e07aSXin Li }
146*ec63e07aSXin Li
147*ec63e07aSXin Li bool isdone = false;
148*ec63e07aSXin Li while (!isdone) {
149*ec63e07aSXin Li sapi::v::Struct<ZSTD_outBuffer_s> struct_out;
150*ec63e07aSXin Li struct_out.mutable_data()->dst =
151*ec63e07aSXin Li static_cast<uint8_t*>(outbuf.GetRemote());
152*ec63e07aSXin Li struct_out.mutable_data()->pos = 0;
153*ec63e07aSXin Li struct_out.mutable_data()->size = outbuf.GetSize();
154*ec63e07aSXin Li
155*ec63e07aSXin Li SAPI_ASSIGN_OR_RETURN(size_t remaining, api.ZSTD_compressStream2(
156*ec63e07aSXin Li &rcctx, struct_out.PtrBoth(),
157*ec63e07aSXin Li struct_in.PtrBoth(), mode));
158*ec63e07aSXin Li SAPI_ASSIGN_OR_RETURN(int iserr, api.ZSTD_isError(remaining));
159*ec63e07aSXin Li if (iserr) {
160*ec63e07aSXin Li return absl::UnavailableError("Unable to decompress file");
161*ec63e07aSXin Li }
162*ec63e07aSXin Li
163*ec63e07aSXin Li if (!api.GetSandbox()->TransferFromSandboxee(&outbuf).ok()) {
164*ec63e07aSXin Li return absl::UnavailableError("Unable to transfer data from");
165*ec63e07aSXin Li }
166*ec63e07aSXin Li out_stream.write(reinterpret_cast<char*>(outbuf.GetData()),
167*ec63e07aSXin Li struct_out.mutable_data()->pos);
168*ec63e07aSXin Li if (!out_stream.good()) {
169*ec63e07aSXin Li return absl::UnavailableError("Unable to write file");
170*ec63e07aSXin Li }
171*ec63e07aSXin Li
172*ec63e07aSXin Li if (mode == ZSTD_e_continue) {
173*ec63e07aSXin Li isdone = (struct_in.mutable_data()->pos == in_stream.gcount());
174*ec63e07aSXin Li } else {
175*ec63e07aSXin Li isdone = (remaining == 0);
176*ec63e07aSXin Li }
177*ec63e07aSXin Li }
178*ec63e07aSXin Li }
179*ec63e07aSXin Li
180*ec63e07aSXin Li api.ZSTD_freeDCtx(&rcctx).IgnoreError();
181*ec63e07aSXin Li
182*ec63e07aSXin Li return absl::OkStatus();
183*ec63e07aSXin Li }
184*ec63e07aSXin Li
DecompressStream(ZstdApi & api,std::ifstream & in_stream,std::ofstream & out_stream)185*ec63e07aSXin Li absl::Status DecompressStream(ZstdApi& api, std::ifstream& in_stream,
186*ec63e07aSXin Li std::ofstream& out_stream) {
187*ec63e07aSXin Li // Create necessary buffers.
188*ec63e07aSXin Li SAPI_ASSIGN_OR_RETURN(size_t inbuf_size, api.ZSTD_CStreamInSize());
189*ec63e07aSXin Li SAPI_ASSIGN_OR_RETURN(size_t outbuf_size, api.ZSTD_CStreamOutSize());
190*ec63e07aSXin Li sapi::v::Array<uint8_t> inbuf(inbuf_size);
191*ec63e07aSXin Li sapi::v::Array<uint8_t> outbuf(outbuf_size);
192*ec63e07aSXin Li
193*ec63e07aSXin Li if (!api.GetSandbox()->Allocate(&inbuf).ok() ||
194*ec63e07aSXin Li !api.GetSandbox()->Allocate(&outbuf).ok()) {
195*ec63e07aSXin Li return absl::UnavailableError("Unable to allocate buffors");
196*ec63e07aSXin Li }
197*ec63e07aSXin Li
198*ec63e07aSXin Li // Create Zstd context.
199*ec63e07aSXin Li SAPI_ASSIGN_OR_RETURN(ZSTD_DCtx * dctx, api.ZSTD_createDCtx());
200*ec63e07aSXin Li sapi::v::RemotePtr rdctx(dctx);
201*ec63e07aSXin Li
202*ec63e07aSXin Li // Decompress.
203*ec63e07aSXin Li while (in_stream) {
204*ec63e07aSXin Li in_stream.read(reinterpret_cast<char*>(inbuf.GetData()), inbuf_size);
205*ec63e07aSXin Li
206*ec63e07aSXin Li if (!api.GetSandbox()->TransferToSandboxee(&inbuf).ok()) {
207*ec63e07aSXin Li return absl::UnavailableError("Unable to transfer data");
208*ec63e07aSXin Li }
209*ec63e07aSXin Li
210*ec63e07aSXin Li sapi::v::Struct<ZSTD_inBuffer_s> struct_in;
211*ec63e07aSXin Li *struct_in.mutable_data() = {static_cast<uint8_t*>(inbuf.GetRemote()),
212*ec63e07aSXin Li (size_t)in_stream.gcount(), 0};
213*ec63e07aSXin Li
214*ec63e07aSXin Li bool isdone = false;
215*ec63e07aSXin Li while (struct_in.mutable_data()->pos < in_stream.gcount()) {
216*ec63e07aSXin Li sapi::v::Struct<ZSTD_outBuffer_s> struct_out;
217*ec63e07aSXin Li *struct_out.mutable_data() = {static_cast<uint8_t*>(outbuf.GetRemote()),
218*ec63e07aSXin Li (size_t)outbuf.GetSize(), 0};
219*ec63e07aSXin Li
220*ec63e07aSXin Li SAPI_ASSIGN_OR_RETURN(
221*ec63e07aSXin Li size_t ret, api.ZSTD_decompressStream(&rdctx, struct_out.PtrBoth(),
222*ec63e07aSXin Li struct_in.PtrBoth()));
223*ec63e07aSXin Li SAPI_ASSIGN_OR_RETURN(int iserr, api.ZSTD_isError(ret));
224*ec63e07aSXin Li if (iserr) {
225*ec63e07aSXin Li return absl::UnavailableError("Unable to decompress file");
226*ec63e07aSXin Li }
227*ec63e07aSXin Li
228*ec63e07aSXin Li if (!api.GetSandbox()->TransferFromSandboxee(&outbuf).ok()) {
229*ec63e07aSXin Li return absl::UnavailableError("Unable to transfer data from");
230*ec63e07aSXin Li }
231*ec63e07aSXin Li
232*ec63e07aSXin Li out_stream.write(reinterpret_cast<char*>(outbuf.GetData()),
233*ec63e07aSXin Li struct_out.mutable_data()->pos);
234*ec63e07aSXin Li if (!out_stream.good()) {
235*ec63e07aSXin Li return absl::UnavailableError("Unable to write file");
236*ec63e07aSXin Li }
237*ec63e07aSXin Li }
238*ec63e07aSXin Li }
239*ec63e07aSXin Li
240*ec63e07aSXin Li api.ZSTD_freeDCtx(&rdctx).IgnoreError();
241*ec63e07aSXin Li
242*ec63e07aSXin Li return absl::OkStatus();
243*ec63e07aSXin Li }
244*ec63e07aSXin Li
CompressInMemoryFD(ZstdApi & api,sapi::v::Fd & infd,sapi::v::Fd & outfd,int level)245*ec63e07aSXin Li absl::Status CompressInMemoryFD(ZstdApi& api, sapi::v::Fd& infd,
246*ec63e07aSXin Li sapi::v::Fd& outfd, int level) {
247*ec63e07aSXin Li SAPI_RETURN_IF_ERROR(api.GetSandbox()->TransferToSandboxee(&infd));
248*ec63e07aSXin Li SAPI_RETURN_IF_ERROR(api.GetSandbox()->TransferToSandboxee(&outfd));
249*ec63e07aSXin Li
250*ec63e07aSXin Li SAPI_ASSIGN_OR_RETURN(
251*ec63e07aSXin Li int iserr,
252*ec63e07aSXin Li api.ZSTD_compress_fd(infd.GetRemoteFd(), outfd.GetRemoteFd(), 0));
253*ec63e07aSXin Li SAPI_ASSIGN_OR_RETURN(iserr, api.ZSTD_isError(iserr));
254*ec63e07aSXin Li if (iserr) {
255*ec63e07aSXin Li return absl::UnavailableError("Unable to compress file");
256*ec63e07aSXin Li }
257*ec63e07aSXin Li
258*ec63e07aSXin Li infd.CloseRemoteFd(api.GetSandbox()->rpc_channel()).IgnoreError();
259*ec63e07aSXin Li outfd.CloseRemoteFd(api.GetSandbox()->rpc_channel()).IgnoreError();
260*ec63e07aSXin Li
261*ec63e07aSXin Li return absl::OkStatus();
262*ec63e07aSXin Li }
263*ec63e07aSXin Li
DecompressInMemoryFD(ZstdApi & api,sapi::v::Fd & infd,sapi::v::Fd & outfd)264*ec63e07aSXin Li absl::Status DecompressInMemoryFD(ZstdApi& api, sapi::v::Fd& infd,
265*ec63e07aSXin Li sapi::v::Fd& outfd) {
266*ec63e07aSXin Li SAPI_RETURN_IF_ERROR(api.GetSandbox()->TransferToSandboxee(&infd));
267*ec63e07aSXin Li SAPI_RETURN_IF_ERROR(api.GetSandbox()->TransferToSandboxee(&outfd));
268*ec63e07aSXin Li
269*ec63e07aSXin Li SAPI_ASSIGN_OR_RETURN(int iserr, api.ZSTD_decompress_fd(infd.GetRemoteFd(),
270*ec63e07aSXin Li outfd.GetRemoteFd()));
271*ec63e07aSXin Li SAPI_ASSIGN_OR_RETURN(iserr, api.ZSTD_isError(iserr));
272*ec63e07aSXin Li if (iserr) {
273*ec63e07aSXin Li return absl::UnavailableError("Unable to compress file");
274*ec63e07aSXin Li }
275*ec63e07aSXin Li
276*ec63e07aSXin Li infd.CloseRemoteFd(api.GetSandbox()->rpc_channel()).IgnoreError();
277*ec63e07aSXin Li outfd.CloseRemoteFd(api.GetSandbox()->rpc_channel()).IgnoreError();
278*ec63e07aSXin Li
279*ec63e07aSXin Li return absl::OkStatus();
280*ec63e07aSXin Li }
281*ec63e07aSXin Li
CompressStreamFD(ZstdApi & api,sapi::v::Fd & infd,sapi::v::Fd & outfd,int level)282*ec63e07aSXin Li absl::Status CompressStreamFD(ZstdApi& api, sapi::v::Fd& infd,
283*ec63e07aSXin Li sapi::v::Fd& outfd, int level) {
284*ec63e07aSXin Li SAPI_ASSIGN_OR_RETURN(ZSTD_CCtx * cctx, api.ZSTD_createCCtx());
285*ec63e07aSXin Li sapi::v::RemotePtr rcctx(cctx);
286*ec63e07aSXin Li
287*ec63e07aSXin Li int iserr;
288*ec63e07aSXin Li SAPI_ASSIGN_OR_RETURN(iserr, api.ZSTD_CCtx_setParameter(
289*ec63e07aSXin Li &rcctx, ZSTD_c_compressionLevel, level));
290*ec63e07aSXin Li SAPI_ASSIGN_OR_RETURN(iserr, api.ZSTD_isError(iserr));
291*ec63e07aSXin Li if (iserr) {
292*ec63e07aSXin Li return absl::UnavailableError("Unable to set parameter l");
293*ec63e07aSXin Li }
294*ec63e07aSXin Li SAPI_ASSIGN_OR_RETURN(
295*ec63e07aSXin Li iserr, api.ZSTD_CCtx_setParameter(&rcctx, ZSTD_c_checksumFlag, 1));
296*ec63e07aSXin Li SAPI_ASSIGN_OR_RETURN(iserr, api.ZSTD_isError(iserr));
297*ec63e07aSXin Li if (iserr) {
298*ec63e07aSXin Li return absl::UnavailableError("Unable to set parameter c");
299*ec63e07aSXin Li }
300*ec63e07aSXin Li
301*ec63e07aSXin Li SAPI_RETURN_IF_ERROR(api.GetSandbox()->TransferToSandboxee(&infd));
302*ec63e07aSXin Li SAPI_RETURN_IF_ERROR(api.GetSandbox()->TransferToSandboxee(&outfd));
303*ec63e07aSXin Li
304*ec63e07aSXin Li SAPI_ASSIGN_OR_RETURN(iserr,
305*ec63e07aSXin Li api.ZSTD_compressStream_fd(&rcctx, infd.GetRemoteFd(),
306*ec63e07aSXin Li outfd.GetRemoteFd()));
307*ec63e07aSXin Li if (iserr) {
308*ec63e07aSXin Li return absl::UnavailableError("Unable to compress");
309*ec63e07aSXin Li }
310*ec63e07aSXin Li
311*ec63e07aSXin Li infd.CloseRemoteFd(api.GetSandbox()->rpc_channel()).IgnoreError();
312*ec63e07aSXin Li outfd.CloseRemoteFd(api.GetSandbox()->rpc_channel()).IgnoreError();
313*ec63e07aSXin Li
314*ec63e07aSXin Li return absl::OkStatus();
315*ec63e07aSXin Li }
316*ec63e07aSXin Li
DecompressStreamFD(ZstdApi & api,sapi::v::Fd & infd,sapi::v::Fd & outfd)317*ec63e07aSXin Li absl::Status DecompressStreamFD(ZstdApi& api, sapi::v::Fd& infd,
318*ec63e07aSXin Li sapi::v::Fd& outfd) {
319*ec63e07aSXin Li SAPI_ASSIGN_OR_RETURN(ZSTD_DCtx * dctx, api.ZSTD_createDCtx());
320*ec63e07aSXin Li sapi::v::RemotePtr rdctx(dctx);
321*ec63e07aSXin Li
322*ec63e07aSXin Li SAPI_RETURN_IF_ERROR(api.GetSandbox()->TransferToSandboxee(&infd));
323*ec63e07aSXin Li SAPI_RETURN_IF_ERROR(api.GetSandbox()->TransferToSandboxee(&outfd));
324*ec63e07aSXin Li
325*ec63e07aSXin Li SAPI_ASSIGN_OR_RETURN(int iserr,
326*ec63e07aSXin Li api.ZSTD_decompressStream_fd(&rdctx, infd.GetRemoteFd(),
327*ec63e07aSXin Li outfd.GetRemoteFd()));
328*ec63e07aSXin Li if (iserr) {
329*ec63e07aSXin Li return absl::UnavailableError("Unable to decompress");
330*ec63e07aSXin Li }
331*ec63e07aSXin Li infd.CloseRemoteFd(api.GetSandbox()->rpc_channel()).IgnoreError();
332*ec63e07aSXin Li outfd.CloseRemoteFd(api.GetSandbox()->rpc_channel()).IgnoreError();
333*ec63e07aSXin Li
334*ec63e07aSXin Li return absl::OkStatus();
335*ec63e07aSXin Li }
336