1 // 2 // Copyright (C) 2017 The Android Open Source Project 3 // 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use this file except in compliance with the License. 6 // You may obtain a copy of the License at 7 // 8 // http://www.apache.org/licenses/LICENSE-2.0 9 // 10 // Unless required by applicable law or agreed to in writing, software 11 // distributed under the License is distributed on an "AS IS" BASIS, 12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 // 16 17 #include "update_engine/payload_consumer/file_descriptor_utils.h" 18 19 #include <algorithm> 20 21 #include <base/logging.h> 22 23 #include "update_engine/common/hash_calculator.h" 24 #include "update_engine/common/utils.h" 25 #include "update_engine/payload_consumer/extent_reader.h" 26 #include "update_engine/payload_consumer/extent_writer.h" 27 28 using google::protobuf::RepeatedPtrField; 29 using std::min; 30 31 namespace chromeos_update_engine { 32 33 namespace { 34 35 // Size of the buffer used to copy blocks. 36 const uint64_t kMaxCopyBufferSize = 1024 * 1024; 37 38 bool CommonHashExtents(FileDescriptorPtr source, 39 const RepeatedPtrField<Extent>& src_extents, 40 DirectExtentWriter* writer, 41 uint64_t block_size, 42 brillo::Blob* hash_out) { 43 auto total_blocks = utils::BlocksInExtents(src_extents); 44 auto buffer_blocks = kMaxCopyBufferSize / block_size; 45 // Ensure we copy at least one block at a time. 46 if (buffer_blocks < 1) 47 buffer_blocks = 1; 48 brillo::Blob buf(buffer_blocks * block_size); 49 50 DirectExtentReader reader; 51 TEST_AND_RETURN_FALSE(reader.Init(source, src_extents, block_size)); 52 53 HashCalculator source_hasher; 54 while (total_blocks > 0) { 55 auto read_blocks = std::min(total_blocks, buffer_blocks); 56 TEST_AND_RETURN_FALSE(reader.Read(buf.data(), read_blocks * block_size)); 57 if (hash_out != nullptr) { 58 TEST_AND_RETURN_FALSE( 59 source_hasher.Update(buf.data(), read_blocks * block_size)); 60 } 61 if (writer) { 62 TEST_AND_RETURN_FALSE( 63 writer->Write(buf.data(), read_blocks * block_size)); 64 } 65 total_blocks -= read_blocks; 66 } 67 68 if (hash_out != nullptr) { 69 TEST_AND_RETURN_FALSE(source_hasher.Finalize()); 70 *hash_out = source_hasher.raw_hash(); 71 } 72 return true; 73 } 74 75 } // namespace 76 77 namespace fd_utils { 78 79 bool CopyAndHashExtents(FileDescriptorPtr source, 80 const RepeatedPtrField<Extent>& src_extents, 81 FileDescriptorPtr target, 82 const RepeatedPtrField<Extent>& tgt_extents, 83 uint64_t block_size, 84 brillo::Blob* hash_out) { 85 DirectExtentWriter writer; 86 TEST_AND_RETURN_FALSE(writer.Init(target, tgt_extents, block_size)); 87 TEST_AND_RETURN_FALSE(utils::BlocksInExtents(src_extents) == 88 utils::BlocksInExtents(tgt_extents)); 89 TEST_AND_RETURN_FALSE( 90 CommonHashExtents(source, src_extents, &writer, block_size, hash_out)); 91 return true; 92 } 93 94 bool ReadAndHashExtents(FileDescriptorPtr source, 95 const RepeatedPtrField<Extent>& extents, 96 uint64_t block_size, 97 brillo::Blob* hash_out) { 98 return CommonHashExtents(source, extents, nullptr, block_size, hash_out); 99 } 100 101 } // namespace fd_utils 102 103 } // namespace chromeos_update_engine 104