.Other reading:
- <<internal,Internal structure>>
- <<bconfig,Configuring streams>>
+- <<fbexc,Exceptions>>
ucw/fastbuf.h
-------------
---------------
!!ucw/ff-binary.h
+
+Exceptions [[fbexc]]
+--------------------
+
+All standard back-ends and front-ends raise exceptions on errors. All such
+exceptions live in the `ucw.fb` subtree. The following exceptions are defined:
+
+`ucw.fb.eof`:: Unexpected end of file (e.g., when the @FB_DIE_ON_EOF flag is set)
+`ucw.fb.mmap`:: Memory mapping failed (e.g., the `mmap` syscall has failed)
+`ucw.fb.open`:: Opening failed (file does not exist and similar problems)
+`ucw.fb.read`:: Read error (e.g., the `read` syscall has failed or the stream is write-only)
+`ucw.fb.seek`:: Seek error (e.g., file not seekable, or a seek behind EOF)
+`ucw.fb.tmp`:: Creation of temporary file failed
+`ucw.fb.write`:: Write error (e.g., the `write` syscall has failed or the stream is read-only)
void NONRET bthrow(struct fastbuf *f, const char *id, const char *fmt, ...)
{
+ DBG("FB: throwing %s", full_id);
+ char full_id[16];
+ snprintf(full_id, sizeof(full_id), "ucw.fb.%s", id);
ASSERT(!(f->flags & FB_DEAD)); /* Only one bthrow() is allowed before bclose() */
- DBG("FB: throwing %s", id);
va_list args;
va_start(args, fmt);
if (!f->res)
die("Fastbuf %s error: %s", f->name ? : "<fb>", stk_vprintf(fmt, args));
f->flags |= FB_DEAD;
f->bptr = f->bstop = f->bufend; /* Reset the buffer to guard consecutive seek/read/write */
- trans_vthrow(id, f, fmt, args);
+ trans_vthrow(full_id, f, fmt, args);
}
int brefill(struct fastbuf *f, int allow_eof)
DBG("FB: refill");
ASSERT(!(f->flags & FB_DEAD) && f->buffer <= f->bstop && f->bstop <= f->bptr && f->bptr <= f->bufend);
if (!f->refill)
- bthrow(f, "fb.read", "Stream not readable");
+ bthrow(f, "read", "Stream not readable");
if (f->refill(f))
{
ASSERT(f->buffer <= f->bptr && f->bptr < f->bstop && f->bstop <= f->bufend);
{
ASSERT(f->buffer <= f->bptr && f->bptr == f->bstop && f->bstop <= f->bufend);
if (!allow_eof && (f->flags & FB_DIE_ON_EOF))
- bthrow(f, "fb.eof", "Unexpected EOF");
+ bthrow(f, "eof", "Unexpected EOF");
return 0;
}
}
DBG("FB: spout");
ASSERT(!(f->flags & FB_DEAD) && f->buffer <= f->bstop && f->bstop <= f->bptr && f->bptr <= f->bufend); /* Check write mode possibly with unflushed data */
if (!f->spout)
- bthrow(f, "fb.write", "Stream not writeable");
+ bthrow(f, "write", "Stream not writeable");
f->spout(f);
ASSERT(f->buffer <= f->bstop && f->bstop <= f->bptr && f->bptr <= f->bufend);
}
bflush(f);
DBG("FB: seeking to pos=%lld whence=%d %p %p %p %p", (long long)pos, whence, f->buffer, f->bstop, f->bptr, f->bufend);
if (!f->seek || !f->seek(f, pos, whence))
- bthrow(f, "fb.seek", "Stream not seekable");
+ bthrow(f, "seek", "Stream not seekable");
DBG("FB: seeked %p %p %p %p", f->buffer, f->bstop, f->bptr, f->bufend);
ASSERT(f->buffer <= f->bstop && f->bstop <= f->bptr && f->bptr <= f->bufend);
if (whence == SEEK_SET)
else if (pos != btell(f))
{
if (pos < 0)
- bthrow(f, "fb.seek", "Seek out of range");
+ bthrow(f, "seek", "Seek out of range");
do_seek(f, pos, SEEK_SET);
}
}
break;
case SEEK_END:
if (pos > 0)
- bthrow(f, "fb.seek", "Seek out of range");
+ bthrow(f, "seek", "Seek out of range");
do_seek(f, pos, SEEK_END);
break;
default:
total += k;
}
if (check && total && l)
- bthrow(f, "fb.read", "breadb: short read");
+ bthrow(f, "eof", "breadb: short read");
return total;
}
{
if (l == ~0U)
return;
- bthrow(f, "fb.read", "bbcopy: source exhausted");
+ bthrow(f, "eof", "bbcopy: source exhausted");
}
tavail = bdirect_write_prepare(t, &tptr);
n = MIN(l, favail);
ASSERT(af->record_len < 0 || !(size % af->record_len));
int res = write(af->fd, f->buffer, size);
if (res < 0)
- bthrow(f, "fb.write", "Error writing %s: %m", f->name);
+ bthrow(f, "write", "Error writing %s: %m", f->name);
if (res != size)
- bthrow(f, "fb.write", "Unexpected partial write to %s: written only %d bytes of %d", f->name, res, size);
+ bthrow(f, "write", "Unexpected partial write to %s: written only %d bytes of %d", f->name, res, size);
f->bptr = f->buffer;
}
}
{
int fd = ucw_open(name, O_WRONLY | O_CREAT | O_TRUNC | O_APPEND, 0666);
if (fd < 0)
- trans_throw("fb.open", NULL, "Cannot create %s: %m", name);
+ trans_throw("ucw.fb.open", NULL, "Cannot create %s: %m", name);
af = xmalloc_zero(sizeof(*af) + strlen(name));
af->fd = fd;
af->use_count = 1;
if (whence == SEEK_END)
pos += len;
if (pos < 0 || pos > len)
- bthrow(f, "fb.seek", "Seek out of range");
+ bthrow(f, "seek", "Seek out of range");
f->bptr = f->buffer + pos;
f->bstop = f->buffer;
f->pos = 0;
static void
fbbuf_spout(struct fastbuf *f)
{
- bthrow(f, "fb.write", "fbbuf: buffer overflow on write");
+ bthrow(f, "write", "fbbuf: buffer overflow on write");
}
void
if (!r->status)
return 0;
if (r->status < 0)
- bthrow(f, "fb.read", "Error reading %s: %s", f->name, strerror(r->returned_errno));
+ bthrow(f, "read", "Error reading %s: %s", f->name, strerror(r->returned_errno));
f->bptr = f->buffer = r->buffer;
f->bstop = f->bufend = f->buffer + r->status;
f->pos += r->status;
asio_sync(F->io_queue);
DBG("FB-DIRECT: Truncating at %llu", (long long)f->pos);
if (ucw_ftruncate(F->fd, f->pos) < 0)
- bthrow(f, "fb.write", "Error truncating %s: %m", f->name);
+ bthrow(f, "write", "Error truncating %s: %m", f->name);
}
else
asio_submit(r);
int l = read(F->fd, f->buffer, MIN(skip, blen));
if (unlikely(l <= 0))
if (l < 0)
- bthrow(f, "fb.read", "Error reading %s: %m", f->name);
+ bthrow(f, "read", "Error reading %s: %m", f->name);
else
{
F->wpos -= skip;
/* Do lseek() */
F->wpos = f->pos + (f->buffer - f->bptr);
if (ucw_seek(F->fd, F->wpos, SEEK_SET) < 0)
- bthrow(f, "fb.read", "Error seeking %s: %m", f->name);
+ bthrow(f, "read", "Error seeking %s: %m", f->name);
}
/* Read (part of) buffer */
do
{
int l = read(F->fd, read_ptr, read_len);
if (unlikely(l < 0))
- bthrow(f, "fb.read", "Error reading %s: %m", f->name);
+ bthrow(f, "read", "Error reading %s: %m", f->name);
if (!l)
if (unlikely(read_ptr < f->bptr))
goto eof;
{
/* Do delayed lseek() if needed */
if (FB_FILE(f)->wpos != f->pos && ucw_seek(FB_FILE(f)->fd, f->pos, SEEK_SET) < 0)
- bthrow(f, "fb.write", "Error seeking %s: %m", f->name);
+ bthrow(f, "write", "Error seeking %s: %m", f->name);
int l = f->bptr - f->buffer;
byte *c = f->buffer;
{
int z = write(FB_FILE(f)->fd, c, l);
if (z <= 0)
- bthrow(f, "fb.write", "Error writing %s: %m", f->name);
+ bthrow(f, "write", "Error writing %s: %m", f->name);
l -= z;
c += z;
}
case SEEK_END: ;
ucw_off_t l = ucw_seek(FB_FILE(f)->fd, pos, SEEK_END);
if (l < 0)
- bthrow(f, "fb.seek", "Error seeking %s: %m", f->name);
+ bthrow(f, "seek", "Error seeking %s: %m", f->name);
FB_FILE(f)->wpos = f->pos = l;
FB_FILE(f)->wlen = 0;
return 1;
if (whence == SEEK_END)
pos += len;
if (pos < 0 || pos > len)
- bthrow(b, "fb.seek", "Seek out of range");
+ bthrow(b, "seek", "Seek out of range");
b->bptr = b->buffer + pos;
b->bstop = b->buffer;
b->pos = 0;
int max = MIN(FB_LIMFD(f)->limit - f->pos, f->bufend - f->buffer);
int l = read(FB_LIMFD(f)->fd, f->buffer, max);
if (l < 0)
- bthrow(f, "fb.read", "Error reading %s: %m", f->name);
+ bthrow(f, "read", "Error reading %s: %m", f->name);
f->bstop = f->buffer + l;
f->pos += l;
return l;
FB_MEM(f)->block = NULL;
return 1;
}
- bthrow(f, "fb.seek", "fbmem_seek to invalid offset");
+ bthrow(f, "seek", "fbmem_seek to an invalid offset");
}
static void
if (f->buffer == (byte *) MAP_FAILED)
{
f->buffer = NULL;
- bthrow(f, "fb.mmap", "mmap(%s): %m", f->name);
+ bthrow(f, "mmap", "mmap(%s): %m", f->name);
}
#ifdef MADV_SEQUENTIAL
if (ll > CPU_PAGE_SIZE)
{
F->file_extend = ALIGN_TO(F->file_extend + mmap_extend_size, (ucw_off_t)CPU_PAGE_SIZE);
if (ucw_ftruncate(F->fd, F->file_extend))
- bthrow(f, "fb.write", "ftruncate(%s): %m", f->name);
+ bthrow(f, "write", "ftruncate(%s): %m", f->name);
}
bfmm_map_window(f);
f->bstop = f->bptr;
if (!(f->flags & FB_DEAD) &&
F->file_extend > F->file_size &&
ucw_ftruncate(F->fd, F->file_size))
- bthrow(f, "fb.write", "ftruncate(%s): %m", f->name);
+ bthrow(f, "write", "ftruncate(%s): %m", f->name);
bclose_file_helper(f, F->fd, F->is_temp_file);
xfree(f);
}
return fb;
case FB_MMAP:
if (!~mode && (int)(mode = fcntl(fd, F_GETFL)) < 0)
- trans_throw("fb.open", NULL, "Cannot get flags of fd %d: %m", fd);
+ trans_throw("ucw.fb.open", NULL, "Cannot get flags of fd %d: %m", fd);
return bfmmopen_internal(fd, name, mode);
default:
ASSERT(0);
if (try)
return NULL;
else
- trans_throw("fb.open", NULL, "Unable to %s file %s: %m", (mode & O_CREAT) ? "create" : "open", name);
+ trans_throw("ucw.fb.open", NULL, "Unable to %s file %s: %m", (mode & O_CREAT) ? "create" : "open", name);
struct fastbuf *fb = bopen_fd_internal(fd, params, mode, name);
ASSERT(fb);
if (mode & O_APPEND)
int was_temp = bconfig(fb, BCONFIG_IS_TEMP_FILE, 0);
ASSERT(was_temp == 1);
if (rename(fb->name, name))
- bthrow(fb, "fb.tmp", "Cannot rename %s to %s: %m", fb->name, name);
+ bthrow(fb, "tmp", "Cannot rename %s to %s: %m", fb->name, name);
bclose(fb);
}