ibstorage.c - dedup - deduplicating backup program Err bitreich.org 70 hgit clone git://bitreich.org/dedup/ git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d7roiv6bfj7d652fid.onion/dedup/ URL:git://bitreich.org/dedup/ git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d7roiv6bfj7d652fid.onion/dedup/ bitreich.org 70 1Log /scm/dedup/log.gph bitreich.org 70 1Files /scm/dedup/files.gph bitreich.org 70 1Refs /scm/dedup/refs.gph bitreich.org 70 1Tags /scm/dedup/tag bitreich.org 70 1README /scm/dedup/file/README.gph bitreich.org 70 1LICENSE /scm/dedup/file/LICENSE.gph bitreich.org 70 i--- Err bitreich.org 70 ibstorage.c (13644B) Err bitreich.org 70 i--- Err bitreich.org 70 i 1 /* Err bitreich.org 70 i 2 * Storage layer implementation using a single backing file. Err bitreich.org 70 i 3 * The file format is as follows: Err bitreich.org 70 i 4 * Err bitreich.org 70 i 5 * [block header] Err bitreich.org 70 i 6 * [block descriptor 0] Err bitreich.org 70 i 7 * [data] Err bitreich.org 70 i 8 * [block descriptor 1] Err bitreich.org 70 i 9 * [data] Err bitreich.org 70 i 10 * ... Err bitreich.org 70 i 11 */ Err bitreich.org 70 i 12 #include Err bitreich.org 70 i 13 #include Err bitreich.org 70 i 14 Err bitreich.org 70 i 15 #include Err bitreich.org 70 i 16 #include Err bitreich.org 70 i 17 #include Err bitreich.org 70 i 18 #include Err bitreich.org 70 i 19 #include Err bitreich.org 70 i 20 #include Err bitreich.org 70 i 21 #include Err bitreich.org 70 i 22 #include Err bitreich.org 70 i 23 #include Err bitreich.org 70 i 24 Err bitreich.org 70 i 25 #include "block.h" Err bitreich.org 70 i 26 #include "compat.h" Err bitreich.org 70 i 27 #include "config.h" Err bitreich.org 70 i 28 #include "misc.h" Err bitreich.org 70 i 29 #include "queue.h" Err bitreich.org 70 i 30 #include "tree.h" Err bitreich.org 70 i 31 Err bitreich.org 70 i 32 /* block header constants */ Err bitreich.org 70 i 33 #define BHDRMAGIC "DEDUPDIDUPDIDUP" Err bitreich.org 70 i 34 #define NBHDRMAGIC 16 Err bitreich.org 70 i 35 Err bitreich.org 70 i 36 #define VMIN 0 Err bitreich.org 70 i 37 #define VMAJ 1 Err bitreich.org 70 i 38 #define VMINMASK 0xff Err bitreich.org 70 i 39 #define VMAJSHIFT 8 Err bitreich.org 70 i 40 #define VMAJMASK 0xff Err bitreich.org 70 i 41 Err bitreich.org 70 i 42 #define BHDRSIZE (NBHDRMAGIC + 8 + 8) Err bitreich.org 70 i 43 Err bitreich.org 70 i 44 /* block descriptor constants */ Err bitreich.org 70 i 45 #define BDTYPE 0x100 Err bitreich.org 70 i 46 #define BDSIZE (8 + 8 + 8 + 8 + (MDSIZE)) Err bitreich.org 70 i 47 Err bitreich.org 70 i 48 /* misc helpers */ Err bitreich.org 70 i 49 extern int pack(unsigned char *, char *, ...); Err bitreich.org 70 i 50 extern int unpack(unsigned char *, char *, ...); Err bitreich.org 70 i 51 Err bitreich.org 70 i 52 static int bscreat(struct bctx *, char *, int); Err bitreich.org 70 i 53 static int bsopen(struct bctx *, char *, int, int); Err bitreich.org 70 i 54 static int bsput(struct bctx *, void *, size_t, unsigned char *); Err bitreich.org 70 i 55 static int bsget(struct bctx *, unsigned char *, void *, size_t *); Err bitreich.org 70 i 56 static int bsrm(struct bctx *, unsigned char *); Err bitreich.org 70 i 57 static int bsgc(struct bctx *); Err bitreich.org 70 i 58 static int bssync(struct bctx *); Err bitreich.org 70 i 59 static int bsclose(struct bctx *); Err bitreich.org 70 i 60 Err bitreich.org 70 i 61 static struct bops bops = { Err bitreich.org 70 i 62 .creat = bscreat, Err bitreich.org 70 i 63 .open = bsopen, Err bitreich.org 70 i 64 .put = bsput, Err bitreich.org 70 i 65 .get = bsget, Err bitreich.org 70 i 66 .rm = bsrm, Err bitreich.org 70 i 67 .gc = bsgc, Err bitreich.org 70 i 68 .sync = bssync, Err bitreich.org 70 i 69 .close = bsclose, Err bitreich.org 70 i 70 }; Err bitreich.org 70 i 71 Err bitreich.org 70 i 72 /* Block header structure */ Err bitreich.org 70 i 73 struct bhdr { Err bitreich.org 70 i 74 char magic[NBHDRMAGIC]; /* magic number for file(1) */ Err bitreich.org 70 i 75 uint64_t flags; /* version number */ Err bitreich.org 70 i 76 uint64_t nbd; /* number of block descriptors */ Err bitreich.org 70 i 77 }; Err bitreich.org 70 i 78 Err bitreich.org 70 i 79 /* Block descriptor */ Err bitreich.org 70 i 80 struct bd { Err bitreich.org 70 i 81 uint16_t type; /* BDTYPE */ Err bitreich.org 70 i 82 unsigned char reserved[6]; /* should be set to 0 when writing */ Err bitreich.org 70 i 83 uint64_t offset; /* block offset */ Err bitreich.org 70 i 84 uint64_t size; /* block size */ Err bitreich.org 70 i 85 uint64_t refcnt; /* reference count of block, 0 if block is removed */ Err bitreich.org 70 i 86 unsigned char md[MDSIZE]; /* hash of block */ Err bitreich.org 70 i 87 RB_ENTRY(bd) rbe; /* bdcache link node */ Err bitreich.org 70 i 88 SLIST_ENTRY(bd) sle; /* gchead link node */ Err bitreich.org 70 i 89 }; Err bitreich.org 70 i 90 RB_HEAD(bdcache, bd); Err bitreich.org 70 i 91 Err bitreich.org 70 i 92 /* Storage layer context */ Err bitreich.org 70 i 93 struct sctx { Err bitreich.org 70 i 94 struct bdcache bdcache; /* cache of block descriptors */ Err bitreich.org 70 i 95 SLIST_HEAD(gchead, bd) gchead; /* list of all blocks with a zero refcount */ Err bitreich.org 70 i 96 int fd; /* underlying storage file descriptor */ Err bitreich.org 70 i 97 int rdonly; /* when set to 1, the bssync() operation is a no-op */ Err bitreich.org 70 i 98 struct bhdr bhdr; /* block header */ Err bitreich.org 70 i 99 }; Err bitreich.org 70 i 100 Err bitreich.org 70 i 101 static int Err bitreich.org 70 i 102 bd_cmp(struct bd *b1, struct bd *b2) Err bitreich.org 70 i 103 { Err bitreich.org 70 i 104 int r; Err bitreich.org 70 i 105 Err bitreich.org 70 i 106 r = memcmp(b1->md, b2->md, MDSIZE); Err bitreich.org 70 i 107 if (r > 0) Err bitreich.org 70 i 108 return 1; Err bitreich.org 70 i 109 else if (r < 0) Err bitreich.org 70 i 110 return -1; Err bitreich.org 70 i 111 return 0; Err bitreich.org 70 i 112 } Err bitreich.org 70 i 113 static RB_PROTOTYPE(bdcache, bd, rbe, bd_cmp) Err bitreich.org 70 i 114 static RB_GENERATE(bdcache, bd, rbe, bd_cmp) Err bitreich.org 70 i 115 Err bitreich.org 70 i 116 /* Unpack block header */ Err bitreich.org 70 i 117 static int Err bitreich.org 70 i 118 unpackbhdr(unsigned char *buf, struct bhdr *bhdr) Err bitreich.org 70 i 119 { Err bitreich.org 70 i 120 char fmt[BUFSIZ]; Err bitreich.org 70 i 121 int n; Err bitreich.org 70 i 122 Err bitreich.org 70 i 123 snprintf(fmt, sizeof(fmt), "'%dqq", NBHDRMAGIC); Err bitreich.org 70 i 124 n = unpack(buf, fmt, Err bitreich.org 70 i 125 bhdr->magic, Err bitreich.org 70 i 126 &bhdr->flags, Err bitreich.org 70 i 127 &bhdr->nbd); Err bitreich.org 70 i 128 Err bitreich.org 70 i 129 assert(n == BHDRSIZE); Err bitreich.org 70 i 130 return n; Err bitreich.org 70 i 131 } Err bitreich.org 70 i 132 Err bitreich.org 70 i 133 /* Pack block header */ Err bitreich.org 70 i 134 static int Err bitreich.org 70 i 135 packbhdr(unsigned char *buf, struct bhdr *bhdr) Err bitreich.org 70 i 136 { Err bitreich.org 70 i 137 char fmt[BUFSIZ]; Err bitreich.org 70 i 138 int n; Err bitreich.org 70 i 139 Err bitreich.org 70 i 140 snprintf(fmt, sizeof(fmt), "'%dqq", NBHDRMAGIC); Err bitreich.org 70 i 141 n = pack(buf, fmt, Err bitreich.org 70 i 142 bhdr->magic, Err bitreich.org 70 i 143 bhdr->flags, Err bitreich.org 70 i 144 bhdr->nbd); Err bitreich.org 70 i 145 Err bitreich.org 70 i 146 assert(n == BHDRSIZE); Err bitreich.org 70 i 147 return n; Err bitreich.org 70 i 148 } Err bitreich.org 70 i 149 Err bitreich.org 70 i 150 /* Unpack block descriptor */ Err bitreich.org 70 i 151 static int Err bitreich.org 70 i 152 unpackbd(unsigned char *buf, struct bd *bd) Err bitreich.org 70 i 153 { Err bitreich.org 70 i 154 char fmt[BUFSIZ]; Err bitreich.org 70 i 155 int n; Err bitreich.org 70 i 156 Err bitreich.org 70 i 157 snprintf(fmt, sizeof(fmt), "s'6qqq'%d", MDSIZE); Err bitreich.org 70 i 158 n = unpack(buf, fmt, Err bitreich.org 70 i 159 &bd->type, Err bitreich.org 70 i 160 bd->reserved, Err bitreich.org 70 i 161 &bd->offset, Err bitreich.org 70 i 162 &bd->size, Err bitreich.org 70 i 163 &bd->refcnt, Err bitreich.org 70 i 164 bd->md); Err bitreich.org 70 i 165 Err bitreich.org 70 i 166 assert(n == BDSIZE); Err bitreich.org 70 i 167 return n; Err bitreich.org 70 i 168 } Err bitreich.org 70 i 169 Err bitreich.org 70 i 170 /* Write block descriptor */ Err bitreich.org 70 i 171 static int Err bitreich.org 70 i 172 packbd(unsigned char *buf, struct bd *bd) Err bitreich.org 70 i 173 { Err bitreich.org 70 i 174 char fmt[BUFSIZ]; Err bitreich.org 70 i 175 int n; Err bitreich.org 70 i 176 Err bitreich.org 70 i 177 snprintf(fmt, sizeof(fmt), "s'6qqq'%d", MDSIZE); Err bitreich.org 70 i 178 n = pack(buf, fmt, Err bitreich.org 70 i 179 bd->type, Err bitreich.org 70 i 180 bd->reserved, Err bitreich.org 70 i 181 bd->offset, Err bitreich.org 70 i 182 bd->size, Err bitreich.org 70 i 183 bd->refcnt, Err bitreich.org 70 i 184 bd->md); Err bitreich.org 70 i 185 Err bitreich.org 70 i 186 assert(n == BDSIZE); Err bitreich.org 70 i 187 return n; Err bitreich.org 70 i 188 } Err bitreich.org 70 i 189 Err bitreich.org 70 i 190 /* Load block descriptor from file */ Err bitreich.org 70 i 191 static int Err bitreich.org 70 i 192 loadbd(struct sctx *sctx) Err bitreich.org 70 i 193 { Err bitreich.org 70 i 194 unsigned char bdbuf[BDSIZE]; Err bitreich.org 70 i 195 struct bd *bd; Err bitreich.org 70 i 196 Err bitreich.org 70 i 197 bd = calloc(1, sizeof(*bd)); Err bitreich.org 70 i 198 if (bd == NULL) { Err bitreich.org 70 i 199 seterr("calloc: out of memory"); Err bitreich.org 70 i 200 return -1; Err bitreich.org 70 i 201 } Err bitreich.org 70 i 202 Err bitreich.org 70 i 203 if (xread(sctx->fd, bdbuf, BDSIZE) != BDSIZE) { Err bitreich.org 70 i 204 free(bd); Err bitreich.org 70 i 205 seterr("failed to read block descriptor: %s", Err bitreich.org 70 i 206 strerror(errno)); Err bitreich.org 70 i 207 return -1; Err bitreich.org 70 i 208 } Err bitreich.org 70 i 209 unpackbd(bdbuf, bd); Err bitreich.org 70 i 210 Err bitreich.org 70 i 211 if (bd->type != BDTYPE) { Err bitreich.org 70 i 212 free(bd); Err bitreich.org 70 i 213 seterr("invalid block descriptor type: %d", bd->type); Err bitreich.org 70 i 214 return -1; Err bitreich.org 70 i 215 } Err bitreich.org 70 i 216 Err bitreich.org 70 i 217 /* Move to the next block descriptor */ Err bitreich.org 70 i 218 if (lseek(sctx->fd, bd->size, SEEK_CUR) < 0) { Err bitreich.org 70 i 219 free(bd); Err bitreich.org 70 i 220 seterr("lseek: %s", strerror(errno)); Err bitreich.org 70 i 221 return -1; Err bitreich.org 70 i 222 } Err bitreich.org 70 i 223 Err bitreich.org 70 i 224 /* Err bitreich.org 70 i 225 * When refcount is 0 the block has been removed. Err bitreich.org 70 i 226 * In that case, the block descriptor is still present Err bitreich.org 70 i 227 * in the file as it is used to locate the next block Err bitreich.org 70 i 228 * descriptor which could be live. Err bitreich.org 70 i 229 * Err bitreich.org 70 i 230 * The garbage collection list links together all block Err bitreich.org 70 i 231 * descriptors that have a reference count of 0. Err bitreich.org 70 i 232 * This is needed to implement the gc operation. Err bitreich.org 70 i 233 */ Err bitreich.org 70 i 234 if (bd->refcnt > 0) Err bitreich.org 70 i 235 RB_INSERT(bdcache, &sctx->bdcache, bd); Err bitreich.org 70 i 236 else Err bitreich.org 70 i 237 SLIST_INSERT_HEAD(&sctx->gchead, bd, sle); Err bitreich.org 70 i 238 return 0; Err bitreich.org 70 i 239 } Err bitreich.org 70 i 240 Err bitreich.org 70 i 241 /* Initialize block descriptor cache */ Err bitreich.org 70 i 242 static int Err bitreich.org 70 i 243 initbdcache(struct sctx *sctx) Err bitreich.org 70 i 244 { Err bitreich.org 70 i 245 struct bhdr *bhdr; Err bitreich.org 70 i 246 uint64_t i; Err bitreich.org 70 i 247 Err bitreich.org 70 i 248 bhdr = &sctx->bhdr; Err bitreich.org 70 i 249 for (i = 0; i < bhdr->nbd; i++) { Err bitreich.org 70 i 250 struct bd *bd, *tmp; Err bitreich.org 70 i 251 Err bitreich.org 70 i 252 if (loadbd(sctx) == 0) Err bitreich.org 70 i 253 continue; Err bitreich.org 70 i 254 Err bitreich.org 70 i 255 /* Free block descriptor cache */ Err bitreich.org 70 i 256 RB_FOREACH_SAFE(bd, bdcache, &sctx->bdcache, tmp) { Err bitreich.org 70 i 257 RB_REMOVE(bdcache, &sctx->bdcache, bd); Err bitreich.org 70 i 258 free(bd); Err bitreich.org 70 i 259 } Err bitreich.org 70 i 260 Err bitreich.org 70 i 261 /* Free garbage collector list */ Err bitreich.org 70 i 262 while (!SLIST_EMPTY(&sctx->gchead)) { Err bitreich.org 70 i 263 bd = SLIST_FIRST(&sctx->gchead); Err bitreich.org 70 i 264 SLIST_REMOVE(&sctx->gchead, bd, bd, sle); Err bitreich.org 70 i 265 free(bd); Err bitreich.org 70 i 266 } Err bitreich.org 70 i 267 return -1; Err bitreich.org 70 i 268 } Err bitreich.org 70 i 269 return 0; Err bitreich.org 70 i 270 } Err bitreich.org 70 i 271 Err bitreich.org 70 i 272 /* Create storage file */ Err bitreich.org 70 i 273 static int Err bitreich.org 70 i 274 bscreat(struct bctx *bctx, char *path, int mode) Err bitreich.org 70 i 275 { Err bitreich.org 70 i 276 unsigned char bhdrbuf[BHDRSIZE]; Err bitreich.org 70 i 277 struct sctx *sctx; Err bitreich.org 70 i 278 struct bhdr *bhdr; Err bitreich.org 70 i 279 int fd; Err bitreich.org 70 i 280 Err bitreich.org 70 i 281 fd = open(path, O_RDWR | O_CREAT | O_EXCL, mode); Err bitreich.org 70 i 282 if (fd < 0) { Err bitreich.org 70 i 283 seterr("open: %s", strerror(errno)); Err bitreich.org 70 i 284 return -1; Err bitreich.org 70 i 285 } Err bitreich.org 70 i 286 Err bitreich.org 70 i 287 bctx->sctx = calloc(1, sizeof(struct sctx)); Err bitreich.org 70 i 288 if (bctx->sctx == NULL) { Err bitreich.org 70 i 289 close(fd); Err bitreich.org 70 i 290 seterr("calloc: out of memory"); Err bitreich.org 70 i 291 return -1; Err bitreich.org 70 i 292 } Err bitreich.org 70 i 293 Err bitreich.org 70 i 294 sctx = bctx->sctx; Err bitreich.org 70 i 295 RB_INIT(&sctx->bdcache); Err bitreich.org 70 i 296 SLIST_INIT(&sctx->gchead); Err bitreich.org 70 i 297 sctx->fd = fd; Err bitreich.org 70 i 298 Err bitreich.org 70 i 299 bhdr = &sctx->bhdr; Err bitreich.org 70 i 300 memcpy(bhdr->magic, BHDRMAGIC, NBHDRMAGIC); Err bitreich.org 70 i 301 bhdr->flags = (VMAJ << VMAJSHIFT) | VMIN; Err bitreich.org 70 i 302 bhdr->nbd = 0; Err bitreich.org 70 i 303 Err bitreich.org 70 i 304 packbhdr(bhdrbuf, bhdr); Err bitreich.org 70 i 305 if (xwrite(fd, bhdrbuf, BHDRSIZE) != BHDRSIZE) { Err bitreich.org 70 i 306 free(sctx); Err bitreich.org 70 i 307 close(fd); Err bitreich.org 70 i 308 seterr("failed to write block header: %s", strerror(errno)); Err bitreich.org 70 i 309 return -1; Err bitreich.org 70 i 310 } Err bitreich.org 70 i 311 return 0; Err bitreich.org 70 i 312 } Err bitreich.org 70 i 313 Err bitreich.org 70 i 314 /* Open storage file */ Err bitreich.org 70 i 315 static int Err bitreich.org 70 i 316 bsopen(struct bctx *bctx, char *path, int flags, int mode) Err bitreich.org 70 i 317 { Err bitreich.org 70 i 318 unsigned char bhdrbuf[BHDRSIZE]; Err bitreich.org 70 i 319 struct sctx *sctx; Err bitreich.org 70 i 320 struct bhdr *bhdr; Err bitreich.org 70 i 321 int fd; Err bitreich.org 70 i 322 Err bitreich.org 70 i 323 switch (flags) { Err bitreich.org 70 i 324 case B_READ: Err bitreich.org 70 i 325 flags = O_RDONLY; Err bitreich.org 70 i 326 break; Err bitreich.org 70 i 327 case B_RDWR: Err bitreich.org 70 i 328 flags = O_RDWR; Err bitreich.org 70 i 329 break; Err bitreich.org 70 i 330 default: Err bitreich.org 70 i 331 seterr("invalid params"); Err bitreich.org 70 i 332 return -1; Err bitreich.org 70 i 333 } Err bitreich.org 70 i 334 Err bitreich.org 70 i 335 fd = open(path, flags, mode); Err bitreich.org 70 i 336 if (fd < 0) { Err bitreich.org 70 i 337 seterr("open: %s", strerror(errno)); Err bitreich.org 70 i 338 return -1; Err bitreich.org 70 i 339 } Err bitreich.org 70 i 340 Err bitreich.org 70 i 341 bctx->sctx = calloc(1, sizeof(struct sctx)); Err bitreich.org 70 i 342 if (bctx->sctx == NULL) { Err bitreich.org 70 i 343 close(fd); Err bitreich.org 70 i 344 seterr("calloc: out of memory"); Err bitreich.org 70 i 345 return -1; Err bitreich.org 70 i 346 } Err bitreich.org 70 i 347 Err bitreich.org 70 i 348 sctx = bctx->sctx; Err bitreich.org 70 i 349 RB_INIT(&sctx->bdcache); Err bitreich.org 70 i 350 SLIST_INIT(&sctx->gchead); Err bitreich.org 70 i 351 bhdr = &sctx->bhdr; Err bitreich.org 70 i 352 Err bitreich.org 70 i 353 if (xread(fd, bhdrbuf, BHDRSIZE) != BHDRSIZE) { Err bitreich.org 70 i 354 free(sctx); Err bitreich.org 70 i 355 close(fd); Err bitreich.org 70 i 356 seterr("failed to read block header: %s", strerror(errno)); Err bitreich.org 70 i 357 return -1; Err bitreich.org 70 i 358 } Err bitreich.org 70 i 359 unpackbhdr(bhdrbuf, bhdr); Err bitreich.org 70 i 360 Err bitreich.org 70 i 361 if (memcmp(bhdr->magic, BHDRMAGIC, NBHDRMAGIC) != 0) { Err bitreich.org 70 i 362 free(sctx); Err bitreich.org 70 i 363 close(fd); Err bitreich.org 70 i 364 seterr("unknown block header magic"); Err bitreich.org 70 i 365 return -1; Err bitreich.org 70 i 366 } Err bitreich.org 70 i 367 Err bitreich.org 70 i 368 /* If the major version is different, the format is incompatible */ Err bitreich.org 70 i 369 if (((bhdr->flags >> VMAJSHIFT) & VMAJMASK) != VMAJ) { Err bitreich.org 70 i 370 free(sctx); Err bitreich.org 70 i 371 close(fd); Err bitreich.org 70 i 372 seterr("block header version mismatch"); Err bitreich.org 70 i 373 return -1; Err bitreich.org 70 i 374 } Err bitreich.org 70 i 375 Err bitreich.org 70 i 376 sctx->fd = fd; Err bitreich.org 70 i 377 sctx->rdonly = flags == O_RDONLY; Err bitreich.org 70 i 378 Err bitreich.org 70 i 379 if (initbdcache(sctx) < 0) { Err bitreich.org 70 i 380 free(sctx); Err bitreich.org 70 i 381 close(fd); Err bitreich.org 70 i 382 return -1; Err bitreich.org 70 i 383 } Err bitreich.org 70 i 384 return 0; Err bitreich.org 70 i 385 } Err bitreich.org 70 i 386 Err bitreich.org 70 i 387 /* Write a block to the storage file */ Err bitreich.org 70 i 388 static int Err bitreich.org 70 i 389 bsput(struct bctx *bctx, void *buf, size_t n, unsigned char *md) Err bitreich.org 70 i 390 { Err bitreich.org 70 i 391 unsigned char bdbuf[BDSIZE]; Err bitreich.org 70 i 392 struct sctx *sctx; Err bitreich.org 70 i 393 struct bhdr *bhdr; Err bitreich.org 70 i 394 struct bd key, *bd; Err bitreich.org 70 i 395 off_t offs; Err bitreich.org 70 i 396 Err bitreich.org 70 i 397 /* Err bitreich.org 70 i 398 * If the block is already present in the cache Err bitreich.org 70 i 399 * just increment the reference count and write back Err bitreich.org 70 i 400 * the block descriptor associated with that block. Err bitreich.org 70 i 401 */ Err bitreich.org 70 i 402 sctx = bctx->sctx; Err bitreich.org 70 i 403 memcpy(key.md, md, MDSIZE); Err bitreich.org 70 i 404 bd = RB_FIND(bdcache, &sctx->bdcache, &key); Err bitreich.org 70 i 405 if (bd != NULL) { Err bitreich.org 70 i 406 off_t bdoffs; Err bitreich.org 70 i 407 Err bitreich.org 70 i 408 bdoffs = bd->offset - BDSIZE; Err bitreich.org 70 i 409 if (lseek(sctx->fd, bdoffs, SEEK_SET) < 0) { Err bitreich.org 70 i 410 seterr("lseek: %s", strerror(errno)); Err bitreich.org 70 i 411 return -1; Err bitreich.org 70 i 412 } Err bitreich.org 70 i 413 Err bitreich.org 70 i 414 bd->refcnt++; Err bitreich.org 70 i 415 packbd(bdbuf, bd); Err bitreich.org 70 i 416 if (xwrite(sctx->fd, bdbuf, BDSIZE) != BDSIZE) { Err bitreich.org 70 i 417 bd->refcnt--; Err bitreich.org 70 i 418 seterr("failed to write block descriptor: %s", Err bitreich.org 70 i 419 strerror(errno)); Err bitreich.org 70 i 420 return -1; Err bitreich.org 70 i 421 } Err bitreich.org 70 i 422 Err bitreich.org 70 i 423 memcpy(md, bd->md, MDSIZE); Err bitreich.org 70 i 424 return 0; Err bitreich.org 70 i 425 } Err bitreich.org 70 i 426 Err bitreich.org 70 i 427 /* New blocks are appended at the end of storage file */ Err bitreich.org 70 i 428 offs = lseek(sctx->fd, 0, SEEK_END); Err bitreich.org 70 i 429 if (offs < 0) { Err bitreich.org 70 i 430 seterr("lseek: %s", strerror(errno)); Err bitreich.org 70 i 431 return -1; Err bitreich.org 70 i 432 } Err bitreich.org 70 i 433 Err bitreich.org 70 i 434 bd = calloc(1, sizeof(*bd)); Err bitreich.org 70 i 435 if (bd == NULL) { Err bitreich.org 70 i 436 seterr("calloc: out of memory"); Err bitreich.org 70 i 437 return -1; Err bitreich.org 70 i 438 } Err bitreich.org 70 i 439 bd->type = BDTYPE; Err bitreich.org 70 i 440 bd->offset = offs + BDSIZE; Err bitreich.org 70 i 441 bd->size = n; Err bitreich.org 70 i 442 bd->refcnt = 1; Err bitreich.org 70 i 443 memcpy(bd->md, key.md, MDSIZE); Err bitreich.org 70 i 444 Err bitreich.org 70 i 445 packbd(bdbuf, bd); Err bitreich.org 70 i 446 if (xwrite(sctx->fd, bdbuf, BDSIZE) != BDSIZE) { Err bitreich.org 70 i 447 /* Shouldn't fail but if it does rewind storage file state */ Err bitreich.org 70 i 448 ftruncate(sctx->fd, offs); Err bitreich.org 70 i 449 free(bd); Err bitreich.org 70 i 450 seterr("failed to write block descriptor: %s", Err bitreich.org 70 i 451 strerror(errno)); Err bitreich.org 70 i 452 return -1; Err bitreich.org 70 i 453 } Err bitreich.org 70 i 454 Err bitreich.org 70 i 455 if (xwrite(sctx->fd, buf, n) != n) { Err bitreich.org 70 i 456 /* Shouldn't fail but if it does rewind storage file state */ Err bitreich.org 70 i 457 ftruncate(sctx->fd, offs); Err bitreich.org 70 i 458 free(bd); Err bitreich.org 70 i 459 seterr("failed to write block: %s", strerror(errno)); Err bitreich.org 70 i 460 return -1; Err bitreich.org 70 i 461 } Err bitreich.org 70 i 462 Err bitreich.org 70 i 463 /* Err bitreich.org 70 i 464 * Update block entry header. Err bitreich.org 70 i 465 * The header will be written to the storage file Err bitreich.org 70 i 466 * when bsclose() or bssync() is called. Err bitreich.org 70 i 467 */ Err bitreich.org 70 i 468 bhdr = &sctx->bhdr; Err bitreich.org 70 i 469 bhdr->nbd++; Err bitreich.org 70 i 470 Err bitreich.org 70 i 471 RB_INSERT(bdcache, &sctx->bdcache, bd); Err bitreich.org 70 i 472 memcpy(md, bd->md, MDSIZE); Err bitreich.org 70 i 473 return bd->size; Err bitreich.org 70 i 474 } Err bitreich.org 70 i 475 Err bitreich.org 70 i 476 /* Read a block from the storage file */ Err bitreich.org 70 i 477 static int Err bitreich.org 70 i 478 bsget(struct bctx *bctx, unsigned char *md, void *buf, size_t *n) Err bitreich.org 70 i 479 { Err bitreich.org 70 i 480 struct sctx *sctx; Err bitreich.org 70 i 481 struct bd key, *bd; Err bitreich.org 70 i 482 Err bitreich.org 70 i 483 sctx = bctx->sctx; Err bitreich.org 70 i 484 memcpy(key.md, md, MDSIZE); Err bitreich.org 70 i 485 bd = RB_FIND(bdcache, &sctx->bdcache, &key); Err bitreich.org 70 i 486 if (bd == NULL) { Err bitreich.org 70 i 487 seterr("block not found"); Err bitreich.org 70 i 488 return -1; Err bitreich.org 70 i 489 } Err bitreich.org 70 i 490 Err bitreich.org 70 i 491 if (*n < bd->size) { Err bitreich.org 70 i 492 seterr("buffer too small"); Err bitreich.org 70 i 493 return -1; Err bitreich.org 70 i 494 } Err bitreich.org 70 i 495 Err bitreich.org 70 i 496 if (lseek(sctx->fd, bd->offset, SEEK_SET) < 0) { Err bitreich.org 70 i 497 seterr("lseek: %s", strerror(errno)); Err bitreich.org 70 i 498 return -1; Err bitreich.org 70 i 499 } Err bitreich.org 70 i 500 if (xread(sctx->fd, buf, bd->size) != bd->size) { Err bitreich.org 70 i 501 seterr("failed to read block: %s", strerror(errno)); Err bitreich.org 70 i 502 return -1; Err bitreich.org 70 i 503 } Err bitreich.org 70 i 504 *n = bd->size; Err bitreich.org 70 i 505 return 0; Err bitreich.org 70 i 506 } Err bitreich.org 70 i 507 Err bitreich.org 70 i 508 /* Remove a block with the given hash */ Err bitreich.org 70 i 509 static int Err bitreich.org 70 i 510 bsrm(struct bctx *bctx, unsigned char *md) Err bitreich.org 70 i 511 { Err bitreich.org 70 i 512 unsigned char bdbuf[BDSIZE]; Err bitreich.org 70 i 513 struct sctx *sctx; Err bitreich.org 70 i 514 struct bd key, *bd; Err bitreich.org 70 i 515 off_t bdoffs; Err bitreich.org 70 i 516 Err bitreich.org 70 i 517 sctx = bctx->sctx; Err bitreich.org 70 i 518 memcpy(key.md, md, MDSIZE); Err bitreich.org 70 i 519 bd = RB_FIND(bdcache, &sctx->bdcache, &key); Err bitreich.org 70 i 520 if (bd == NULL) { Err bitreich.org 70 i 521 seterr("block not found"); Err bitreich.org 70 i 522 return -1; Err bitreich.org 70 i 523 } Err bitreich.org 70 i 524 Err bitreich.org 70 i 525 bdoffs = bd->offset - BDSIZE; Err bitreich.org 70 i 526 if (lseek(sctx->fd, bdoffs, SEEK_SET) < 0) { Err bitreich.org 70 i 527 seterr("lseek: %s", strerror(errno)); Err bitreich.org 70 i 528 return -1; Err bitreich.org 70 i 529 } Err bitreich.org 70 i 530 Err bitreich.org 70 i 531 bd->refcnt--; Err bitreich.org 70 i 532 packbd(bdbuf, bd); Err bitreich.org 70 i 533 if (xwrite(sctx->fd, bdbuf, BDSIZE) != BDSIZE) { Err bitreich.org 70 i 534 bd->refcnt++; Err bitreich.org 70 i 535 seterr("failed to write block descriptor: %s", Err bitreich.org 70 i 536 strerror(errno)); Err bitreich.org 70 i 537 return -1; Err bitreich.org 70 i 538 } Err bitreich.org 70 i 539 Err bitreich.org 70 i 540 /* This block is still referenced so just return */ Err bitreich.org 70 i 541 if (bd->refcnt > 0) Err bitreich.org 70 i 542 return 0; Err bitreich.org 70 i 543 Err bitreich.org 70 i 544 if (punchhole(sctx->fd, bd->offset, bd->size) < 0) { Err bitreich.org 70 i 545 /* Err bitreich.org 70 i 546 * Filesystem does not support hole punching. Err bitreich.org 70 i 547 * Restore reference count. Err bitreich.org 70 i 548 */ Err bitreich.org 70 i 549 lseek(sctx->fd, bdoffs, SEEK_SET); Err bitreich.org 70 i 550 bd->refcnt++; Err bitreich.org 70 i 551 packbd(bdbuf, bd); Err bitreich.org 70 i 552 xwrite(sctx->fd, bdbuf, BDSIZE); Err bitreich.org 70 i 553 seterr("operation not supported"); Err bitreich.org 70 i 554 return -1; Err bitreich.org 70 i 555 } Err bitreich.org 70 i 556 Err bitreich.org 70 i 557 /* Err bitreich.org 70 i 558 * Remove block from block descriptor cache as this is no Err bitreich.org 70 i 559 * longer a valid block. Insert it into the garbage collector Err bitreich.org 70 i 560 * list instead. Err bitreich.org 70 i 561 */ Err bitreich.org 70 i 562 RB_REMOVE(bdcache, &sctx->bdcache, bd); Err bitreich.org 70 i 563 SLIST_INSERT_HEAD(&sctx->gchead, bd, sle); Err bitreich.org 70 i 564 return 0; Err bitreich.org 70 i 565 } Err bitreich.org 70 i 566 Err bitreich.org 70 i 567 /* Err bitreich.org 70 i 568 * Re-punch all holes in the storage file. Err bitreich.org 70 i 569 * This is needed when the storage file is copied from Err bitreich.org 70 i 570 * one system to another and back. The target system Err bitreich.org 70 i 571 * may not support hole punching so the holes will be Err bitreich.org 70 i 572 * filled with literal zeroes, negating the space saving Err bitreich.org 70 i 573 * effects. Err bitreich.org 70 i 574 */ Err bitreich.org 70 i 575 static int Err bitreich.org 70 i 576 bsgc(struct bctx *bctx) Err bitreich.org 70 i 577 { Err bitreich.org 70 i 578 struct sctx *sctx; Err bitreich.org 70 i 579 struct bd *bd; Err bitreich.org 70 i 580 Err bitreich.org 70 i 581 sctx = bctx->sctx; Err bitreich.org 70 i 582 SLIST_FOREACH(bd, &sctx->gchead, sle) { Err bitreich.org 70 i 583 assert(bd->refcnt == 0); Err bitreich.org 70 i 584 punchhole(sctx->fd, bd->offset, bd->size); Err bitreich.org 70 i 585 } Err bitreich.org 70 i 586 return 0; Err bitreich.org 70 i 587 } Err bitreich.org 70 i 588 Err bitreich.org 70 i 589 /* Sync block header to storage file */ Err bitreich.org 70 i 590 static int Err bitreich.org 70 i 591 bssync(struct bctx *bctx) Err bitreich.org 70 i 592 { Err bitreich.org 70 i 593 unsigned char bhdrbuf[BHDRSIZE]; Err bitreich.org 70 i 594 struct sctx *sctx; Err bitreich.org 70 i 595 struct bhdr *bhdr; Err bitreich.org 70 i 596 Err bitreich.org 70 i 597 sctx = bctx->sctx; Err bitreich.org 70 i 598 if (sctx->rdonly) Err bitreich.org 70 i 599 return 0; Err bitreich.org 70 i 600 Err bitreich.org 70 i 601 if (lseek(sctx->fd, 0, SEEK_SET) < 0) { Err bitreich.org 70 i 602 seterr("lseek: %s", strerror(errno)); Err bitreich.org 70 i 603 return -1; Err bitreich.org 70 i 604 } Err bitreich.org 70 i 605 Err bitreich.org 70 i 606 bhdr = &sctx->bhdr; Err bitreich.org 70 i 607 packbhdr(bhdrbuf, bhdr); Err bitreich.org 70 i 608 if (xwrite(sctx->fd, bhdrbuf, BHDRSIZE) != BHDRSIZE) { Err bitreich.org 70 i 609 seterr("failed to write block header: %s", strerror(errno)); Err bitreich.org 70 i 610 return -1; Err bitreich.org 70 i 611 } Err bitreich.org 70 i 612 fsync(sctx->fd); Err bitreich.org 70 i 613 return 0; Err bitreich.org 70 i 614 } Err bitreich.org 70 i 615 Err bitreich.org 70 i 616 /* Close storage handle */ Err bitreich.org 70 i 617 static int Err bitreich.org 70 i 618 bsclose(struct bctx *bctx) Err bitreich.org 70 i 619 { Err bitreich.org 70 i 620 struct sctx *sctx; Err bitreich.org 70 i 621 struct bd *bd, *tmp; Err bitreich.org 70 i 622 int r; Err bitreich.org 70 i 623 Err bitreich.org 70 i 624 /* Free block descriptor cache */ Err bitreich.org 70 i 625 sctx = bctx->sctx; Err bitreich.org 70 i 626 RB_FOREACH_SAFE(bd, bdcache, &sctx->bdcache, tmp) { Err bitreich.org 70 i 627 RB_REMOVE(bdcache, &sctx->bdcache, bd); Err bitreich.org 70 i 628 free(bd); Err bitreich.org 70 i 629 } Err bitreich.org 70 i 630 Err bitreich.org 70 i 631 /* Free garbage collector list */ Err bitreich.org 70 i 632 while (!SLIST_EMPTY(&sctx->gchead)) { Err bitreich.org 70 i 633 bd = SLIST_FIRST(&sctx->gchead); Err bitreich.org 70 i 634 SLIST_REMOVE(&sctx->gchead, bd, bd, sle); Err bitreich.org 70 i 635 free(bd); Err bitreich.org 70 i 636 } Err bitreich.org 70 i 637 Err bitreich.org 70 i 638 r = close(sctx->fd); Err bitreich.org 70 i 639 free(sctx); Err bitreich.org 70 i 640 if (r < 0) Err bitreich.org 70 i 641 seterr("close: %s", strerror(errno)); Err bitreich.org 70 i 642 return r; Err bitreich.org 70 i 643 } Err bitreich.org 70 i 644 Err bitreich.org 70 i 645 struct bops * Err bitreich.org 70 i 646 bstorageops(void) Err bitreich.org 70 i 647 { Err bitreich.org 70 i 648 return &bops; Err bitreich.org 70 i 649 } Err bitreich.org 70 .