Skip to content

Commit

Permalink
Issue 313 - Use bsdiff library instead of managed implementation (#314)
Browse files Browse the repository at this point in the history
* Add pal_bsdiff / pal_bspatch.

* R#

* Refactor: corerun / libcorerun is no longer embedded inside Snap but assets are instead copied to runtimes/$Rid/native directory.

This means that snapx can now support native AOT compiled executables and we use bsdiff C library in CoreRunLib class.

* Use bsdiff library instead of our own implementation.

* Try fixing linking error on windows.

* Try fixing build error on windows.

* Move bsdiff code to Snap.Bsdiff in order to avoid increasing corerun executable binary size.

* Add missing cmake configuration.

* Windows build fix.

* Fix copying bsdiff library on Windows.

* Bugfix: Incorrect os platform.

* Bugfix: Collect bsdiff libary.

* Renaming in order to make the code easier to reason about.

* Bugfix: Create relative directory.

* Add support for reading patch from memory.

I fixed the bug in the bsdiff library in the following commit: fintermobilityas/bsdiff@6ba6b5d

* Enable nupkg workflow

But only publish nupkgs if branch is master.

* Fix clang-tidy warnings.

* Fix nupkg.
  • Loading branch information
peters authored Apr 12, 2023
1 parent 5757d89 commit c871f29
Show file tree
Hide file tree
Showing 46 changed files with 1,383 additions and 2,125 deletions.
13 changes: 11 additions & 2 deletions .github/workflows/dotnetcore.yml
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ jobs:
SNAPX_UNIX_CORERUN_REL_DIR: build/native/Unix/${{ matrix.rid }}/${{ matrix.configuration }}/Snap.CoreRun
SNAPX_UNIX_CORERUN_TESTS_REL_DIR: build/native/Unix/${{ matrix.rid }}/${{ matrix.configuration }}/Snap.CoreRun.Tests
SNAPX_UNIX_PAL_REL_DIR: build/native/Unix/${{ matrix.rid }}/${{ matrix.configuration }}/Snap.CoreRun.Pal
SNAPX_UNIX_BSDIFF_REL_DIR: build/native/Unix/${{ matrix.rid }}/${{ matrix.configuration }}/Snap.Bsdiff
run: |
mkdir -p ${{ github.workspace }}/artifacts/${{ env.SNAPX_UNIX_SETUP_ZIP_REL_DIR }}
cp ${{ github.workspace }}/${{ env.SNAPX_UNIX_SETUP_ZIP_REL_DIR }}/Setup-${{ matrix.rid }}.zip ${{ github.workspace }}/artifacts/${{ env.SNAPX_UNIX_SETUP_ZIP_REL_DIR }}/Setup-${{ matrix.rid }}.zip
Expand All @@ -117,6 +118,9 @@ jobs:
mkdir -p ${{ github.workspace }}/artifacts/${{ env.SNAPX_UNIX_PAL_REL_DIR }}
cp ${{ github.workspace }}/${{ env.SNAPX_UNIX_PAL_REL_DIR }}/libpal.so ${{ github.workspace }}/artifacts/${{ env.SNAPX_UNIX_PAL_REL_DIR }}/libpal.so
mkdir -p ${{ github.workspace }}/artifacts/${{ env.SNAPX_UNIX_BSDIFF_REL_DIR }}
cp ${{ github.workspace }}/${{ env.SNAPX_UNIX_BSDIFF_REL_DIR }}/libsnap_bsdiff.so ${{ github.workspace }}/artifacts/${{ env.SNAPX_UNIX_BSDIFF_REL_DIR }}/libsnap_bsdiff.so
- name: Upload artifacts
if: success()
uses: actions/upload-artifact@v3
Expand Down Expand Up @@ -166,6 +170,7 @@ jobs:
SNAPX_WINDOWS_SETUP_ZIP_REL_DIR: build/dotnet/${{ matrix.rid }}/Snap.Installer/${{ env.SNAPX_DOTNET_FRAMEWORK_VERSION }}/${{ matrix.configuration }}/publish
SNAPX_WINDOWS_CORERUN_REL_DIR: build/native/Windows/${{ matrix.rid }}/${{ matrix.configuration }}/Snap.CoreRun/${{ matrix.configuration }}
SNAPX_WINDOWS_PAL_REL_DIR: build/native/Windows/${{ matrix.rid }}/${{ matrix.configuration }}/Snap.CoreRun.Pal/${{ matrix.configuration }}
SNAPX_WINDOWS_BSDIFF_REL_DIR: build/native/Windows/${{ matrix.rid }}/${{ matrix.configuration }}/Snap.Bsdiff/${{ matrix.configuration }}
run: |
mkdir -p ${{ github.workspace }}/artifacts/${{ env.SNAPX_WINDOWS_SETUP_ZIP_REL_DIR }}
cp ${{ github.workspace }}/${{ env.SNAPX_WINDOWS_SETUP_ZIP_REL_DIR }}/Setup-${{ matrix.rid }}.zip ${{ github.workspace }}/artifacts/${{ env.SNAPX_WINDOWS_SETUP_ZIP_REL_DIR }}/Setup-${{ matrix.rid }}.zip
Expand All @@ -176,6 +181,9 @@ jobs:
mkdir -p ${{ github.workspace }}/artifacts/${{ env.SNAPX_WINDOWS_PAL_REL_DIR }}
cp ${{ github.workspace }}/${{ env.SNAPX_WINDOWS_PAL_REL_DIR }}/pal.dll ${{ github.workspace }}/artifacts/${{ env.SNAPX_WINDOWS_PAL_REL_DIR }}/pal.dll
mkdir -p ${{ github.workspace }}/artifacts/${{ env.SNAPX_WINDOWS_BSDIFF_REL_DIR }}
cp ${{ github.workspace }}/${{ env.SNAPX_WINDOWS_BSDIFF_REL_DIR }}/snap_bsdiff.dll ${{ github.workspace }}/artifacts/${{ env.SNAPX_WINDOWS_BSDIFF_REL_DIR }}/snap_bsdiff.dll
- name: Upload artifacts
if: success()
uses: actions/upload-artifact@v3
Expand Down Expand Up @@ -229,9 +237,9 @@ jobs:
# run: ./build.ps1 Run-Dotnet-UnitTests -Version ${{ env.SNAPX_VERSION }} -Configuration ${{ matrix.configuration }} -CIBuild -NetCoreAppVersion ${{ env.SNAPX_DOTNET_FRAMEWORK_VERSION }} -Rid ${{ matrix.rid }}

publish:
if: success() && (github.ref == 'refs/heads/develop' || github.ref == 'refs/heads/master')
if: success()
runs-on: ubuntu-latest
name: Publish
name: Nupkg
needs: [setup, windows, linux] # todo: enable me when github actions supports arm64: test-linux-arm64
env:
SNAPX_VERSION: ${{ needs.setup.outputs.SNAPX_VERSION }}
Expand Down Expand Up @@ -282,6 +290,7 @@ jobs:
run: ./build.ps1 -Target Snapx -CIBuild -Version ${{ env.SNAPX_VERSION }} -Configuration Release

- name: Push nuget packages
if: github.ref == 'refs/heads/develop' || github.ref == 'refs/heads/master'
shell: pwsh
run: |
$nupkgs = Get-ChildItem ".\${{ env.GITHUB_WORKSPACE }}\nupkgs" -Filter *.nupkg | Select-Object -ExpandProperty FullName
Expand Down
7 changes: 7 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,16 @@ set(MSVS_CXX_WARNING_FLAGS "/W4")
option(BUILD_ENABLE_LTO "Build with LINK TIME OPTIMIZATION enabled" OFF)
option(BUILD_ENABLE_TESTS "Build with tests enabled" OFF)
option(BUILD_ENABLE_LOGGING "Build with logging enabled" ON)
option(BUILD_ENABLE_BSDIFF "Build with bsdiff support enabled" ON)

add_subdirectory(Snap.CoreRun.Pal)
add_subdirectory(Snap.CoreRun)

if(BUILD_ENABLE_BSDIFF)
add_subdirectory(Vendor/bsdiff)
add_subdirectory(Snap.Bsdiff)
endif()

if (BUILD_ENABLE_TESTS)

message(STATUS "Unit tests enabled.")
Expand Down Expand Up @@ -79,6 +85,7 @@ string(STRIP "${SNAP_COMPILER_STR}" SNAP_COMPILER_STR)
message(STATUS "")
message(STATUS " Options:")
message(STATUS " Lto: " ${BUILD_ENABLE_LTO})
message(STATUS " Bsdiff: " ${BUILD_ENABLE_BSDIFF})
message(STATUS " Tests: " ${BUILD_ENABLE_TESTS})
message(STATUS " Toolchain file: " ${CMAKE_TOOLCHAIN_FILE})

Expand Down
34 changes: 34 additions & 0 deletions src/Snap.Bsdiff/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
cmake_minimum_required (VERSION 3.10 FATAL_ERROR)

project(snap_bsdiff CXX)

set(snap_bsdiff_SOURCES
src/lib.cpp
)

set(snap_bsdiff_INCLUDE_DIRS PRIVATE
../Vendor/bsdiff/include
src/include)


set(snap_bsdiff_static_LIBS )

if(WIN32)
list(APPEND snap_bsdiff_DEFINES SNAP_PLATFORM_WINDOWS)
elseif(UNIX)
list(APPEND snap_bsdiff_DEFINES SNAP_PLATFORM_LINUX)
list(APPEND snap_bsdiff_static_LIBS libstdc++.a)
else()
message(FATAL_ERROR "Error: Unsupported platform")
endif()

add_library(snap_bsdiff SHARED ${snap_bsdiff_SOURCES})

target_link_libraries(snap_bsdiff PUBLIC bsdiff ${snap_bsdiff_static_LIBS})
target_include_directories(snap_bsdiff PUBLIC ${snap_bsdiff_INCLUDE_DIRS})
target_compile_definitions(snap_bsdiff PRIVATE ${snap_bsdiff_DEFINES})

set_property(TARGET snap_bsdiff PROPERTY CXX_STANDARD 17)
set_property(TARGET snap_bsdiff PROPERTY CXX_STANDARD_REQUIRED ON)
set_property(TARGET snap_bsdiff PROPERTY POSITION_INDEPENDENT_CODE ON)

62 changes: 62 additions & 0 deletions src/Snap.Bsdiff/src/include/bsdiff/lib.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#pragma once

#include <bsdiff.h>
#include <cstdint>

#ifdef SNAP_PLATFORM_WINDOWS
#define SNAP_API __declspec( dllexport )
#define SNAP_CALLING_CONVENTION __cdecl
#elif SNAP_PLATFORM_LINUX
#if defined(__GNUC__)
#define SNAP_API __attribute__((visibility("default")))
#define SNAP_CALLING_CONVENTION
#endif
#endif

#ifdef __cplusplus
extern "C" {
#endif

typedef void (*snap_bsdiff_error_logger_t)(void *opaque, const char *errmsg);

typedef enum _snap_bsdiff_status_type {
bsdiff_status_type_success = 0,
bsdiff_status_type_error = 1,
bsdiff_status_type_invalid_arg = 2,
bsdiff_status_type_out_of_memory = 3,
bsdiff_status_type_file_error = 4,
bsdiff_status_type_end_of_file = 5,
bsdiff_status_type_corrupt_patch = 6,
bsdiff_status_type_size_too_large = 7
} snap_bsdiff_status_type;

typedef struct _snap_bsdiff_patch_ctx {
snap_bsdiff_error_logger_t error_logger;
const void *older;
size_t older_size;
uint8_t **newer;
size_t newer_size;
const void *patch;
const size_t patch_size;
snap_bsdiff_status_type status;
} snap_bsdiff_patch_ctx;

typedef struct _snap_bsdiff_diff_ctx {
snap_bsdiff_error_logger_t error_logger;
const void *older;
size_t older_size;
const void *newer;
size_t newer_size;
uint8_t **patch;
size_t patch_size;
snap_bsdiff_status_type status;
} snap_bsdiff_diff_ctx;

SNAP_API int32_t SNAP_CALLING_CONVENTION snap_bsdiff_patch(snap_bsdiff_patch_ctx *p_ctx);
SNAP_API int32_t SNAP_CALLING_CONVENTION snap_bsdiff_patch_free(snap_bsdiff_patch_ctx* p_ctx);
SNAP_API int32_t SNAP_CALLING_CONVENTION snap_bsdiff_diff(snap_bsdiff_diff_ctx* p_ctx);
SNAP_API int32_t SNAP_CALLING_CONVENTION snap_bsdiff_diff_free(snap_bsdiff_diff_ctx* p_ctx);

#ifdef __cplusplus
}
#endif
146 changes: 146 additions & 0 deletions src/Snap.Bsdiff/src/lib.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
#include "bsdiff/lib.hpp"
#include <cstring>

SNAP_API int32_t SNAP_CALLING_CONVENTION snap_bsdiff_patch(snap_bsdiff_patch_ctx* p_ctx) {
if(p_ctx == nullptr ||
p_ctx->older == nullptr ||
p_ctx->older_size <= 0 ||
p_ctx->newer != nullptr ||
p_ctx->newer_size != 0 ||
p_ctx->patch == nullptr ||
p_ctx->patch_size <= 0) {
return 0;
}

int ret;
struct bsdiff_stream oldfile = { nullptr }, newfile = { nullptr }, patchfile = { nullptr };
struct bsdiff_ctx ctx = { nullptr };
struct bsdiff_patch_packer packer = { nullptr };

if ((ret = bsdiff_open_memory_stream(BSDIFF_MODE_READ, p_ctx->older, p_ctx->older_size, &oldfile)) != BSDIFF_SUCCESS) {
goto cleanup;
}

if ((ret = bsdiff_open_memory_stream(BSDIFF_MODE_WRITE, nullptr, 0, &newfile)) != BSDIFF_SUCCESS) {
goto cleanup;
}

if ((ret = bsdiff_open_memory_stream(BSDIFF_MODE_READ, p_ctx->patch, p_ctx->patch_size, &patchfile)) != BSDIFF_SUCCESS) {
goto cleanup;
}

if ((ret = bsdiff_open_bz2_patch_packer(BSDIFF_MODE_READ, &patchfile, &packer)) != BSDIFF_SUCCESS) {
goto cleanup;
}

ctx.log_error = p_ctx->error_logger;

if ((ret = bspatch(&ctx, &oldfile, &newfile, &packer)) != BSDIFF_SUCCESS) {
goto cleanup;
}

cleanup:
p_ctx->status = static_cast<snap_bsdiff_status_type>(ret);

if(p_ctx->status == bsdiff_status_type_success) {
const void* newer_buffer = nullptr;
size_t newer_buffer_len = 0;
newfile.get_buffer(newfile.state, &newer_buffer, &newer_buffer_len);

p_ctx->newer_size = static_cast<int64_t>(newer_buffer_len);
p_ctx->newer = new uint8_t*[newer_buffer_len];
std::memcpy(p_ctx->newer, newer_buffer, newer_buffer_len);
}

bsdiff_close_patch_packer(&packer);
bsdiff_close_stream(&patchfile);
bsdiff_close_stream(&newfile);
bsdiff_close_stream(&oldfile);

return p_ctx->status == bsdiff_status_type_success ? 1 : 0;
}

SNAP_API int32_t SNAP_CALLING_CONVENTION snap_bsdiff_patch_free(snap_bsdiff_patch_ctx* p_ctx) {
if(p_ctx == nullptr) {
return 0;
}

if(p_ctx->newer != nullptr) {
delete[] p_ctx->newer;
p_ctx->newer = nullptr;
p_ctx->newer_size = 0;
}

return 1;
}

SNAP_API int32_t SNAP_CALLING_CONVENTION snap_bsdiff_diff(snap_bsdiff_diff_ctx* p_ctx) {
if(p_ctx == nullptr ||
p_ctx->older == nullptr ||
p_ctx->older_size <= 0 ||
p_ctx->newer == nullptr ||
p_ctx->newer_size <= 0) {
return 0;
}

int ret;
struct bsdiff_stream oldfile = { nullptr }, newfile = { nullptr }, patchfile = { nullptr };
struct bsdiff_ctx ctx = { nullptr };
struct bsdiff_patch_packer packer = { nullptr };

if ((ret = bsdiff_open_memory_stream(BSDIFF_MODE_READ, p_ctx->older, p_ctx->older_size, &oldfile)) != BSDIFF_SUCCESS) {
goto cleanup;
}

if ((ret = bsdiff_open_memory_stream(BSDIFF_MODE_READ, p_ctx->newer, p_ctx->newer_size, &newfile)) != BSDIFF_SUCCESS) {
goto cleanup;
}

if ((ret = bsdiff_open_memory_stream(BSDIFF_MODE_WRITE, nullptr, 0, &patchfile)) != BSDIFF_SUCCESS) {
goto cleanup;
}

if ((ret = bsdiff_open_bz2_patch_packer(BSDIFF_MODE_WRITE, &patchfile, &packer)) != BSDIFF_SUCCESS) {
goto cleanup;
}

ctx.log_error = p_ctx->error_logger;

if ((ret = bsdiff(&ctx, &oldfile, &newfile, &packer)) != BSDIFF_SUCCESS) {
goto cleanup;
}

cleanup:
p_ctx->status = static_cast<snap_bsdiff_status_type>(ret);

if(p_ctx->status == bsdiff_status_type_success) {
const void* patch_buffer = nullptr;
size_t patch_buffer_len = 0;
patchfile.get_buffer(patchfile.state, &patch_buffer, &patch_buffer_len);

p_ctx->patch_size = static_cast<int64_t>(patch_buffer_len);
p_ctx->patch = new uint8_t*[patch_buffer_len];
std::memcpy(p_ctx->patch, patch_buffer, patch_buffer_len);
}

bsdiff_close_patch_packer(&packer);
bsdiff_close_stream(&patchfile);
bsdiff_close_stream(&newfile);
bsdiff_close_stream(&oldfile);

return p_ctx->status == bsdiff_status_type_success ? 1 : 0;
}

SNAP_API int32_t SNAP_CALLING_CONVENTION snap_bsdiff_diff_free(snap_bsdiff_diff_ctx* p_ctx) {
if(p_ctx == nullptr) {
return 0;
}

if(p_ctx->patch != nullptr) {
delete[] p_ctx->patch;
p_ctx->patch = nullptr;
p_ctx->patch_size = 0;
}

return 1;
}
3 changes: 2 additions & 1 deletion src/Snap.CoreRun.Pal/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ if(WIN32)
)
endif()

add_library(pal_static
add_library(pal_static STATIC
${pal_SOURCES}
)

Expand Down Expand Up @@ -94,6 +94,7 @@ foreach(cmake_target IN ITEMS pal pal_static)
target_link_libraries(${cmake_target} PUBLIC ${pal_LIBS})
set_property(TARGET ${cmake_target} PROPERTY CXX_STANDARD 17)
set_property(TARGET ${cmake_target} PROPERTY CXX_STANDARD_REQUIRED ON)
set_property(TARGET ${cmake_target} PROPERTY POSITION_INDEPENDENT_CODE ON)
endforeach(cmake_target)

target_link_libraries(pal_static PUBLIC ${pal_static_LIBS})
2 changes: 1 addition & 1 deletion src/Snap.CoreRun/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ target_link_libraries(corerun PUBLIC pal_static)
if(WIN32)

if (CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /subsystem:windows")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /ENTRY:wWinMainCRTStartup /subsystem:windows")
set(CMAKE_CREATE_CONSOLE_EXE "/subsystem:windows") # Override subsystem on Windows.
elseif (CMAKE_COMPILER_IS_GNUCXX)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -mwindows -municode -Wl,-subsystem,windows")
Expand Down
Loading

0 comments on commit c871f29

Please sign in to comment.