resolve merge conflicts of f4e69fd to stage-aosp-master

stage-aosp-master already had the CL that was cherry-picked to
aosp/master but the CLs landed together with other CLs so the merge
didn't realize the CL was already applied.

Test: I solemnly swear I tested this conflict resolution.
Change-Id: Ia41a55653312f82dbf7f2f29f4b8cde368f8d3eb
This commit is contained in:
Alex Deymo committed 2017-09-19 14:11:55 +02:00
commit f074bc8571
10 files changed
+560 -274

No files matched your search

+113
View File
@@ -0,0 +1,113 @@
// Copyright (C) 2008 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
cc_defaults {
name: "bsdiff_defaults",
host_supported: true,
static_libs: ["libbz"],
export_include_dirs: [
"include",
// TODO(deymo): Remove include/bsdiff when all callers use the "bsdiff/"
// prefix when including code.
"include/bsdiff",
],
cflags: [
"-D_FILE_OFFSET_BITS=64",
"-Wall",
"-Werror",
"-Wextra",
"-Wno-unused-parameter",
],
}
// Host and target static libraries.
cc_library_static {
name: "libbspatch",
defaults: ["bsdiff_defaults"],
srcs: [
"bspatch.cc",
"buffer_file.cc",
"extents.cc",
"extents_file.cc",
"file.cc",
"memory_file.cc",
"sink_file.cc",
],
}
cc_library_static {
name: "libbsdiff",
defaults: ["bsdiff_defaults"],
srcs: [
"bsdiff.cc",
"bz2_compressor.cc",
"patch_writer.cc",
],
static_libs: [
"libdivsufsort64",
"libdivsufsort",
],
}
// Host and target Executables.
cc_binary {
name: "bspatch",
defaults: ["bsdiff_defaults"],
srcs: ["bspatch_main.cc"],
static_libs: [
"libbspatch",
"libbz",
],
}
// Host executables, bsdiff is only built for the host.
cc_binary_host {
name: "bsdiff",
defaults: ["bsdiff_defaults"],
srcs: ["bsdiff_main.cc"],
static_libs: [
"libbsdiff",
"libdivsufsort64",
"libdivsufsort",
"libbz",
],
}
// Unit tests.
cc_test {
name: "bsdiff_unittest",
defaults: ["bsdiff_defaults"],
test_suites: ["device-tests"],
srcs: [
"bsdiff_unittest.cc",
"bspatch_unittest.cc",
"extents_file_unittest.cc",
"extents_unittest.cc",
"test_utils.cc",
"testrunner.cc",
],
cflags: ["-DBSDIFF_TARGET_UNITTEST"],
static_libs: [
"libbsdiff",
"libbspatch",
"libgmock",
"libdivsufsort64",
"libdivsufsort",
"libbz",
],
}
-155
View File
@@ -1,155 +0,0 @@
# Copyright (C) 2008 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
LOCAL_PATH := $(call my-dir)
# Common project flags.
bsdiff_common_cflags := \
-D_FILE_OFFSET_BITS=64 \
-Wall \
-Werror \
-Wextra \
-Wno-unused-parameter
bsdiff_common_static_libs := \
libbz
# "bsdiff" program.
bsdiff_static_libs := \
libdivsufsort64 \
libdivsufsort \
$(bsdiff_common_static_libs)
bsdiff_src_files := \
bsdiff.cc
# "bspatch" program.
bspatch_src_files := \
bspatch.cc \
buffer_file.cc \
extents.cc \
extents_file.cc \
file.cc \
memory_file.cc \
sink_file.cc
# Unit test files.
bsdiff_common_unittests := \
bsdiff_unittest.cc \
bspatch_unittest.cc \
extents_file_unittest.cc \
extents_unittest.cc \
test_utils.cc
# TODO(deymo): Remove include/bsdiff when all callers use the "bsdiff/" prefix
# when including code.
lib_export_includes := \
$(LOCAL_PATH)/include \
$(LOCAL_PATH)/include/bsdiff
# Target static libraries.
include $(CLEAR_VARS)
LOCAL_MODULE := libbspatch
LOCAL_CPP_EXTENSION := .cc
LOCAL_SRC_FILES := $(bspatch_src_files)
LOCAL_CFLAGS := $(bsdiff_common_cflags)
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
LOCAL_EXPORT_C_INCLUDE_DIRS := $(lib_export_includes)
LOCAL_STATIC_LIBRARIES := $(bsdiff_common_static_libs)
include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := libbsdiff
LOCAL_CPP_EXTENSION := .cc
LOCAL_SRC_FILES := $(bsdiff_src_files)
LOCAL_CFLAGS := $(bsdiff_common_cflags)
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
LOCAL_EXPORT_C_INCLUDE_DIRS := $(lib_export_includes)
LOCAL_STATIC_LIBRARIES := $(bsdiff_static_libs)
include $(BUILD_STATIC_LIBRARY)
# Host static libraries.
include $(CLEAR_VARS)
LOCAL_MODULE := libbspatch
LOCAL_CPP_EXTENSION := .cc
LOCAL_SRC_FILES := $(bspatch_src_files)
LOCAL_CFLAGS := $(bsdiff_common_cflags)
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
LOCAL_EXPORT_C_INCLUDE_DIRS := $(lib_export_includes)
LOCAL_STATIC_LIBRARIES := $(bsdiff_common_static_libs)
include $(BUILD_HOST_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := libbsdiff
LOCAL_CPP_EXTENSION := .cc
LOCAL_SRC_FILES := $(bsdiff_src_files)
LOCAL_CFLAGS := $(bsdiff_common_cflags)
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
LOCAL_EXPORT_C_INCLUDE_DIRS := $(lib_export_includes)
LOCAL_STATIC_LIBRARIES := $(bsdiff_static_libs)
include $(BUILD_HOST_STATIC_LIBRARY)
# Target executables.
include $(CLEAR_VARS)
LOCAL_MODULE := bspatch
LOCAL_CPP_EXTENSION := .cc
LOCAL_SRC_FILES := bspatch_main.cc
LOCAL_CFLAGS := $(bsdiff_common_cflags)
LOCAL_STATIC_LIBRARIES := \
libbspatch \
$(bsdiff_common_static_libs)
include $(BUILD_EXECUTABLE)
# Host executables.
include $(CLEAR_VARS)
LOCAL_MODULE := bsdiff
LOCAL_CPP_EXTENSION := .cc
LOCAL_SRC_FILES := bsdiff_main.cc
LOCAL_CFLAGS := $(bsdiff_common_cflags)
LOCAL_STATIC_LIBRARIES := \
libbsdiff \
$(bsdiff_static_libs)
include $(BUILD_HOST_EXECUTABLE)
include $(CLEAR_VARS)
LOCAL_MODULE := bspatch
LOCAL_CPP_EXTENSION := .cc
LOCAL_SRC_FILES := bspatch_main.cc
LOCAL_CFLAGS := $(bsdiff_common_cflags)
LOCAL_STATIC_LIBRARIES := \
libbspatch \
$(bsdiff_common_static_libs)
include $(BUILD_HOST_EXECUTABLE)
# Unit tests.
include $(CLEAR_VARS)
LOCAL_MODULE := bsdiff_unittest
LOCAL_COMPATIBILITY_SUITE := device-tests
LOCAL_MODULE_TAGS := debug tests
LOCAL_CPP_EXTENSION := .cc
LOCAL_SRC_FILES := $(bsdiff_common_unittests) \
testrunner.cc
LOCAL_CFLAGS := $(bsdiff_common_cflags) \
-DBSDIFF_TARGET_UNITTEST
LOCAL_STATIC_LIBRARIES := \
libbsdiff \
libbspatch \
libgmock \
$(bsdiff_static_libs)
include $(BUILD_NATIVE_TEST)
+3 -1
View File
@@ -33,7 +33,9 @@ clean:
### List of source files for each project. Keep in sync with the Android.mk.
# "bsdiff" program.
bsdiff_src_files := \
bsdiff.cc
bsdiff.cc \
bz2_compressor.cc \
patch_writer.cc
# "bspatch" program.
bspatch_src_files := \
+11 -118
View File
@@ -32,7 +32,6 @@ __FBSDID("$FreeBSD: src/usr.bin/bsdiff/bsdiff/bsdiff.c,v 1.1 2005/08/06 01:59:05
#include <sys/types.h>
#include <bzlib.h>
#include <err.h>
#include <fcntl.h>
#include <stdio.h>
@@ -42,6 +41,8 @@ __FBSDID("$FreeBSD: src/usr.bin/bsdiff/bsdiff/bsdiff.c,v 1.1 2005/08/06 01:59:05
#include <algorithm>
#include "patch_writer.h"
namespace bsdiff {
static off_t matchlen(const u_char* old, off_t oldsize, const u_char* new_buf,
@@ -85,24 +86,6 @@ static off_t search(saidx_t* I, const u_char* old, off_t oldsize,
};
}
static void offtout(off_t x,u_char *buf)
{
off_t y;
if(x<0) y=-x; else y=x;
buf[0]=y%256;y-=buf[0];
y=y/256;buf[1]=y%256;y-=buf[1];
y=y/256;buf[2]=y%256;y-=buf[2];
y=y/256;buf[3]=y%256;y-=buf[3];
y=y/256;buf[4]=y%256;y-=buf[4];
y=y/256;buf[5]=y%256;y-=buf[5];
y=y/256;buf[6]=y%256;y-=buf[6];
y=y/256;buf[7]=y%256;
if(x<0) buf[7]|=0x80;
}
int bsdiff(const char* old_filename, const char* new_filename,
const char* patch_filename) {
int fd;
@@ -148,13 +131,7 @@ int bsdiff(const u_char* old_buf, off_t oldsize, const u_char* new_buf,
off_t s,Sf,lenf,Sb,lenb;
off_t overlap,Ss,lens;
off_t i;
off_t dblen,eblen;
u_char *db,*eb;
u_char buf[8];
u_char header[32];
FILE * pf;
BZFILE * pfbz2;
int bz2err;
BsdiffPatchWriter patch(old_buf, oldsize, new_buf, newsize);
if (I_cache && *I_cache) {
I = *I_cache;
@@ -167,35 +144,11 @@ int bsdiff(const u_char* old_buf, off_t oldsize, const u_char* new_buf,
*I_cache = I;
}
if(((db=static_cast<u_char*>(malloc(newsize+1)))==NULL) ||
((eb=static_cast<u_char*>(malloc(newsize+1)))==NULL)) err(1,NULL);
dblen=0;
eblen=0;
/* Create the patch file */
if ((pf = fopen(patch_filename, "w")) == NULL)
err(1, "%s", patch_filename);
/* Header is
0 8 "BSDIFF40"
8 8 length of bzip2ed ctrl block
16 8 length of bzip2ed diff block
24 8 length of new file */
/* File is
0 32 Header
32 ?? Bzip2ed ctrl block
?? ?? Bzip2ed diff block
?? ?? Bzip2ed extra block */
memcpy(header,"BSDIFF40",8);
offtout(0, header + 8);
offtout(0, header + 16);
offtout(newsize, header + 24);
if (fwrite(header, 32, 1, pf) != 1)
err(1, "fwrite(%s)", patch_filename);
if (!patch.Open(patch_filename))
return 1;
/* Compute the differences, writing ctrl as we go */
if ((pfbz2 = BZ2_bzWriteOpen(&bz2err, pf, 9, 0, 0)) == NULL)
errx(1, "BZ2_bzWriteOpen, bz2err = %d", bz2err);
scan=0;len=0;
lastscan=0;lastpos=0;lastoffset=0;
while(scan<newsize) {
@@ -271,79 +224,19 @@ int bsdiff(const u_char* old_buf, off_t oldsize, const u_char* new_buf,
lenb-=lens;
};
for(i=0;i<lenf;i++)
db[dblen+i]=new_buf[lastscan+i]-old_buf[lastpos+i];
for(i=0;i<(scan-lenb)-(lastscan+lenf);i++)
eb[eblen+i]=new_buf[lastscan+lenf+i];
dblen+=lenf;
eblen+=(scan-lenb)-(lastscan+lenf);
offtout(lenf,buf);
BZ2_bzWrite(&bz2err, pfbz2, buf, 8);
if (bz2err != BZ_OK)
errx(1, "BZ2_bzWrite, bz2err = %d", bz2err);
offtout((scan-lenb)-(lastscan+lenf),buf);
BZ2_bzWrite(&bz2err, pfbz2, buf, 8);
if (bz2err != BZ_OK)
errx(1, "BZ2_bzWrite, bz2err = %d", bz2err);
offtout((pos-lenb)-(lastpos+lenf),buf);
BZ2_bzWrite(&bz2err, pfbz2, buf, 8);
if (bz2err != BZ_OK)
errx(1, "BZ2_bzWrite, bz2err = %d", bz2err);
if (!patch.AddControlEntry(ControlEntry(lenf,
(scan - lenb) - (lastscan + lenf),
(pos - lenb) - (lastpos + lenf))))
errx(1, "Writing a control entry");
lastscan=scan-lenb;
lastpos=pos-lenb;
lastoffset=pos-scan;
};
};
BZ2_bzWriteClose(&bz2err, pfbz2, 0, NULL, NULL);
if (bz2err != BZ_OK)
errx(1, "BZ2_bzWriteClose, bz2err = %d", bz2err);
if (!patch.Close())
errx(1, "Closing the patch file");
/* Compute size of compressed ctrl data */
if ((len = ftello(pf)) == -1)
err(1, "ftello");
offtout(len-32, header + 8);
/* Write compressed diff data */
if ((pfbz2 = BZ2_bzWriteOpen(&bz2err, pf, 9, 0, 0)) == NULL)
errx(1, "BZ2_bzWriteOpen, bz2err = %d", bz2err);
BZ2_bzWrite(&bz2err, pfbz2, db, dblen);
if (bz2err != BZ_OK)
errx(1, "BZ2_bzWrite, bz2err = %d", bz2err);
BZ2_bzWriteClose(&bz2err, pfbz2, 0, NULL, NULL);
if (bz2err != BZ_OK)
errx(1, "BZ2_bzWriteClose, bz2err = %d", bz2err);
/* Compute size of compressed diff data */
if ((newsize = ftello(pf)) == -1)
err(1, "ftello");
offtout(newsize - len, header + 16);
/* Write compressed extra data */
if ((pfbz2 = BZ2_bzWriteOpen(&bz2err, pf, 9, 0, 0)) == NULL)
errx(1, "BZ2_bzWriteOpen, bz2err = %d", bz2err);
BZ2_bzWrite(&bz2err, pfbz2, eb, eblen);
if (bz2err != BZ_OK)
errx(1, "BZ2_bzWrite, bz2err = %d", bz2err);
BZ2_bzWriteClose(&bz2err, pfbz2, 0, NULL, NULL);
if (bz2err != BZ_OK)
errx(1, "BZ2_bzWriteClose, bz2err = %d", bz2err);
/* Seek to the beginning, write the header, and close the file */
if (fseeko(pf, 0, SEEK_SET))
err(1, "fseeko");
if (fwrite(header, 32, 1, pf) != 1)
err(1, "fwrite(%s)", patch_filename);
if (fclose(pf))
err(1, "fclose");
/* Free the memory we used */
free(db);
free(eb);
if (I_cache == nullptr)
free(I);
+2
View File
@@ -48,6 +48,8 @@
},
'sources': [
'bsdiff.cc',
"bz2_compressor.cc",
"patch_writer.cc",
],
},
# bsdiff executable
+116
View File
@@ -0,0 +1,116 @@
// Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "bz2_compressor.h"
#include <string.h>
#include "logging.h"
using std::endl;
namespace {
// The BZ2 compression level used. Smaller compression levels are nowadays
// pointless.
const int kCompressionLevel = 9;
} // namespace
namespace bsdiff {
BZ2Compressor::BZ2Compressor() {
memset(&bz_strm_, 0, sizeof(bz_strm_));
int bz_err = BZ2_bzCompressInit(&bz_strm_, kCompressionLevel,
0 /* verbosity */, 0 /* workFactor */);
if (bz_err != BZ_OK) {
LOG(ERROR) << "Initializing bz_strm, bz_error=" << bz_err << endl;
} else {
bz_strm_initialized_ = true;
}
comp_buffer_.resize(1024 * 1024);
}
BZ2Compressor::~BZ2Compressor() {
if (!bz_strm_initialized_)
return;
int bz_err = BZ2_bzCompressEnd(&bz_strm_);
if (bz_err != BZ_OK) {
LOG(ERROR) << "Deleting the compressor stream, bz_error=" << bz_err << endl;
}
}
bool BZ2Compressor::Write(const uint8_t* buf, size_t size) {
if (!bz_strm_initialized_)
return false;
// The bz_stream struct defines the next_in as a non-const data pointer,
// although the documentation says it won't modify it.
bz_strm_.next_in = reinterpret_cast<char*>(const_cast<uint8_t*>(buf));
bz_strm_.avail_in = size;
while (bz_strm_.avail_in) {
bz_strm_.next_out = reinterpret_cast<char*>(comp_buffer_.data());
bz_strm_.avail_out = comp_buffer_.size();
int bz_err = BZ2_bzCompress(&bz_strm_, BZ_RUN);
if (bz_err != BZ_RUN_OK) {
LOG(ERROR) << "Compressing data, bz_error=" << bz_err << endl;
return false;
}
uint64_t output_bytes = comp_buffer_.size() - bz_strm_.avail_out;
if (output_bytes) {
comp_chunks_.emplace_back(comp_buffer_.data(),
comp_buffer_.data() + output_bytes);
}
}
return true;
}
bool BZ2Compressor::Finish() {
if (!bz_strm_initialized_)
return false;
bz_strm_.next_in = nullptr;
bz_strm_.avail_in = 0;
int bz_err = BZ_FINISH_OK;
while (bz_err == BZ_FINISH_OK) {
bz_strm_.next_out = reinterpret_cast<char*>(comp_buffer_.data());
bz_strm_.avail_out = comp_buffer_.size();
bz_err = BZ2_bzCompress(&bz_strm_, BZ_FINISH);
uint64_t output_bytes = comp_buffer_.size() - bz_strm_.avail_out;
if (output_bytes) {
comp_chunks_.emplace_back(comp_buffer_.data(),
comp_buffer_.data() + output_bytes);
}
}
if (bz_err != BZ_STREAM_END) {
LOG(ERROR) << "Finishing compressing data, bz_error=" << bz_err << endl;
return false;
}
bz_err = BZ2_bzCompressEnd(&bz_strm_);
bz_strm_initialized_ = false;
if (bz_err != BZ_OK) {
LOG(ERROR) << "Deleting the compressor stream, bz_error=" << bz_err << endl;
return false;
}
return true;
}
const std::vector<uint8_t>& BZ2Compressor::GetCompressedData() {
if (!comp_chunks_.empty()) {
size_t chunks_size = 0;
for (const auto& chunk : comp_chunks_)
chunks_size += chunk.size();
comp_data_.reserve(comp_data_.size() + chunks_size);
for (const auto& chunk : comp_chunks_) {
comp_data_.insert(comp_data_.end(), chunk.begin(), chunk.end());
}
comp_chunks_.clear();
}
return comp_data_;
}
} // namespace bsdiff
+55
View File
@@ -0,0 +1,55 @@
// Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef _BSDIFF_BZ2_COMPRESSOR_H_
#define _BSDIFF_BZ2_COMPRESSOR_H_
#include <bzlib.h>
#include <stdint.h>
#include <vector>
namespace bsdiff {
// An in-memory class to wrap the low-level bzip2 compress functions. This class
// allows to stream uncompressed data to it and then retrieve all the compressed
// data at the end of the compression step. For that, all the compressed data
// is stored in memory.
class BZ2Compressor {
public:
BZ2Compressor();
~BZ2Compressor();
// Compress and write the data at |buf| of size |size|.
bool Write(const uint8_t* buf, size_t size);
// Finish the compression step.
bool Finish();
// Return the compressed data. This method must be only called after Finish().
const std::vector<uint8_t>& GetCompressedData();
private:
// The low-level bzip2 stream.
bz_stream bz_strm_;
// Whether the bz_strm_ is initialized.
bool bz_strm_initialized_{false};
// A list of chunks of compressed data. The final compressed representation is
// the concatenation of all the compressed data.
std::vector<std::vector<uint8_t>> comp_chunks_;
// A concatenated version of the |comp_chunks_|, used to store the compressed
// memory after Finish() is called.
std::vector<uint8_t> comp_data_;
// A temporary compression buffer for multiple calls to Write().
std::vector<uint8_t> comp_buffer_;
};
} // namespace bsdiff
#endif // _BSDIFF_BZ2_COMPRESSOR_H_
+15
View File
@@ -0,0 +1,15 @@
// Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef _BSDIFF_LOGGING_H_
#define _BSDIFF_LOGGING_H_
#include <iostream>
// Simple error logging macro to avoid dependencies in other base libraries.
// Unfortunately, you must pass std::endl as the last element on the stream to
// produce the new line.
#define LOG(X) (std::cerr << #X << " " << __FILE__ << ":" << __LINE__ << ": ")
#endif // _BSDIFF_LOGGING_H_
+158
View File
@@ -0,0 +1,158 @@
// Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "patch_writer.h"
#include <string.h>
#include "logging.h"
using std::endl;
namespace {
// The maximum positive number that we should encode. A number larger than this
// for unsigned fields will be interpreted as a negative value and thus a
// corrupt patch.
const uint64_t kMaxEncodedUint64Value = (1ULL << 63) - 1;
constexpr uint8_t kMagicHeader[] = "BSDIFF40";
void EncodeInt64(int64_t x, uint8_t* buf) {
uint64_t y = x < 0 ? (1ULL << 63ULL) - x : x;
for (int i = 0; i < 8; ++i) {
buf[i] = y & 0xff;
y /= 256;
}
}
} // namespace
namespace bsdiff {
bool BsdiffPatchWriter::Open(const std::string& patch_filename) {
fp_ = fopen(patch_filename.c_str(), "w");
if (!fp_) {
LOG(ERROR) << "Opening " << patch_filename << endl;
return false;
}
return true;
}
bool BsdiffPatchWriter::AddControlEntry(const ControlEntry& entry) {
if (entry.diff_size > kMaxEncodedUint64Value) {
LOG(ERROR) << "Encoding value out of range " << entry.diff_size << endl;
return false;
}
if (entry.extra_size > kMaxEncodedUint64Value) {
LOG(ERROR) << "Encoding value out of range " << entry.extra_size << endl;
return false;
}
if (written_output_ + entry.diff_size + entry.extra_size > new_size_) {
LOG(ERROR) << "Wrote more output than the declared new_size" << endl;
return false;
}
if (entry.diff_size > 0 &&
(old_pos_ < 0 || static_cast<uint64_t>(old_pos_) >= old_size_)) {
LOG(ERROR) << "The pointer in the old stream (" << old_pos_
<< ") is out of bounds [0, " << old_size_ << ")" << endl;
return false;
}
// Generate the 24 byte control entry.
uint8_t buf[24];
EncodeInt64(entry.diff_size, buf);
EncodeInt64(entry.extra_size, buf + 8);
EncodeInt64(entry.offset_increment, buf + 16);
if (!ctrl_stream_.Write(buf, sizeof(buf)))
return false;
// Generate the diff stream.
std::vector<uint8_t> diff(entry.diff_size);
for (uint64_t i = 0; i < entry.diff_size; ++i) {
diff[i] = new_buf_[written_output_ + i] - old_buf_[old_pos_ + i];
}
if (!diff_stream_.Write(diff.data(), diff.size()))
return false;
if (!extra_stream_.Write(new_buf_ + written_output_ + entry.diff_size,
entry.extra_size))
return false;
old_pos_ += entry.diff_size + entry.offset_increment;
written_output_ += entry.diff_size + entry.extra_size;
return true;
}
bool BsdiffPatchWriter::Close() {
if (!fp_) {
LOG(ERROR) << "File not open." << endl;
return false;
}
if (written_output_ != new_size_) {
LOG(ERROR) << "Close() called but not all the output was written" << endl;
return false;
}
if (!ctrl_stream_.Finish() || !diff_stream_.Finish() ||
!extra_stream_.Finish())
return false;
auto ctrl_data = ctrl_stream_.GetCompressedData();
auto diff_data = diff_stream_.GetCompressedData();
auto extra_data = extra_stream_.GetCompressedData();
if (!WriteHeader(ctrl_data.size(), diff_data.size()))
return false;
if (fwrite(ctrl_data.data(), 1, ctrl_data.size(), fp_) != ctrl_data.size()) {
LOG(ERROR) << "Writing ctrl_data." << endl;
return false;
}
if (fwrite(diff_data.data(), 1, diff_data.size(), fp_) != diff_data.size()) {
LOG(ERROR) << "Writing diff_data." << endl;
return false;
}
if (fwrite(extra_data.data(), 1, extra_data.size(), fp_) !=
extra_data.size()) {
LOG(ERROR) << "Writing extra_data." << endl;
return false;
}
if (fclose(fp_) != 0) {
LOG(ERROR) << "Closing the patch file." << endl;
return false;
}
fp_ = nullptr;
return true;
}
bool BsdiffPatchWriter::WriteHeader(uint64_t ctrl_size, uint64_t diff_size) {
/* Header format is
* 0 8 "BSDIFF40"
* 8 8 length of bzip2ed ctrl block
* 16 8 length of bzip2ed diff block
* 24 8 length of new file
*
* File format is
* 0 32 Header
* 32 ?? Bzip2ed ctrl block
* ?? ?? Bzip2ed diff block
* ?? ?? Bzip2ed extra block
*/
uint8_t header[32];
memcpy(header, kMagicHeader, 8);
EncodeInt64(ctrl_size, header + 8);
EncodeInt64(diff_size, header + 16);
EncodeInt64(new_size_, header + 24);
if (fwrite(header, sizeof(header), 1, fp_) != 1) {
LOG(ERROR) << "writing to the patch file" << endl;
return false;
}
return true;
}
} // namespace bsdiff
+87
View File
@@ -0,0 +1,87 @@
// Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef _BSDIFF_PATCH_WRITER_H_
#define _BSDIFF_PATCH_WRITER_H_
#include <stdio.h>
#include <string>
#include <vector>
#include "bsdiff/common.h"
#include "bz2_compressor.h"
namespace bsdiff {
struct ControlEntry {
ControlEntry(uint64_t diff_size,
uint64_t extra_size,
int64_t offset_increment)
: diff_size(diff_size),
extra_size(extra_size),
offset_increment(offset_increment) {}
// The number of bytes to copy from the source and diff stream.
uint64_t diff_size;
// The number of bytes to copy from the extra stream.
uint64_t extra_size;
// The value to add to the source pointer after patching from the diff stream.
int64_t offset_increment;
};
class BsdiffPatchWriter {
public:
BsdiffPatchWriter(const uint8_t* old_buf,
uint64_t old_size,
const uint8_t* new_buf,
uint64_t new_size)
: old_buf_(old_buf),
old_size_(old_size),
new_buf_(new_buf),
new_size_(new_size) {}
// Create the file |patch_filename| where the patch will be written to.
bool Open(const std::string& patch_filename);
// Add a new control triplet entry to the patch. The |entry.diff_size| bytes
// for the diff stream and the |entry.extra_size| bytes for the extra stream
// will be computed and added to the corresponding streams in the patch.
// Returns whether the operation succeeded. The operation can fail if either
// the old or new files are referenced out of bounds.
bool AddControlEntry(const ControlEntry& entry);
bool Close();
private:
// Write the BSDIFF patch header to the |fp_| given the size of the compressed
// control block and the compressed diff block.
bool WriteHeader(uint64_t ctrl_size, uint64_t diff_size);
const uint8_t* old_buf_;
uint64_t old_size_;
const uint8_t* new_buf_;
uint64_t new_size_;
// Bytes of the new_buf_ already written.
uint64_t written_output_{0};
// The current position in the old buf.
int64_t old_pos_{0};
// The current file we are writing to.
FILE* fp_{nullptr};
// The three internal compressed streams.
BZ2Compressor ctrl_stream_;
BZ2Compressor diff_stream_;
BZ2Compressor extra_stream_;
};
} // namespace bsdiff
#endif // _BSDIFF_PATCH_WRITER_H_