+ int l = f->bptr - f->buffer;
+ char *c = f->buffer;
+
+ while (l)
+ {
+ int z = sh_pwrite(f->fd, c, l, f->fdpos);
+ if (z <= 0)
+ die("Error writing bucket: %m");
+ f->fdpos += z;
+ l -= z;
+ c += z;
+ }
+ f->bptr = f->buffer;
+ f->pos = f->fdpos;
+}
+
+static void
+obuck_fb_close(struct fastbuf *f)
+{
+ close(f->fd);
+}
+
+/*** Exported functions ***/
+
+void
+obuck_init(int writeable)
+{
+ struct fastbuf *b;
+ int buflen = 65536;
+ sh_off_t size;
+
+ obuck_fd = open(obuck_name, (writeable ? O_RDWR | O_CREAT : O_RDONLY), 0666);
+ obuck_fb = b = xmalloc_zero(sizeof(struct fastbuf) + buflen + OBUCK_ALIGN + 4);
+ b->buflen = buflen;
+ b->buffer = (char *)(b+1);
+ b->bptr = b->bstop = b->buffer;
+ b->bufend = b->buffer + buflen;
+ b->name = "bucket";
+ b->fd = obuck_fd;
+ b->refill = obuck_fb_refill;
+ b->spout = obuck_fb_spout;
+ b->close = obuck_fb_close;
+ obuck_lock_read();
+ size = sh_seek(obuck_fd, 0, SEEK_END);
+ if (size)
+ {
+ /* If the bucket pool is not empty, check consistency of its end */
+ u32 check;
+ bucket_start = size - 4; /* for error reporting */
+ if (sh_pread(obuck_fd, &check, 4, size-4) != 4 ||
+ check != OBUCK_TRAILER)
+ obuck_broken("Missing trailer of last object");
+ }
+ obuck_unlock();
+}
+
+void
+obuck_cleanup(void)
+{
+ bclose(obuck_fb);
+}
+
+void /* FIXME: Call somewhere :) */
+obuck_sync(void)
+{
+ bflush(obuck_fb);
+ fsync(obuck_fd);
+}
+
+static void
+obuck_get(oid_t oid)
+{
+ struct fastbuf *b = obuck_fb;
+
+ bucket_start = ((sh_off_t) oid) << OBUCK_SHIFT;
+ bflush(b);
+ if (sh_pread(obuck_fd, &obuck_hdr, sizeof(obuck_hdr), bucket_start) != sizeof(obuck_hdr))
+ obuck_broken("Short header read");
+ b->fdpos = bucket_start + sizeof(obuck_hdr);