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