Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
branch: master
Fetching contributors…

Octocat-spinner-32-eaf2f5

Cannot retrieve contributors at this time

file 102 lines (86 sloc) 3.768 kb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
//
// SUBinaryDeltaApply.m
// Sparkle
//
// Created by Mark Rowe on 2009-06-01.
// Copyright 2009 Mark Rowe. All rights reserved.
//

#import "SUBinaryDeltaApply.h"
#import "SUBinaryDeltaCommon.h"
#import <CommonCrypto/CommonDigest.h>
#import <Foundation/Foundation.h>
#import <bspatch.h>
#import <stdio.h>
#import <stdlib.h>
#import <xar/xar.h>

static void applyBinaryDeltaToFile(xar_t x, xar_file_t file, NSString *sourceFilePath, NSString *destinationFilePath)
{
    NSString *patchFile = temporaryFilename(@"apply-binary-delta");
    xar_extract_tofile(x, file, [patchFile fileSystemRepresentation]);
    const char *argv[] = {"/usr/bin/bspatch", [sourceFilePath fileSystemRepresentation], [destinationFilePath fileSystemRepresentation], [patchFile fileSystemRepresentation]};
    bspatch(4, (char **)argv);
    unlink([patchFile fileSystemRepresentation]);
}

int applyBinaryDelta(NSString *source, NSString *destination, NSString *patchFile)
{
    xar_t x = xar_open([patchFile UTF8String], READ);
    if (!x) {
        fprintf(stderr, "Unable to open %s. Giving up.\n", [patchFile UTF8String]);
        return 1;
    }

    NSString *expectedBeforeHash = nil;
    NSString *expectedAfterHash = nil;
    xar_subdoc_t subdoc;
    for (subdoc = xar_subdoc_first(x); subdoc; subdoc = xar_subdoc_next(subdoc)) {
        if (!strcmp(xar_subdoc_name(subdoc), "binary-delta-attributes")) {
            const char *value = 0;
            xar_subdoc_prop_get(subdoc, "before-sha1", &value);
            if (value)
                expectedBeforeHash = [NSString stringWithUTF8String:value];

            xar_subdoc_prop_get(subdoc, "after-sha1", &value);
            if (value)
                expectedAfterHash = [NSString stringWithUTF8String:value];
        }
    }

    if (!expectedBeforeHash || !expectedAfterHash) {
        fprintf(stderr, "Unable to find before-sha1 or after-sha1 metadata in delta. Giving up.\n");
        return 1;
    }

    fprintf(stderr, "Verifying source... ");
    NSString *beforeHash = hashOfTree(source);

    if (![beforeHash isEqualToString:expectedBeforeHash]) {
        fprintf(stderr, "Source doesn't have expected hash (%s != %s). Giving up.\n", [expectedBeforeHash UTF8String], [beforeHash UTF8String]);
        return 1;
    }

    fprintf(stderr, "\nCopying files... ");
    removeTree(destination);
    copyTree(source, destination);

    fprintf(stderr, "\nPatching... ");
    xar_file_t file;
    xar_iter_t iter = xar_iter_new();
    for (file = xar_file_first(x, iter); file; file = xar_file_next(iter)) {
        NSString *path = [NSString stringWithUTF8String:xar_get_path(file)];
        NSString *sourceFilePath = [source stringByAppendingPathComponent:path];
        NSString *destinationFilePath = [destination stringByAppendingPathComponent:path];

        const char *value;
        if (!xar_prop_get(file, "delete", &value) || !xar_prop_get(file, "delete-then-extract", &value)) {
            removeTree(destinationFilePath);
            if (!xar_prop_get(file, "delete", &value))
                continue;
        }

        if (!xar_prop_get(file, "binary-delta", &value))
            applyBinaryDeltaToFile(x, file, sourceFilePath, destinationFilePath);
        else
            xar_extract_tofile(x, file, [destinationFilePath fileSystemRepresentation]);
    }
    xar_close(x);

    fprintf(stderr, "\nVerifying destination... ");
    NSString *afterHash = hashOfTree(destination);

    if (![afterHash isEqualToString:expectedAfterHash]) {
        fprintf(stderr, "Destination doesn't have expected hash (%s != %s). Giving up.\n", [expectedAfterHash UTF8String], [afterHash UTF8String]);
        removeTree(destination);
        return 1;
    }

    fprintf(stderr, "\nDone!\n");
    return 0;
}
Something went wrong with that request. Please try again.