xref: /aosp_15_r20/external/sandboxed-api/sandboxed_api/examples/zlib/main_zlib.cc (revision ec63e07ab9515d95e79c211197c445ef84cefa6a)
1 // Copyright 2019 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include <cassert>
16 #include <cstdio>
17 #include <cstdlib>
18 
19 #include "absl/base/log_severity.h"
20 #include "absl/base/macros.h"
21 #include "absl/flags/parse.h"
22 #include "absl/log/globals.h"
23 #include "absl/log/initialize.h"
24 #include "absl/log/log.h"
25 #include "absl/status/status.h"
26 #include "absl/status/statusor.h"
27 #include "sandboxed_api/examples/zlib/zlib-sapi.sapi.h"
28 #include "sandboxed_api/vars.h"
29 
30 // Need to define these manually, as zlib.h cannot be directly included. The
31 // interface generator makes all functions available that were requested in
32 // sapi_library(), but does not know which macro constants are needed by the
33 // sandboxee.
34 #define Z_NO_FLUSH 0
35 #define Z_FINISH 4
36 #define Z_OK 0
37 #define Z_DEFAULT_COMPRESSION (-1)
38 #define Z_ERRNO (-1)
39 #define Z_STREAM_ERROR (-2)
40 #define Z_STREAM_END 1
41 
main(int argc,char * argv[])42 int main(int argc, char* argv[]) {
43   absl::SetStderrThreshold(absl::LogSeverityAtLeast::kInfo);
44   absl::ParseCommandLine(argc, argv);
45   absl::InitializeLog();
46 
47   sapi::Sandbox sandbox(sapi::zlib::zlib_sapi_embed_create());
48   sapi::zlib::ZlibApi api(&sandbox);
49   if (auto status = sandbox.Init(); !status.ok()) {
50     LOG(FATAL) << "Couldn't initialize Sandboxed API for zlib: "
51                << status.message();
52   }
53 
54   absl::StatusOr<int> ret;
55   int flush;
56   unsigned have;
57   sapi::v::Struct<sapi::zlib::z_stream> strm;
58 
59   constexpr int kChunk = 16384;
60   unsigned char in_[kChunk] = {0};
61   unsigned char out_[kChunk] = {0};
62   sapi::v::Array<unsigned char> input(in_, kChunk);
63   sapi::v::Array<unsigned char> output(out_, kChunk);
64   if (!sandbox.Allocate(&input).ok() || !sandbox.Allocate(&output).ok()) {
65     LOG(FATAL) << "Allocate memory failed";
66   }
67 
68   constexpr char kZlibVersion[] = "1.2.11";
69   sapi::v::Array<const char> version(kZlibVersion,
70                                      ABSL_ARRAYSIZE(kZlibVersion));
71 
72   // Allocate deflate state.
73   *strm.mutable_data() = sapi::zlib::z_stream{};
74 
75   if (ret = api.deflateInit_(strm.PtrBoth(), Z_DEFAULT_COMPRESSION,
76                              version.PtrBefore(), sizeof(sapi::zlib::z_stream));
77       *ret != Z_OK) {
78     return *ret;
79   }
80 
81   LOG(INFO) << "Starting compression";
82 
83   // Compress until end of file.
84   do {
85     strm.mutable_data()->avail_in = fread(input.GetLocal(), 1, kChunk, stdin);
86     if (!sandbox.TransferToSandboxee(&input).ok()) {
87       LOG(FATAL) << "TransferToSandboxee failed";
88     }
89     if (ferror(stdin)) {
90       LOG(INFO) << "Error reading from stdin";
91       api.deflateEnd(strm.PtrBoth()).IgnoreError();
92       return Z_ERRNO;
93     }
94     flush = feof(stdin) ? Z_FINISH : Z_NO_FLUSH;
95     strm.mutable_data()->next_in =
96         reinterpret_cast<unsigned char*>(input.GetRemote());
97 
98     // Run deflate() on input until output buffer not full, finish compression
99     // if all of source has been read in.
100     do {
101       strm.mutable_data()->avail_out = kChunk;
102       strm.mutable_data()->next_out =
103           reinterpret_cast<unsigned char*>(output.GetRemote());
104 
105       ret = api.deflate(strm.PtrBoth(), flush);  // no bad return value.
106       assert(*ret != Z_STREAM_ERROR);            // state not clobbered.
107       have = kChunk - strm.data().avail_out;
108 
109       if (!sandbox.TransferFromSandboxee(&output).ok()) {
110         LOG(FATAL) << "TransferFromSandboxee failed";
111       }
112       if (fwrite(output.GetLocal(), 1, have, stdout) != have ||
113           ferror(stdout)) {
114         // Not really necessary as strm did not change from last transfer.
115         api.deflateEnd(strm.PtrBoth()).IgnoreError();
116         return Z_ERRNO;
117       }
118     } while (strm.data().avail_out == 0);
119     assert(strm.data().avail_in == 0);  // all input will be used.
120 
121     // done when last data in file processed.
122   } while (flush != Z_FINISH);
123   assert(*ret == Z_STREAM_END);  // stream will be complete.
124 
125   // clean up and return.
126   api.deflateEnd(strm.PtrBoth()).IgnoreError();
127 
128   return EXIT_SUCCESS;
129 }
130