This source file includes following definitions.
- MBS_ReadHeader
- MBS_ApplyPatch
- CalculateCrc
- ApplyBinaryPatch
#include "mbspatch.h"
#include <sys/stat.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <limits.h>
#ifdef _WIN32
# include <io.h>
# include <winsock2.h>
#else
# include <unistd.h>
# include <arpa/inet.h>
#endif
extern "C" {
#include <7zCrc.h>
}
#ifndef SSIZE_MAX
# define SSIZE_MAX LONG_MAX
#endif
int
MBS_ReadHeader(int fd, MBSPatchHeader *header)
{
int s = read(fd, header, sizeof(MBSPatchHeader));
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(fd, &hs);
if (s)
return READ_ERROR;
if (memcmp(header->tag, "MBDIFF10", 8) != 0)
return UNEXPECTED_ERROR;
if (sizeof(MBSPatchHeader) +
header->cblen +
header->difflen +
header->extralen != int(hs.st_size))
return UNEXPECTED_ERROR;
return OK;
}
int
MBS_ApplyPatch(const MBSPatchHeader *header, int patchfd,
unsigned char *fbuffer, int filefd)
{
unsigned char *fbufend = fbuffer + header->slen;
unsigned char *buf = (unsigned char*) malloc(header->cblen +
header->difflen +
header->extralen);
if (!buf)
return MEM_ERROR;
int rv = OK;
int r = header->cblen + header->difflen + header->extralen;
unsigned char *wb = buf;
while (r) {
int c = read(patchfd, wb, (r > SSIZE_MAX) ? SSIZE_MAX : r);
if (c < 0) {
rv = READ_ERROR;
goto end;
}
r -= c;
if (c == 0 && r) {
rv = UNEXPECTED_ERROR;
goto end;
}
}
{
MBSPatchTriple *ctrlsrc = (MBSPatchTriple*) buf;
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;
do {
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
if (fbuffer + ctrlsrc->x > fbufend ||
diffsrc + ctrlsrc->x > diffend) {
rv = UNEXPECTED_ERROR;
goto end;
}
for (unsigned int i = 0; i < ctrlsrc->x; ++i) {
diffsrc[i] += fbuffer[i];
}
if ((int) write(filefd, diffsrc, ctrlsrc->x) != ctrlsrc->x) {
rv = WRITE_ERROR;
goto end;
}
fbuffer += ctrlsrc->x;
diffsrc += ctrlsrc->x;
if (extrasrc + ctrlsrc->y > extraend) {
rv = UNEXPECTED_ERROR;
goto end;
}
if ((int) write(filefd, extrasrc, ctrlsrc->y) != ctrlsrc->y) {
rv = WRITE_ERROR;
goto end;
}
extrasrc += ctrlsrc->y;
if (fbuffer + ctrlsrc->z > fbufend) {
rv = UNEXPECTED_ERROR;
goto end;
}
fbuffer += ctrlsrc->z;
++ctrlsrc;
} while (ctrlsrc < ctrlend);
}
end:
free(buf);
return rv;
}
int CalculateCrc(const unsigned char *buf, int size) {
CrcGenerateTable();
unsigned int crc = 0xffffffffL;
crc = ~CrcCalc(buf, size);
return crc;
}
#ifndef _O_BINARY
# define _O_BINARY 0
#endif
int ApplyBinaryPatch(const wchar_t *old_file, const wchar_t *patch_file,
const wchar_t *new_file) {
int ret = OK;
int ofd = -1;
int nfd = -1;
unsigned char *buf = NULL;
int pfd = _wopen(patch_file, O_RDONLY | _O_BINARY);
if (pfd < 0) return READ_ERROR;
do {
MBSPatchHeader header;
if ((ret = MBS_ReadHeader(pfd, &header)))
break;
ofd = _wopen(old_file, O_RDONLY | _O_BINARY);
if (ofd < 0) {
ret = READ_ERROR;
break;
}
struct stat os;
if ((ret = fstat(ofd, &os))) {
ret = READ_ERROR;
break;
}
if (os.st_size != header.slen) {
ret = UNEXPECTED_ERROR;
break;
}
buf = (unsigned char*) malloc(header.slen);
if (!buf) {
ret = MEM_ERROR;
break;
}
if (read(ofd, buf, header.slen) != header.slen) {
ret = READ_ERROR;
break;
}
if (CalculateCrc(buf, header.slen) != header.scrc32) {
ret = CRC_ERROR;
break;
}
nfd = _wopen(new_file, O_WRONLY | O_TRUNC | O_CREAT | _O_BINARY);
if (nfd < 0) {
ret = READ_ERROR;
break;
}
MBS_ApplyPatch(&header, pfd, buf, nfd);
} while (0);
free(buf);
close(pfd);
if (ofd >= 0) close(ofd);
if (nfd >= 0) close(nfd);
return ret;
}