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