diff options
-rw-r--r-- | libstore/rdwr.c | 54 |
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. */ |