summaryrefslogtreecommitdiff
path: root/libstore/rdwr.c
diff options
context:
space:
mode:
authorMiles Bader <miles@gnu.org>1996-01-16 20:37:09 +0000
committerMiles Bader <miles@gnu.org>1996-01-16 20:37:09 +0000
commitae3480ec52454855488ddf905d957bc8929e23a4 (patch)
tree0ea6b27109c063b9e777e1382695171e0995df22 /libstore/rdwr.c
parent57d14b26dfd8654cfbe78de37faed37940590450 (diff)
Formerly rdwr.c.~6~
Diffstat (limited to 'libstore/rdwr.c')
-rw-r--r--libstore/rdwr.c46
1 files changed, 32 insertions, 14 deletions
diff --git a/libstore/rdwr.c b/libstore/rdwr.c
index 931538bf..64671241 100644
--- a/libstore/rdwr.c
+++ b/libstore/rdwr.c
@@ -56,7 +56,7 @@ store_find_first_run (struct store *store, off_t addr,
}
/* 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). */
+ in AMOUNT. ADDR is in BLOCKS (as defined by STORE->block_size). */
error_t
store_write (struct store *store,
off_t addr, char *buf, size_t len, size_t *amount)
@@ -129,6 +129,9 @@ store_write (struct store *store,
return err;
}
+/* Read AMOUNT bytes from STORE at ADDR into BUF & LEN (which following the
+ usual mach buffer-return semantics) to STORE at ADDR. ADDR is in BLOCKS
+ (as defined by STORE->block_size). */
error_t
store_read (struct store *store,
off_t addr, size_t amount, char **buf, size_t *len)
@@ -144,16 +147,17 @@ store_read (struct store *store,
/* The first run has it all... */
err = (*read)(store, runs[0] + addr, amount, buf, len);
else
- /* ARGH, we've got to split up the write ... This isn't fun. */
+ /* ARGH, we've got to split up the read ... This isn't fun. */
{
int all;
/* WHOLE_BUF and WHOLE_BUF_LEN will point to a buff that's large enough
to hold the entire request. This is initially whatever the user
passed in, but we'll change it as necessary. */
char *whole_buf = *buf, *buf_end = whole_buf;
- size_t whole_buf_len = *len, buf_left = whole_buf_len;
+ size_t whole_buf_len = *len;
+ int block_shift = store->log2_block_size;
- /* Read LEN bytes from the store address ADDR into BUF_LEN. BUF_LEN
+ /* Read LEN bytes from the store address ADDR into BUF_END. BUF_END
and AMOUNT are adjusted by the amount actually read. Whether or not
the amount read is the same as what was request is returned in ALL. */
inline error_t seg_read (off_t addr, off_t len, int *all)
@@ -177,17 +181,18 @@ store_read (struct store *store,
return err;
}
- if (whole_buf_left < amount)
+ if (whole_buf_len < amount)
/* Not enough room in the user's buffer to hold everything, better
make room. */
{
- whole_buf_left = amount;
- err = vm_allocate (mach_task_self (), &whole_buf, amount, 1);
+ whole_buf_len = amount;
+ err = vm_allocate (mach_task_self (),
+ (vm_address_t *)&whole_buf, amount, 1);
if (err)
return err; /* Punt early, there's nothing to clean up. */
}
- err = seg_read (runs[0] + addr, runs[1], &all);
+ err = seg_read (runs[0] + addr, runs[1] << block_shift, &all);
if (!err && all)
{
@@ -198,7 +203,7 @@ store_read (struct store *store,
off_t run_blocks = runs[1];
if (run_addr < 0)
- /* A hole! Can't write here. Must stop. */
+ /* A hole! Can't read here. Must stop. */
break;
else if (amount == 0)
break;
@@ -213,14 +218,27 @@ store_read (struct store *store,
}
}
- /* The actual amount written. */
- *len = whole_buf_len - amount; XXXXXXXXX
+ /* The actual amount read. */
+ *len = whole_buf + whole_buf_len - buf_end;
+ if (*len > 0)
+ err = 0; /* Return a short read instead of an error. */
/* Deallocate any amount of WHOLE_BUF we didn't use. */
if (whole_buf != *buf)
- {
- *buf = whole_buf;
- }
+ if (err)
+ vm_deallocate (mach_task_self (),
+ (vm_address_t)whole_buf, whole_buf_len);
+ else
+ {
+ vm_size_t unused = whole_buf_len - round_page (*len);
+ if (unused)
+ vm_deallocate (mach_task_self (),
+ (vm_address_t)whole_buf + whole_buf_len - unused,
+ unused);
+ *buf = whole_buf;
+ }
}
+
+ return err;
}