/*- * 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 */ #include "bspatch.h" #include "updatererrors.h" #include #include #include #include #include #include #if defined(XP_WIN) # include #else # include #endif #ifdef XP_WIN # include #else # include #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(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(fbufend - fbuffer) || ctrlsrc->x > static_cast(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(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; }