xref: /aosp_15_r20/external/sandboxed-api/oss-internship-2020/guetzli/guetzli_transaction.cc (revision ec63e07ab9515d95e79c211197c445ef84cefa6a)
1 // Copyright 2020 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 "guetzli_transaction.h"  // NOLINT(build/include)
16 
17 #include <fcntl.h>
18 #include <sys/stat.h>
19 #include <sys/types.h>
20 #include <unistd.h>
21 
22 #include <iostream>
23 #include <memory>
24 
25 #include "absl/status/statusor.h"
26 
27 namespace guetzli::sandbox {
28 
Main()29 absl::Status GuetzliTransaction::Main() {
30   sapi::v::Fd in_fd(open(params_.in_file, O_RDONLY));
31 
32   if (in_fd.GetValue() < 0) {
33     return absl::FailedPreconditionError("Error opening input file");
34   }
35 
36   SAPI_ASSIGN_OR_RETURN(image_type_, GetImageTypeFromFd(in_fd.GetValue()));
37   SAPI_RETURN_IF_ERROR(sandbox()->TransferToSandboxee(&in_fd));
38 
39   if (in_fd.GetRemoteFd() < 0) {
40     return absl::FailedPreconditionError(
41         "Error receiving remote FD: remote input fd is set to -1");
42   }
43 
44   GuetzliApi api(sandbox());
45   sapi::v::LenVal output(0);
46 
47   sapi::v::Struct<ProcessingParams> processing_params;
48   *processing_params.mutable_data() = {in_fd.GetRemoteFd(), params_.verbose,
49                                        params_.quality, params_.memlimit_mb};
50 
51   auto result =
52       image_type_ == ImageType::kJpeg
53           ? api.ProcessJpeg(processing_params.PtrBefore(), output.PtrBefore())
54           : api.ProcessRgb(processing_params.PtrBefore(), output.PtrBefore());
55 
56   if (!result.value_or(false)) {
57     return absl::FailedPreconditionError(absl::StrCat(
58         "Error processing ", (image_type_ == ImageType::kJpeg ? "jpeg" : "rgb"),
59         " data"));
60   }
61 
62   sapi::v::Fd out_fd(open(".", O_TMPFILE | O_RDWR, S_IRUSR | S_IWUSR));
63   if (out_fd.GetValue() < 0) {
64     return absl::FailedPreconditionError("Error creating temp output file");
65   }
66 
67   SAPI_RETURN_IF_ERROR(sandbox()->TransferToSandboxee(&out_fd));
68 
69   if (out_fd.GetRemoteFd() < 0) {
70     return absl::FailedPreconditionError(
71         "Error receiving remote FD: remote output fd is set to -1");
72   }
73 
74   auto write_result = api.WriteDataToFd(out_fd.GetRemoteFd(), output.PtrNone());
75 
76   if (!write_result.value_or(false)) {
77     return absl::FailedPreconditionError("Error writing file inside sandbox");
78   }
79 
80   SAPI_RETURN_IF_ERROR(LinkOutFile(out_fd.GetValue()));
81 
82   return absl::OkStatus();
83 }
84 
LinkOutFile(int out_fd) const85 absl::Status GuetzliTransaction::LinkOutFile(int out_fd) const {
86   if (access(params_.out_file, F_OK) != -1) {
87     if (remove(params_.out_file) < 0) {
88       return absl::FailedPreconditionError(absl::StrCat(
89           "Error deleting existing output file: ", params_.out_file));
90     }
91   }
92 
93   std::string path = absl::StrCat("/proc/self/fd/", out_fd);
94 
95   if (linkat(AT_FDCWD, path.c_str(), AT_FDCWD, params_.out_file,
96              AT_SYMLINK_FOLLOW) < 0) {
97     return absl::FailedPreconditionError(
98         absl::StrCat("Error linking: ", params_.out_file));
99   }
100 
101   return absl::OkStatus();
102 }
103 
GetImageTypeFromFd(int fd) const104 absl::StatusOr<ImageType> GuetzliTransaction::GetImageTypeFromFd(int fd) const {
105   static const unsigned char kPNGMagicBytes[] = {
106       0x89, 'P', 'N', 'G', '\r', '\n', 0x1a, '\n',
107   };
108   char read_buf[sizeof(kPNGMagicBytes)];
109 
110   if (read(fd, read_buf, sizeof(kPNGMagicBytes)) != sizeof(kPNGMagicBytes)) {
111     return absl::FailedPreconditionError(
112         "Error determining type of the input file");
113   }
114 
115   if (lseek(fd, 0, SEEK_SET) != 0) {
116     return absl::FailedPreconditionError(
117         "Error returnig cursor to the beginning");
118   }
119 
120   return memcmp(read_buf, kPNGMagicBytes, sizeof(kPNGMagicBytes)) == 0
121              ? ImageType::kPng
122              : ImageType::kJpeg;
123 }
124 
125 }  // namespace guetzli::sandbox
126