xref: /freebsd/usr.bin/mkuzip/mkuz_blockcache.c (revision 4fc55e3e46222743c4d7af07d911b55538899657)
18f8cb840SMaxim Sobolev /*
28f8cb840SMaxim Sobolev  * Copyright (c) 2016 Maxim Sobolev <sobomax@FreeBSD.org>
38f8cb840SMaxim Sobolev  * All rights reserved.
48f8cb840SMaxim Sobolev  *
58f8cb840SMaxim Sobolev  * Redistribution and use in source and binary forms, with or without
68f8cb840SMaxim Sobolev  * modification, are permitted provided that the following conditions
78f8cb840SMaxim Sobolev  * are met:
88f8cb840SMaxim Sobolev  * 1. Redistributions of source code must retain the above copyright
98f8cb840SMaxim Sobolev  *    notice, this list of conditions and the following disclaimer.
108f8cb840SMaxim Sobolev  * 2. Redistributions in binary form must reproduce the above copyright
118f8cb840SMaxim Sobolev  *    notice, this list of conditions and the following disclaimer in the
128f8cb840SMaxim Sobolev  *    documentation and/or other materials provided with the distribution.
138f8cb840SMaxim Sobolev  *
148f8cb840SMaxim Sobolev  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
158f8cb840SMaxim Sobolev  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
168f8cb840SMaxim Sobolev  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
178f8cb840SMaxim Sobolev  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
188f8cb840SMaxim Sobolev  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
198f8cb840SMaxim Sobolev  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
208f8cb840SMaxim Sobolev  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
218f8cb840SMaxim Sobolev  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
228f8cb840SMaxim Sobolev  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
238f8cb840SMaxim Sobolev  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
248f8cb840SMaxim Sobolev  * SUCH DAMAGE.
258f8cb840SMaxim Sobolev  */
268f8cb840SMaxim Sobolev 
278f8cb840SMaxim Sobolev #include <sys/cdefs.h>
288f8cb840SMaxim Sobolev __FBSDID("$FreeBSD$");
298f8cb840SMaxim Sobolev 
306e5a582dSMaxim Sobolev #include <err.h>
316e5a582dSMaxim Sobolev #include <stdio.h>
328f8cb840SMaxim Sobolev #include <stdlib.h>
338f8cb840SMaxim Sobolev #include <string.h>
348f8cb840SMaxim Sobolev #include <unistd.h>
358f8cb840SMaxim Sobolev 
368f8cb840SMaxim Sobolev #if defined(MKUZ_DEBUG)
37*4fc55e3eSMaxim Sobolev # include <assert.h>
388f8cb840SMaxim Sobolev # include <stdio.h>
398f8cb840SMaxim Sobolev #endif
408f8cb840SMaxim Sobolev 
418f8cb840SMaxim Sobolev #include "mkuz_blockcache.h"
42*4fc55e3eSMaxim Sobolev #include "mkuz_blk.h"
438f8cb840SMaxim Sobolev 
44*4fc55e3eSMaxim Sobolev struct mkuz_blkcache_itm {
45*4fc55e3eSMaxim Sobolev     struct mkuz_blk_info hit;
46*4fc55e3eSMaxim Sobolev     struct mkuz_blkcache_itm *next;
478f8cb840SMaxim Sobolev };
488f8cb840SMaxim Sobolev 
49*4fc55e3eSMaxim Sobolev static struct mkuz_blkcache {
50*4fc55e3eSMaxim Sobolev     struct mkuz_blkcache_itm first[256];
51*4fc55e3eSMaxim Sobolev } blkcache;
528f8cb840SMaxim Sobolev 
536e5a582dSMaxim Sobolev static int
54*4fc55e3eSMaxim Sobolev verify_match(int fd, const struct mkuz_blk *cbp, struct mkuz_blkcache_itm *bcep)
556e5a582dSMaxim Sobolev {
566e5a582dSMaxim Sobolev     void *vbuf;
576e5a582dSMaxim Sobolev     ssize_t rlen;
586e5a582dSMaxim Sobolev     int rval;
596e5a582dSMaxim Sobolev 
606e5a582dSMaxim Sobolev     rval = -1;
61*4fc55e3eSMaxim Sobolev     vbuf = malloc(cbp->info.len);
626e5a582dSMaxim Sobolev     if (vbuf == NULL) {
636e5a582dSMaxim Sobolev         goto e0;
646e5a582dSMaxim Sobolev     }
65*4fc55e3eSMaxim Sobolev     if (lseek(fd, bcep->hit.offset, SEEK_SET) < 0) {
666e5a582dSMaxim Sobolev         goto e1;
676e5a582dSMaxim Sobolev     }
68*4fc55e3eSMaxim Sobolev     rlen = read(fd, vbuf, cbp->info.len);
69*4fc55e3eSMaxim Sobolev     if (rlen < 0 || (unsigned)rlen != cbp->info.len) {
706e5a582dSMaxim Sobolev         goto e2;
716e5a582dSMaxim Sobolev     }
72*4fc55e3eSMaxim Sobolev     rval = (memcmp(cbp->data, vbuf, cbp->info.len) == 0) ? 1 : 0;
736e5a582dSMaxim Sobolev e2:
74*4fc55e3eSMaxim Sobolev     lseek(fd, cbp->info.offset, SEEK_SET);
756e5a582dSMaxim Sobolev e1:
766e5a582dSMaxim Sobolev     free(vbuf);
776e5a582dSMaxim Sobolev e0:
786e5a582dSMaxim Sobolev     return (rval);
796e5a582dSMaxim Sobolev }
806e5a582dSMaxim Sobolev 
81*4fc55e3eSMaxim Sobolev #define I2J(x)	((intmax_t)(x))
82*4fc55e3eSMaxim Sobolev #define U2J(x)	((uintmax_t)(x))
838f8cb840SMaxim Sobolev 
84*4fc55e3eSMaxim Sobolev static unsigned char
85*4fc55e3eSMaxim Sobolev digest_fold(const unsigned char *mdigest)
86*4fc55e3eSMaxim Sobolev {
87*4fc55e3eSMaxim Sobolev     int i;
88*4fc55e3eSMaxim Sobolev     unsigned char rval;
89*4fc55e3eSMaxim Sobolev 
90*4fc55e3eSMaxim Sobolev     rval = mdigest[0];
91*4fc55e3eSMaxim Sobolev     for (i = 1; i < 16; i++) {
92*4fc55e3eSMaxim Sobolev         rval = rval ^ mdigest[i];
938f8cb840SMaxim Sobolev     }
94*4fc55e3eSMaxim Sobolev     return (rval);
95*4fc55e3eSMaxim Sobolev }
96*4fc55e3eSMaxim Sobolev 
97*4fc55e3eSMaxim Sobolev struct mkuz_blk_info *
98*4fc55e3eSMaxim Sobolev mkuz_blkcache_regblock(int fd, const struct mkuz_blk *bp)
99*4fc55e3eSMaxim Sobolev {
100*4fc55e3eSMaxim Sobolev     struct mkuz_blkcache_itm *bcep;
101*4fc55e3eSMaxim Sobolev     int rval;
102*4fc55e3eSMaxim Sobolev     unsigned char h;
103*4fc55e3eSMaxim Sobolev 
104*4fc55e3eSMaxim Sobolev #if defined(MKUZ_DEBUG)
105*4fc55e3eSMaxim Sobolev     assert((unsigned)lseek(fd, 0, SEEK_CUR) == bp->info.offset);
106*4fc55e3eSMaxim Sobolev #endif
107*4fc55e3eSMaxim Sobolev     h = digest_fold(bp->info.digest);
108*4fc55e3eSMaxim Sobolev     if (blkcache.first[h].hit.len == 0) {
109*4fc55e3eSMaxim Sobolev         bcep = &blkcache.first[h];
1108f8cb840SMaxim Sobolev     } else {
111*4fc55e3eSMaxim Sobolev         for (bcep = &blkcache.first[h]; bcep != NULL; bcep = bcep->next) {
112*4fc55e3eSMaxim Sobolev             if (bcep->hit.len != bp->info.len)
1138f8cb840SMaxim Sobolev                 continue;
114*4fc55e3eSMaxim Sobolev             if (memcmp(bp->info.digest, bcep->hit.digest,
115*4fc55e3eSMaxim Sobolev               sizeof(bp->info.digest)) == 0) {
1168f8cb840SMaxim Sobolev                 break;
1178f8cb840SMaxim Sobolev             }
1188f8cb840SMaxim Sobolev         }
1198f8cb840SMaxim Sobolev         if (bcep != NULL) {
120*4fc55e3eSMaxim Sobolev             rval = verify_match(fd, bp, bcep);
1216e5a582dSMaxim Sobolev             if (rval == 1) {
1228f8cb840SMaxim Sobolev #if defined(MKUZ_DEBUG)
123*4fc55e3eSMaxim Sobolev                 fprintf(stderr, "cache hit %jd, %jd, %jd, %jd\n",
124*4fc55e3eSMaxim Sobolev                   I2J(bcep->hit.blkno), I2J(bcep->hit.offset),
125*4fc55e3eSMaxim Sobolev                   I2J(bp->info.offset), I2J(bp->info.len));
1268f8cb840SMaxim Sobolev #endif
1278f8cb840SMaxim Sobolev                 return (&bcep->hit);
1288f8cb840SMaxim Sobolev             }
1296e5a582dSMaxim Sobolev             if (rval == 0) {
1306e5a582dSMaxim Sobolev #if defined(MKUZ_DEBUG)
1316e5a582dSMaxim Sobolev                 fprintf(stderr, "block MD5 collision, you should try lottery, "
1326e5a582dSMaxim Sobolev                   "man!\n");
1336e5a582dSMaxim Sobolev #endif
1346e5a582dSMaxim Sobolev                 return (NULL);
1356e5a582dSMaxim Sobolev             }
1366e5a582dSMaxim Sobolev             warn("verify_match");
1376e5a582dSMaxim Sobolev             return (NULL);
1386e5a582dSMaxim Sobolev         }
139*4fc55e3eSMaxim Sobolev         bcep = malloc(sizeof(struct mkuz_blkcache_itm));
1408f8cb840SMaxim Sobolev         if (bcep == NULL)
1418f8cb840SMaxim Sobolev             return (NULL);
142*4fc55e3eSMaxim Sobolev         memset(bcep, '\0', sizeof(struct mkuz_blkcache_itm));
143*4fc55e3eSMaxim Sobolev         bcep->next = blkcache.first[h].next;
144*4fc55e3eSMaxim Sobolev         blkcache.first[h].next = bcep;
1458f8cb840SMaxim Sobolev     }
146*4fc55e3eSMaxim Sobolev     bcep->hit = bp->info;
1478f8cb840SMaxim Sobolev     return (NULL);
1488f8cb840SMaxim Sobolev }
149