summaryrefslogtreecommitdiff
path: root/libstore/rdwr.c
diff options
context:
space:
mode:
authorRoland McGrath <roland@gnu.org>1999-09-13 07:38:25 +0000
committerRoland McGrath <roland@gnu.org>1999-09-13 07:38:25 +0000
commit2a783565dd9ce52c840fd7c6271717306ead1612 (patch)
tree1e2acc67654fb3e99a49669b3d6e8a664b122a3e /libstore/rdwr.c
parent2a061ebb71bf7a93d5e7ed71fa13dd7005745965 (diff)
1999-09-09 Roland McGrath <roland@baalperazim.frob.com>
* rdwr.c (store_write, store_read): Carefully avoid scaling run lengths from blocks to bytes except when we're already sure the run's size in bytes won't overflow size_t.
Diffstat (limited to 'libstore/rdwr.c')
-rw-r--r--libstore/rdwr.c54
1 files changed, 28 insertions, 26 deletions
diff --git a/libstore/rdwr.c b/libstore/rdwr.c
index c5059536..c9163618 100644
--- a/libstore/rdwr.c
+++ b/libstore/rdwr.c
@@ -89,6 +89,8 @@ store_next_run (struct store *store, struct store_run *runs_end,
return 1;
}
+#include <assert.h>
+
/* Write LEN bytes from BUF to STORE at ADDR. Returns the amount written
in AMOUNT. ADDR is in BLOCKS (as defined by STORE->block_size). */
error_t
@@ -105,10 +107,12 @@ store_write (struct store *store,
if (store->flags & STORE_READONLY)
return EROFS; /* XXX */
+ assert ((len & (block_shift - 1)) == 0);
+
addr = store_find_first_run (store, addr, &run, &runs_end, &base, &index);
if (addr < 0)
err = EIO;
- else if ((run->length << block_shift) >= len)
+ else if ((len >> block_shift) <= run->length)
/* The first run has it all... */
err = (*write)(store, base + run->start + addr, index, buf, len, amount);
else
@@ -131,22 +135,25 @@ store_write (struct store *store,
/* Ok, we can write in this run, at least a bit. */
{
mach_msg_type_number_t seg_written;
- off_t run_len = (run->length << block_shift);
- try = run_len > len ? len : run_len;
+ if ((len >> block_shift) <= run->length)
+ try = len;
+ else
+ try = run->length << block_shift;
+
err = (*write)(store, base + run->start, index, buf, try,
&seg_written);
if (err)
break; /* Ack */
-
written += seg_written;
+
+ if (seg_written < try)
+ break; /* Didn't use up the run, we're done. */
+
len -= seg_written;
if (len == 0)
break; /* Nothing left to write! */
- if (seg_written < run_len)
- break; /* Didn't use up the run, we're done. */
-
buf += seg_written;
}
}
@@ -157,7 +164,7 @@ store_write (struct store *store,
return err;
}
-/* Read AMOUNT bytes from STORE at ADDR into BUF & LEN (which following the
+/* Read AMOUNT bytes from STORE at ADDR into BUF & LEN (which follows the
usual mach buffer-return semantics) to STORE at ADDR. ADDR is in BLOCKS
(as defined by STORE->block_size). */
error_t
@@ -165,7 +172,7 @@ store_read (struct store *store,
off_t addr, size_t amount, void **buf, size_t *len)
{
size_t index;
- off_t base, first_run_size;
+ off_t base;
struct store_run *run, *runs_end;
int block_shift = store->log2_block_size;
store_read_meth_t read = store->class->read;
@@ -174,14 +181,11 @@ store_read (struct store *store,
if (addr < 0 || run->start < 0)
return EIO; /* Reading from a hole. */
- first_run_size = (run->length << block_shift);
- if (first_run_size >= amount)
+ assert ((amount & (block_shift - 1)) == 0);
+
+ if ((amount >> block_shift) <= run->length)
/* The first run has it all... */
- {
- if (first_run_size < amount)
- amount = first_run_size;
- return (*read)(store, base + run->start + addr, index, amount, buf, len);
- }
+ return (*read) (store, base + run->start + addr, index, amount, buf, len);
else
/* ARGH, we've got to split up the read ... This isn't fun. */
{
@@ -233,22 +237,20 @@ store_read (struct store *store,
buf_end = whole_buf;
- err = seg_read (base + run->start + addr, first_run_size, &all);
+ err = seg_read (base + run->start + addr,
+ run->length << block_shift, &all);
while (!err && all && amount > 0
&& store_next_run (store, runs_end, &run, &base, &index))
{
- off_t run_addr = run->start;
- off_t run_blocks = run->length;
-
- if (run_addr < 0)
+ if (run->start < 0)
/* A hole! Can't read here. Must stop. */
break;
else
- {
- off_t run_len = (run_blocks << block_shift);
- off_t seg_len = run_len > amount ? amount : run_len;
- err = seg_read (base + run_addr, seg_len, &all);
- }
+ err = seg_read (base + run->start,
+ (amount >> block_shift) <= run->length
+ ? amount /* This run has the rest. */
+ : (run->length << block_shift), /* Whole run. */
+ &all);
}
/* The actual amount read. */