summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ext2fs/storeinfo.c187
1 files changed, 63 insertions, 124 deletions
diff --git a/ext2fs/storeinfo.c b/ext2fs/storeinfo.c
index 419809c9..a73d26f3 100644
--- a/ext2fs/storeinfo.c
+++ b/ext2fs/storeinfo.c
@@ -20,6 +20,7 @@
#include <string.h>
#include <netinet/in.h> /* htonl */
+#include <hurd/store.h>
#include "ext2fs.h"
@@ -34,142 +35,80 @@ diskfs_S_file_get_storage_info (struct protid *cred,
char **data, mach_msg_type_number_t *data_len)
{
error_t err = 0;
- size_t name_len =
- (diskfs_device_name && *diskfs_device_name)
- ? strlen (diskfs_device_name) + 1 : 0;
- /* True when we've allocated memory for the corresponding vector. */
- int al_ports = 0, al_ints = 0, al_offsets = 0, al_data = 0;
-
- if (! cred)
- return EOPNOTSUPP;
-
-#define ENSURE_MEM(v, vl, alp, num) \
- if (!err && *vl < num) \
- { \
- err = vm_allocate (mach_task_self (), \
- (vm_address_t *)v, num * sizeof (**v), 1); \
- if (! err) \
- { \
- *vl = num; \
- alp = 1; \
- } \
- }
-
- /* Two longs. */
-#define MISC_LEN (sizeof (long) * 2)
-
- ENSURE_MEM (ports, num_ports, al_ports, 1);
- ENSURE_MEM (ints, num_ints, al_ints, 6);
- ENSURE_MEM (data, data_len, al_data, name_len + MISC_LEN);
- /* OFFSETS is more complex, and done below. */
-
- if (! err)
+ unsigned num_fs_blocks;
+ struct store *file_store;
+ struct store_run *runs, *run = 0;
+ block_t index = 0;
+ size_t num_runs = 0, runs_alloced = 10;
+ struct node *node = cred->po->np;
+
+ runs = malloc (runs_alloced * sizeof (struct store_run));
+ if (! runs)
+ return ENOMEM;
+
+ mutex_lock (&node->lock);
+
+ /* NUM_FS_BLOCKS counts down the blocks in the file that we've not
+ enumerated yet; when it hits zero, we can stop. */
+ num_fs_blocks = node->dn_stat.st_blocks >> log2_stat_blocks_per_fs_block;
+ while (num_fs_blocks-- > 0)
{
- block_t index = 0;
- unsigned num_fs_blocks;
- off_t *run = *num_offsets ? *offsets : 0;
- struct node *node = cred->po->np;
-
- mutex_lock (&node->lock);
+ block_t block;
- num_fs_blocks = node->dn_stat.st_blocks >> log2_stat_blocks_per_fs_block;
- while (num_fs_blocks > 0)
+ err = ext2_getblk (node, index++, 0, &block);
+ if (err == EINVAL)
+ /* Either a hole, or past the end of the file. */
{
- block_t block;
-
- err = ext2_getblk (node, index++, 0, &block);
- if (err == EINVAL)
- /* Either a hole, or past the end of the file. */
- {
- block = 0;
- err = 0;
- }
- else if (err)
- break;
-
- block <<= log2_dev_blocks_per_fs_block;
- if (!run
- || ((block && run[0] >= 0) /* Neither is a hole and... */
- ? (block != run[0] + run[1]) /* BLOCK doesn't follow RUN */
- : (block || run[0] >= 0))) /* or one is, but not both */
- /* Add a new run. */
+ block = 0;
+ err = 0;
+ }
+ else if (err)
+ break;
+
+ block <<= log2_dev_blocks_per_fs_block;
+ if (num_runs == 0
+ || ((block && run->start >= 0) /* Neither is a hole and... */
+ ? (block != run->start + run->length) /* BLOCK doesn't follow RUN */
+ : (block || run->start >= 0))) /* or one is, but not both */
+ /* Add a new run. */
+ {
+ if (num_runs == runs_alloced)
+ /* Make some more space in RUNS. */
{
- run += 2;
- if (!run || run >= *offsets + *num_offsets)
- if (al_offsets)
- /* We've already allocated space for offsets; add a new
- page to the end of it. */
- {
- err =
- vm_allocate (mach_task_self (),
- (vm_address_t *)&run, vm_page_size, 0);
- if (err)
- break;
- *num_offsets += vm_page_size / sizeof (off_t);
- }
- else
- /* We've run out the space passed for inline offsets by
- the caller, so allocate our own memory and copy
- anything we've already stored. */
- {
- off_t *old = *offsets;
- size_t old_len = *num_offsets;
- err =
- vm_allocate (mach_task_self (),
- (vm_address_t *)offsets,
- old_len * sizeof (off_t) + vm_page_size, 1);
- if (err)
- break;
- if (old_len)
- bcopy (old, *offsets, old_len * sizeof (off_t));
- *num_offsets = old_len + vm_page_size / sizeof (off_t);
- run = *offsets;
- al_offsets = 1;
- }
-
- run[0] = block ?: -1; /* -1 means a hole in OFFSETS */
- run[1] = 0; /* will get extended just below */
+ struct store_run *new;
+ runs_alloced *= 2;
+ new = realloc (runs, runs_alloced * sizeof (struct store_run));
+ if (! new)
+ {
+ err = ENOMEM;
+ break;
+ }
+ runs = new;
}
- /* Increase the size of the current run by one filesystem block. */
- run[1] += 1 << log2_dev_blocks_per_fs_block;
-
- num_fs_blocks--;
+ run = runs + num_runs++;
+ run->start = block ?: -1; /* -1 means a hole in OFFSETS */
+ run->length = 0; /* will get extended just below */
}
- /* Fill in PORTS. Root gets device port, everyone else, nothing. */
- (*ports)[0] = diskfs_isuid (0, cred) ? diskfs_device : MACH_PORT_NULL;
- *ports_type = MACH_MSG_TYPE_COPY_SEND;
-
- /* Fill in INTS. */
- (*ints)[0] = STORAGE_DEVICE; /* type */
- (*ints)[1] = 0; /* flags */
- (*ints)[2] = diskfs_device_block_size; /* block size */
- (*ints)[3] = (run - *offsets) / 2; /* num runs */
- (*ints)[4] = name_len;
- (*ints)[5] = MISC_LEN;
-
- /* Fill in DATA. */
- if (name_len)
- strcpy (*data, diskfs_device_name);
- /* The following must be kept in sync with MISC_LEN. */
- ((long *)(*data + name_len))[0] = htonl (node->cache_id);
- ((long *)(*data + name_len))[1] =
- htonl (dino (node->cache_id)->i_translator);
-
- mutex_unlock (&node->lock);
+ /* Increase the size of the current run by one filesystem block. */
+ run->length += 1 << log2_dev_blocks_per_fs_block;
}
- if (err)
+ mutex_unlock (&node->lock);
+
+ if (! err)
+ err = store_clone (store, &file_store);
+ if (! err)
{
-#define DISCARD_MEM(v, vl, alp) \
- if (alp) \
- vm_deallocate (mach_task_self (), (vm_address_t)*v, *vl * sizeof **v);
- DISCARD_MEM (ports, num_ports, al_ports);
- DISCARD_MEM (ints, num_ints, al_ints);
- DISCARD_MEM (offsets, num_offsets, al_offsets);
- DISCARD_MEM (data, data_len, al_data);
+ err = store_remap (file_store, runs, num_runs, &file_store);
+ if (! err)
+ err = store_return (file_store, ports, num_ports, ints, num_ints,
+ offsets, num_offsets, data, data_len);
+ store_free (file_store);
}
+ free (runs);
+
return err;
}