12e71f90d6af955a5359853132085931f1e0479e0Alex Deymo//
22e71f90d6af955a5359853132085931f1e0479e0Alex Deymo// Copyright (C) 2015 The Android Open Source Project
32e71f90d6af955a5359853132085931f1e0479e0Alex Deymo//
42e71f90d6af955a5359853132085931f1e0479e0Alex Deymo// Licensed under the Apache License, Version 2.0 (the "License");
52e71f90d6af955a5359853132085931f1e0479e0Alex Deymo// you may not use this file except in compliance with the License.
62e71f90d6af955a5359853132085931f1e0479e0Alex Deymo// You may obtain a copy of the License at
72e71f90d6af955a5359853132085931f1e0479e0Alex Deymo//
82e71f90d6af955a5359853132085931f1e0479e0Alex Deymo//      http://www.apache.org/licenses/LICENSE-2.0
92e71f90d6af955a5359853132085931f1e0479e0Alex Deymo//
102e71f90d6af955a5359853132085931f1e0479e0Alex Deymo// Unless required by applicable law or agreed to in writing, software
112e71f90d6af955a5359853132085931f1e0479e0Alex Deymo// distributed under the License is distributed on an "AS IS" BASIS,
122e71f90d6af955a5359853132085931f1e0479e0Alex Deymo// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
132e71f90d6af955a5359853132085931f1e0479e0Alex Deymo// See the License for the specific language governing permissions and
142e71f90d6af955a5359853132085931f1e0479e0Alex Deymo// limitations under the License.
152e71f90d6af955a5359853132085931f1e0479e0Alex Deymo//
162e71f90d6af955a5359853132085931f1e0479e0Alex Deymo
1739910dcd1d68987ccee7c3031dc269233a8490bbAlex Deymo#include "update_engine/payload_consumer/xz_extent_writer.h"
182e71f90d6af955a5359853132085931f1e0479e0Alex Deymo
192e71f90d6af955a5359853132085931f1e0479e0Alex Deymousing std::vector;
202e71f90d6af955a5359853132085931f1e0479e0Alex Deymo
212e71f90d6af955a5359853132085931f1e0479e0Alex Deymonamespace chromeos_update_engine {
222e71f90d6af955a5359853132085931f1e0479e0Alex Deymo
232e71f90d6af955a5359853132085931f1e0479e0Alex Deymonamespace {
243f39d5cc753905874d8d93bef94f857b8808f19eAlex Vakulenkoconst brillo::Blob::size_type kOutputBufferLength = 16 * 1024;
252e71f90d6af955a5359853132085931f1e0479e0Alex Deymo
262e71f90d6af955a5359853132085931f1e0479e0Alex Deymo// xz uses a variable dictionary size which impacts on the compression ratio
272e71f90d6af955a5359853132085931f1e0479e0Alex Deymo// and is required to be reconstructed in RAM during decompression. While we
282e71f90d6af955a5359853132085931f1e0479e0Alex Deymo// control the required memory from the compressor side, the decompressor allows
292e71f90d6af955a5359853132085931f1e0479e0Alex Deymo// to set a limit on this dictionary size, rejecting compressed streams that
302e71f90d6af955a5359853132085931f1e0479e0Alex Deymo// require more than that. "xz -9" requires up to 64 MiB, so a 64 MiB limit
312e71f90d6af955a5359853132085931f1e0479e0Alex Deymo// will allow compressed streams up to -9, the maximum compression setting.
322e71f90d6af955a5359853132085931f1e0479e0Alex Deymoconst uint32_t kXzMaxDictSize = 64 * 1024 * 1024;
332e71f90d6af955a5359853132085931f1e0479e0Alex Deymo
342e71f90d6af955a5359853132085931f1e0479e0Alex Deymoconst char* XzErrorString(enum xz_ret error) {
352e71f90d6af955a5359853132085931f1e0479e0Alex Deymo  #define __XZ_ERROR_STRING_CASE(code) case code: return #code;
362e71f90d6af955a5359853132085931f1e0479e0Alex Deymo  switch (error) {
372e71f90d6af955a5359853132085931f1e0479e0Alex Deymo    __XZ_ERROR_STRING_CASE(XZ_OK)
382e71f90d6af955a5359853132085931f1e0479e0Alex Deymo    __XZ_ERROR_STRING_CASE(XZ_STREAM_END)
392e71f90d6af955a5359853132085931f1e0479e0Alex Deymo    __XZ_ERROR_STRING_CASE(XZ_UNSUPPORTED_CHECK)
402e71f90d6af955a5359853132085931f1e0479e0Alex Deymo    __XZ_ERROR_STRING_CASE(XZ_MEM_ERROR)
412e71f90d6af955a5359853132085931f1e0479e0Alex Deymo    __XZ_ERROR_STRING_CASE(XZ_MEMLIMIT_ERROR)
422e71f90d6af955a5359853132085931f1e0479e0Alex Deymo    __XZ_ERROR_STRING_CASE(XZ_FORMAT_ERROR)
432e71f90d6af955a5359853132085931f1e0479e0Alex Deymo    __XZ_ERROR_STRING_CASE(XZ_OPTIONS_ERROR)
442e71f90d6af955a5359853132085931f1e0479e0Alex Deymo    __XZ_ERROR_STRING_CASE(XZ_DATA_ERROR)
452e71f90d6af955a5359853132085931f1e0479e0Alex Deymo    __XZ_ERROR_STRING_CASE(XZ_BUF_ERROR)
462e71f90d6af955a5359853132085931f1e0479e0Alex Deymo    default:
472e71f90d6af955a5359853132085931f1e0479e0Alex Deymo      return "<unknown xz error>";
482e71f90d6af955a5359853132085931f1e0479e0Alex Deymo  }
492e71f90d6af955a5359853132085931f1e0479e0Alex Deymo  #undef __XZ_ERROR_STRING_CASE
502e71f90d6af955a5359853132085931f1e0479e0Alex Deymo};
512e71f90d6af955a5359853132085931f1e0479e0Alex Deymo}  // namespace
522e71f90d6af955a5359853132085931f1e0479e0Alex Deymo
532e71f90d6af955a5359853132085931f1e0479e0Alex DeymoXzExtentWriter::~XzExtentWriter() {
542e71f90d6af955a5359853132085931f1e0479e0Alex Deymo  xz_dec_end(stream_);
552e71f90d6af955a5359853132085931f1e0479e0Alex Deymo}
562e71f90d6af955a5359853132085931f1e0479e0Alex Deymo
572e71f90d6af955a5359853132085931f1e0479e0Alex Deymobool XzExtentWriter::Init(FileDescriptorPtr fd,
582e71f90d6af955a5359853132085931f1e0479e0Alex Deymo                          const vector<Extent>& extents,
592e71f90d6af955a5359853132085931f1e0479e0Alex Deymo                          uint32_t block_size) {
602e71f90d6af955a5359853132085931f1e0479e0Alex Deymo  stream_ = xz_dec_init(XZ_DYNALLOC, kXzMaxDictSize);
612e71f90d6af955a5359853132085931f1e0479e0Alex Deymo  TEST_AND_RETURN_FALSE(stream_ != nullptr);
622e71f90d6af955a5359853132085931f1e0479e0Alex Deymo  return underlying_writer_->Init(fd, extents, block_size);
632e71f90d6af955a5359853132085931f1e0479e0Alex Deymo}
642e71f90d6af955a5359853132085931f1e0479e0Alex Deymo
652e71f90d6af955a5359853132085931f1e0479e0Alex Deymobool XzExtentWriter::Write(const void* bytes, size_t count) {
662e71f90d6af955a5359853132085931f1e0479e0Alex Deymo  // Copy the input data into |input_buffer_| only if |input_buffer_| already
672e71f90d6af955a5359853132085931f1e0479e0Alex Deymo  // contains unconsumed data. Otherwise, process the data directly from the
682e71f90d6af955a5359853132085931f1e0479e0Alex Deymo  // source.
692e71f90d6af955a5359853132085931f1e0479e0Alex Deymo  const uint8_t* input = reinterpret_cast<const uint8_t*>(bytes);
702e71f90d6af955a5359853132085931f1e0479e0Alex Deymo  if (!input_buffer_.empty()) {
712e71f90d6af955a5359853132085931f1e0479e0Alex Deymo    input_buffer_.insert(input_buffer_.end(), input, input + count);
722e71f90d6af955a5359853132085931f1e0479e0Alex Deymo    input = input_buffer_.data();
732e71f90d6af955a5359853132085931f1e0479e0Alex Deymo    count = input_buffer_.size();
742e71f90d6af955a5359853132085931f1e0479e0Alex Deymo  }
752e71f90d6af955a5359853132085931f1e0479e0Alex Deymo
762e71f90d6af955a5359853132085931f1e0479e0Alex Deymo  xz_buf request;
772e71f90d6af955a5359853132085931f1e0479e0Alex Deymo  request.in = input;
782e71f90d6af955a5359853132085931f1e0479e0Alex Deymo  request.in_pos = 0;
792e71f90d6af955a5359853132085931f1e0479e0Alex Deymo  request.in_size = count;
802e71f90d6af955a5359853132085931f1e0479e0Alex Deymo
813f39d5cc753905874d8d93bef94f857b8808f19eAlex Vakulenko  brillo::Blob output_buffer(kOutputBufferLength);
822e71f90d6af955a5359853132085931f1e0479e0Alex Deymo  request.out = output_buffer.data();
832e71f90d6af955a5359853132085931f1e0479e0Alex Deymo  request.out_size = output_buffer.size();
842e71f90d6af955a5359853132085931f1e0479e0Alex Deymo  for (;;) {
852e71f90d6af955a5359853132085931f1e0479e0Alex Deymo    request.out_pos = 0;
862e71f90d6af955a5359853132085931f1e0479e0Alex Deymo
872e71f90d6af955a5359853132085931f1e0479e0Alex Deymo    xz_ret ret = xz_dec_run(stream_, &request);
882e71f90d6af955a5359853132085931f1e0479e0Alex Deymo    if (ret != XZ_OK && ret != XZ_STREAM_END) {
892e71f90d6af955a5359853132085931f1e0479e0Alex Deymo      LOG(ERROR) << "xz_dec_run returned " << XzErrorString(ret);
902e71f90d6af955a5359853132085931f1e0479e0Alex Deymo      return false;
912e71f90d6af955a5359853132085931f1e0479e0Alex Deymo    }
922e71f90d6af955a5359853132085931f1e0479e0Alex Deymo
932e71f90d6af955a5359853132085931f1e0479e0Alex Deymo    if (request.out_pos == 0)
942e71f90d6af955a5359853132085931f1e0479e0Alex Deymo      break;
952e71f90d6af955a5359853132085931f1e0479e0Alex Deymo
962e71f90d6af955a5359853132085931f1e0479e0Alex Deymo    TEST_AND_RETURN_FALSE(
972e71f90d6af955a5359853132085931f1e0479e0Alex Deymo        underlying_writer_->Write(output_buffer.data(), request.out_pos));
982e71f90d6af955a5359853132085931f1e0479e0Alex Deymo    if (ret == XZ_STREAM_END)
992e71f90d6af955a5359853132085931f1e0479e0Alex Deymo      CHECK_EQ(request.in_size, request.in_pos);
1002e71f90d6af955a5359853132085931f1e0479e0Alex Deymo    if (request.in_size == request.in_pos)
1012e71f90d6af955a5359853132085931f1e0479e0Alex Deymo      break;  // No more input to process.
1022e71f90d6af955a5359853132085931f1e0479e0Alex Deymo  }
1032e71f90d6af955a5359853132085931f1e0479e0Alex Deymo  output_buffer.clear();
1042e71f90d6af955a5359853132085931f1e0479e0Alex Deymo
1052e71f90d6af955a5359853132085931f1e0479e0Alex Deymo  // Store unconsumed data (if any) in |input_buffer_|. Since |input| can point
1062e71f90d6af955a5359853132085931f1e0479e0Alex Deymo  // to the existing |input_buffer_| we create a new one before assigning it.
1073f39d5cc753905874d8d93bef94f857b8808f19eAlex Vakulenko  brillo::Blob new_input_buffer(request.in + request.in_pos,
1083f39d5cc753905874d8d93bef94f857b8808f19eAlex Vakulenko                                request.in + request.in_size);
1092e71f90d6af955a5359853132085931f1e0479e0Alex Deymo  input_buffer_ = std::move(new_input_buffer);
1102e71f90d6af955a5359853132085931f1e0479e0Alex Deymo  return true;
1112e71f90d6af955a5359853132085931f1e0479e0Alex Deymo}
1122e71f90d6af955a5359853132085931f1e0479e0Alex Deymo
1132e71f90d6af955a5359853132085931f1e0479e0Alex Deymobool XzExtentWriter::EndImpl() {
1142e71f90d6af955a5359853132085931f1e0479e0Alex Deymo  TEST_AND_RETURN_FALSE(input_buffer_.empty());
1152e71f90d6af955a5359853132085931f1e0479e0Alex Deymo  return underlying_writer_->End();
1162e71f90d6af955a5359853132085931f1e0479e0Alex Deymo}
1172e71f90d6af955a5359853132085931f1e0479e0Alex Deymo
1182e71f90d6af955a5359853132085931f1e0479e0Alex Deymo}  // namespace chromeos_update_engine
119