216 lines
5.8 KiB
C++
216 lines
5.8 KiB
C++
/*-
|
|
* Copyright 2003,2004 Colin Percival
|
|
* All rights reserved
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted providing that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
|
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
* Changelog:
|
|
* 2005-04-26 - Define the header as a C structure, add a CRC32 checksum to
|
|
* the header, and make all the types 32-bit.
|
|
* --Benjamin Smedberg <benjamin@smedbergs.us>
|
|
*/
|
|
|
|
#include "bspatch.h"
|
|
#include "updatererrors.h"
|
|
|
|
#include <sys/stat.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <limits.h>
|
|
|
|
#if defined(XP_WIN)
|
|
# include <io.h>
|
|
#endif
|
|
|
|
#ifdef XP_WIN
|
|
# include <winsock2.h>
|
|
#else
|
|
# include <arpa/inet.h>
|
|
#endif
|
|
|
|
#ifndef SSIZE_MAX
|
|
# define SSIZE_MAX LONG_MAX
|
|
#endif
|
|
|
|
int MBS_ReadHeader(FILE* file, MBSPatchHeader* header) {
|
|
size_t s = fread(header, 1, sizeof(MBSPatchHeader), file);
|
|
if (s != sizeof(MBSPatchHeader)) {
|
|
return READ_ERROR;
|
|
}
|
|
|
|
header->slen = ntohl(header->slen);
|
|
header->scrc32 = ntohl(header->scrc32);
|
|
header->dlen = ntohl(header->dlen);
|
|
header->cblen = ntohl(header->cblen);
|
|
header->difflen = ntohl(header->difflen);
|
|
header->extralen = ntohl(header->extralen);
|
|
|
|
struct stat hs;
|
|
s = fstat(fileno(file), &hs);
|
|
if (s != 0) {
|
|
return READ_ERROR;
|
|
}
|
|
|
|
if (memcmp(header->tag, "MBDIFF10", 8) != 0) {
|
|
return UNEXPECTED_BSPATCH_ERROR;
|
|
}
|
|
|
|
if (hs.st_size > INT_MAX) {
|
|
return UNEXPECTED_BSPATCH_ERROR;
|
|
}
|
|
|
|
size_t size = static_cast<size_t>(hs.st_size);
|
|
if (size < sizeof(MBSPatchHeader)) {
|
|
return UNEXPECTED_BSPATCH_ERROR;
|
|
}
|
|
size -= sizeof(MBSPatchHeader);
|
|
|
|
if (size < header->cblen) {
|
|
return UNEXPECTED_BSPATCH_ERROR;
|
|
}
|
|
size -= header->cblen;
|
|
|
|
if (size < header->difflen) {
|
|
return UNEXPECTED_BSPATCH_ERROR;
|
|
}
|
|
size -= header->difflen;
|
|
|
|
if (size < header->extralen) {
|
|
return UNEXPECTED_BSPATCH_ERROR;
|
|
}
|
|
size -= header->extralen;
|
|
|
|
if (size != 0) {
|
|
return UNEXPECTED_BSPATCH_ERROR;
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
int MBS_ApplyPatch(const MBSPatchHeader* header, FILE* patchFile,
|
|
unsigned char* fbuffer, FILE* file) {
|
|
unsigned char* fbufstart = fbuffer;
|
|
unsigned char* fbufend = fbuffer + header->slen;
|
|
|
|
unsigned char* buf = (unsigned char*)malloc(header->cblen + header->difflen +
|
|
header->extralen);
|
|
if (!buf) {
|
|
return BSPATCH_MEM_ERROR;
|
|
}
|
|
|
|
int rv = OK;
|
|
|
|
size_t r = header->cblen + header->difflen + header->extralen;
|
|
unsigned char* wb = buf;
|
|
while (r) {
|
|
const size_t count = (r > SSIZE_MAX) ? SSIZE_MAX : r;
|
|
size_t c = fread(wb, 1, count, patchFile);
|
|
if (c != count) {
|
|
rv = READ_ERROR;
|
|
goto end;
|
|
}
|
|
|
|
r -= c;
|
|
wb += c;
|
|
|
|
if (c == 0 && r) {
|
|
rv = UNEXPECTED_BSPATCH_ERROR;
|
|
goto end;
|
|
}
|
|
}
|
|
|
|
{
|
|
MBSPatchTriple* ctrlsrc = (MBSPatchTriple*)buf;
|
|
if (header->cblen % sizeof(MBSPatchTriple) != 0) {
|
|
rv = UNEXPECTED_BSPATCH_ERROR;
|
|
goto end;
|
|
}
|
|
|
|
unsigned char* diffsrc = buf + header->cblen;
|
|
unsigned char* extrasrc = diffsrc + header->difflen;
|
|
|
|
MBSPatchTriple* ctrlend = (MBSPatchTriple*)diffsrc;
|
|
unsigned char* diffend = extrasrc;
|
|
unsigned char* extraend = extrasrc + header->extralen;
|
|
|
|
while (ctrlsrc < ctrlend) {
|
|
ctrlsrc->x = ntohl(ctrlsrc->x);
|
|
ctrlsrc->y = ntohl(ctrlsrc->y);
|
|
ctrlsrc->z = ntohl(ctrlsrc->z);
|
|
|
|
#ifdef DEBUG_bsmedberg
|
|
printf(
|
|
"Applying block:\n"
|
|
" x: %u\n"
|
|
" y: %u\n"
|
|
" z: %i\n",
|
|
ctrlsrc->x, ctrlsrc->y, ctrlsrc->z);
|
|
#endif
|
|
|
|
/* Add x bytes from oldfile to x bytes from the diff block */
|
|
|
|
if (ctrlsrc->x > static_cast<size_t>(fbufend - fbuffer) ||
|
|
ctrlsrc->x > static_cast<size_t>(diffend - diffsrc)) {
|
|
rv = UNEXPECTED_BSPATCH_ERROR;
|
|
goto end;
|
|
}
|
|
for (uint32_t i = 0; i < ctrlsrc->x; ++i) {
|
|
diffsrc[i] += fbuffer[i];
|
|
}
|
|
if ((uint32_t)fwrite(diffsrc, 1, ctrlsrc->x, file) != ctrlsrc->x) {
|
|
rv = WRITE_ERROR_PATCH_FILE;
|
|
goto end;
|
|
}
|
|
fbuffer += ctrlsrc->x;
|
|
diffsrc += ctrlsrc->x;
|
|
|
|
/* Copy y bytes from the extra block */
|
|
|
|
if (ctrlsrc->y > static_cast<size_t>(extraend - extrasrc)) {
|
|
rv = UNEXPECTED_BSPATCH_ERROR;
|
|
goto end;
|
|
}
|
|
if ((uint32_t)fwrite(extrasrc, 1, ctrlsrc->y, file) != ctrlsrc->y) {
|
|
rv = WRITE_ERROR_PATCH_FILE;
|
|
goto end;
|
|
}
|
|
extrasrc += ctrlsrc->y;
|
|
|
|
/* "seek" forwards in oldfile by z bytes */
|
|
|
|
if (ctrlsrc->z < fbufstart - fbuffer || ctrlsrc->z > fbufend - fbuffer) {
|
|
rv = UNEXPECTED_BSPATCH_ERROR;
|
|
goto end;
|
|
}
|
|
fbuffer += ctrlsrc->z;
|
|
|
|
/* and on to the next control block */
|
|
|
|
++ctrlsrc;
|
|
}
|
|
}
|
|
|
|
end:
|
|
free(buf);
|
|
return rv;
|
|
}
|