1 /* 2 * Copyright (c) 2016 Maxim Sobolev <sobomax@FreeBSD.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 */ 27 28 #include <sys/cdefs.h> 29 __FBSDID("$FreeBSD$"); 30 31 #include <sys/types.h> 32 #include <err.h> 33 #include <md5.h> 34 #include <stdio.h> 35 #include <stdlib.h> 36 #include <string.h> 37 #include <unistd.h> 38 39 #if defined(MKUZ_DEBUG) 40 # include <stdio.h> 41 #endif 42 43 #include "mkuz_blockcache.h" 44 45 struct mkuz_blkcache { 46 struct mkuz_blkcache_hit hit; 47 off_t data_offset; 48 unsigned char digest[16]; 49 struct mkuz_blkcache *next; 50 }; 51 52 static struct mkuz_blkcache blkcache; 53 54 static int 55 verify_match(int fd, off_t data_offset, void *data, ssize_t len, 56 struct mkuz_blkcache *bcep) 57 { 58 void *vbuf; 59 ssize_t rlen; 60 int rval; 61 62 rval = -1; 63 vbuf = malloc(len); 64 if (vbuf == NULL) { 65 goto e0; 66 } 67 if (lseek(fd, bcep->data_offset, SEEK_SET) < 0) { 68 goto e1; 69 } 70 rlen = read(fd, vbuf, len); 71 if (rlen != len) { 72 goto e2; 73 } 74 rval = (memcmp(data, vbuf, len) == 0) ? 1 : 0; 75 e2: 76 lseek(fd, data_offset, SEEK_SET); 77 e1: 78 free(vbuf); 79 e0: 80 return (rval); 81 } 82 83 struct mkuz_blkcache_hit * 84 mkuz_blkcache_regblock(int fd, uint32_t blkno, off_t offset, ssize_t len, 85 void *data) 86 { 87 struct mkuz_blkcache *bcep; 88 MD5_CTX mcontext; 89 off_t data_offset; 90 unsigned char mdigest[16]; 91 int rval; 92 93 data_offset = lseek(fd, 0, SEEK_CUR); 94 if (data_offset < 0) { 95 return (NULL); 96 } 97 MD5Init(&mcontext); 98 MD5Update(&mcontext, data, len); 99 MD5Final(mdigest, &mcontext); 100 if (blkcache.hit.len == 0) { 101 bcep = &blkcache; 102 } else { 103 for (bcep = &blkcache; bcep != NULL; bcep = bcep->next) { 104 if (bcep->hit.len != len) 105 continue; 106 if (memcmp(mdigest, bcep->digest, sizeof(mdigest)) == 0) { 107 break; 108 } 109 } 110 if (bcep != NULL) { 111 rval = verify_match(fd, data_offset, data, len, bcep); 112 if (rval == 1) { 113 #if defined(MKUZ_DEBUG) 114 fprintf(stderr, "cache hit %d, %d, %d\n", 115 (int)bcep->hit.offset, (int)data_offset, (int)len); 116 #endif 117 return (&bcep->hit); 118 } 119 if (rval == 0) { 120 #if defined(MKUZ_DEBUG) 121 fprintf(stderr, "block MD5 collision, you should try lottery, " 122 "man!\n"); 123 #endif 124 return (NULL); 125 } 126 warn("verify_match"); 127 return (NULL); 128 } 129 bcep = malloc(sizeof(struct mkuz_blkcache)); 130 if (bcep == NULL) 131 return (NULL); 132 memset(bcep, '\0', sizeof(struct mkuz_blkcache)); 133 bcep->next = blkcache.next; 134 blkcache.next = bcep; 135 } 136 memcpy(bcep->digest, mdigest, sizeof(mdigest)); 137 bcep->data_offset = data_offset; 138 bcep->hit.offset = offset; 139 bcep->hit.len = len; 140 bcep->hit.blkno = blkno; 141 return (NULL); 142 } 143