+static inline void
+shake_write(void *addr, int len, sh_off_t pos)
+{
+ int l = sh_pwrite(obuck_fd, addr, len, pos);
+ if (l != len)
+ {
+ if (l < 0)
+ die("obuck_shakedown write error: %m");
+ else
+ die("obuck_shakedown write error: disk full");
+ }
+}
+
+static inline void
+shake_sync(void)
+{
+ if (obuck_shake_security > 1)
+ fdatasync(obuck_fd);
+}
+
+static void
+shake_write_backup(sh_off_t bpos, byte *norm_buf, int norm_size, byte *fragment, int frag_size, sh_off_t frag_pos, int more_size)
+{
+ struct obuck_header *bhdr;
+ int boff = 0;
+ int l;
+ oid_t old_oid;
+
+ /* First of all, the "normal" part -- everything that will be written in this pass */
+ DBG("Backing up first round of changes at position %Lx + %x", (long long) bpos, norm_size);
+ while (boff < norm_size)
+ {
+ /* This needn't be optimized for speed. */
+ bhdr = (struct obuck_header *) (norm_buf + boff);
+ ASSERT(bhdr->magic == OBUCK_MAGIC);
+ l = ALIGN(sizeof(struct obuck_header) + bhdr->length + 4, OBUCK_ALIGN);
+ old_oid = bhdr->oid;
+ bhdr->oid = bpos >> OBUCK_SHIFT;
+ shake_write(bhdr, l, bpos);
+ bhdr->oid = old_oid;
+ boff += l;
+ bpos += l;
+ }
+
+ /* If we have an incomplete bucket at the end of the buffer, we must copy it as well. */
+ if (more_size)
+ {
+ DBG("Backing up fragment of size %x and %x more", frag_size, more_size);
+
+ /* First the part we already have in the buffer */
+ bhdr = (struct obuck_header *) fragment;
+ ASSERT(bhdr->magic == OBUCK_MAGIC);
+ old_oid = bhdr->oid;
+ bhdr->oid = bpos >> OBUCK_SHIFT;
+ shake_write(bhdr, frag_size, bpos);
+ bhdr->oid = old_oid;
+ bpos += frag_size;
+
+ /* And then the rest, using a small 64K buffer */
+ byte *auxbuf = alloca(65536);
+ l = 0;
+ while (l < more_size)
+ {
+ int j = MIN(more_size-l, 65536);
+ if (sh_pread(obuck_fd, auxbuf, j, frag_pos + frag_size + l) != j)
+ die("obuck_shakedown read error: %m");
+ shake_write(auxbuf, j, bpos);
+ bpos += j;
+ l += j;
+ }
+ }
+}
+
+static void
+shake_erase(sh_off_t start, sh_off_t end)
+{
+ if (start > end)
+ die("shake_erase called with negative length, that's a bug");
+ ASSERT(!(start & (OBUCK_ALIGN-1)) && !(end & (OBUCK_ALIGN-1)));
+ while (start < end)
+ {
+ u32 check = OBUCK_TRAILER;
+ obuck_hdr.magic = OBUCK_MAGIC;
+ obuck_hdr.oid = OBUCK_OID_DELETED;
+ uns len = MIN(0x40000000, end-start);
+ obuck_hdr.length = len - sizeof(obuck_hdr) - 4;
+ DBG("Erasing %08x bytes at %Lx", len, (long long) start);
+ shake_write(&obuck_hdr, sizeof(obuck_hdr), start);
+ start += len;
+ shake_write(&check, 4, start-4);
+ }
+}
+