blob: 74fbef3751c1e59130f14434932e03bea8682ab4 [file] [log] [blame]
// Copyright 2015 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 <err.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <limits>
#include "bsdiff/bsdiff.h"
#include "bsdiff/patch_writer_factory.h"
namespace {
// mmap() the passed |filename| to read-only memory and store in |filesize| the
// size of the file. To release the memory, call munmap with the returned
// pointer and filesize. In case of error returns nullptr.
void* MapFile(const char* filename, size_t* filesize) {
int fd = open(filename, O_RDONLY);
if (fd < 0) {
perror("open()");
return nullptr;
}
struct stat st;
fstat(fd, &st);
if (static_cast<uint64_t>(st.st_size) > std::numeric_limits<size_t>::max()) {
fprintf(stderr, "File too big\n");
close(fd);
return nullptr;
}
*filesize = st.st_size;
void* ret = mmap(nullptr, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
if (ret == MAP_FAILED) {
perror("mmap()");
close(fd);
return nullptr;
}
close(fd);
return ret;
}
// Generate bsdiff patch from the |old_filename| file to the |new_filename|
// file storing the resulting patch in a new |patch_filename| file.
int GenerateBsdiffFromFiles(const char* old_filename,
const char* new_filename,
const char* patch_filename) {
size_t oldsize, newsize;
int ret = 0;
uint8_t* old_buf = static_cast<uint8_t*>(MapFile(old_filename, &oldsize));
uint8_t* new_buf = static_cast<uint8_t*>(MapFile(new_filename, &newsize));
if (old_buf && new_buf) {
auto patch_writer = bsdiff::CreateBsdiffPatchWriter(patch_filename);
ret = bsdiff::bsdiff(old_buf, oldsize, new_buf, newsize, patch_writer.get(),
nullptr);
} else {
ret = 1;
}
if (old_buf)
munmap(old_buf, oldsize);
if (new_buf)
munmap(new_buf, newsize);
return ret;
}
} // namespace
int main(int argc, char* argv[]) {
if (argc != 4)
errx(1, "usage: %s oldfile newfile patchfile\n", argv[0]);
return GenerateBsdiffFromFiles(argv[1], argv[2], argv[3]);
}