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