1.1 --- a/Makefile Thu Apr 08 23:55:47 2021 +0200
1.2 +++ b/Makefile Sun Apr 11 19:34:07 2021 +0200
1.3 @@ -2,8 +2,14 @@
1.4 L4DIR ?= $(PKGDIR)/../..
1.5
1.6 TARGET = \
1.7 - dstest_block_client dstest_host_client dstest_pipe_client dstest_test_client \
1.8 - dstest_block_server dstest_host_server dstest_pipe_server dstest_test_server
1.9 + dstest_block_client dstest_block_client_simple \
1.10 + dstest_host_client \
1.11 + dstest_pipe_client \
1.12 + dstest_test_client \
1.13 + dstest_block_server \
1.14 + dstest_host_server \
1.15 + dstest_pipe_server \
1.16 + dstest_test_server
1.17
1.18 MODE = static
1.19
1.20 @@ -45,6 +51,8 @@
1.21
1.22 PLAIN_SRC_CC_dstest_block_client = tests/dstest_block_client.cc client/file.cc
1.23
1.24 +PLAIN_SRC_CC_dstest_block_client_simple = tests/dstest_block_client_simple.cc client/client.cc client/file.cc
1.25 +
1.26 PLAIN_SRC_CC_dstest_host_client = tests/dstest_host_client.cc client/file.cc
1.27
1.28 PLAIN_SRC_CC_dstest_pipe_client = tests/dstest_pipe_client.cc client/file.cc
1.29 @@ -97,6 +105,11 @@
1.30 $(PLAIN_SRC_CC_dstest_block_client) \
1.31 $(COMMON_SRC_CC)
1.32
1.33 +SRC_CC_dstest_block_client_simple = \
1.34 + $(CLIENT_INTERFACES_SRC_CC) \
1.35 + $(PLAIN_SRC_CC_dstest_block_client_simple) \
1.36 + $(COMMON_SRC_CC)
1.37 +
1.38 SRC_CC_dstest_host_client = \
1.39 $(CLIENT_INTERFACES_SRC_CC) \
1.40 $(PLAIN_SRC_CC_dstest_host_client) \
1.41 @@ -145,6 +158,8 @@
1.42
1.43 $(PLAIN_SRC_CC_dstest_block_client): $(CLIENT_INTERFACES_SRC_CC)
1.44
1.45 +$(PLAIN_SRC_CC_dstest_block_client_simple): $(CLIENT_INTERFACES_SRC_CC)
1.46 +
1.47 $(PLAIN_SRC_CC_dstest_host_client): $(CLIENT_INTERFACES_SRC_CC)
1.48
1.49 $(PLAIN_SRC_CC_dstest_pipe_client): $(CLIENT_INTERFACES_SRC_CC)
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2.2 +++ b/client/client.cc Sun Apr 11 19:34:07 2021 +0200
2.3 @@ -0,0 +1,390 @@
2.4 +/*
2.5 + * Filesystem client functions.
2.6 + *
2.7 + * Copyright (C) 2018, 2019, 2020, 2021 Paul Boddie <paul@boddie.org.uk>
2.8 + *
2.9 + * This program is free software; you can redistribute it and/or
2.10 + * modify it under the terms of the GNU General Public License as
2.11 + * published by the Free Software Foundation; either version 2 of
2.12 + * the License, or (at your option) any later version.
2.13 + *
2.14 + * This program is distributed in the hope that it will be useful,
2.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
2.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2.17 + * GNU General Public License for more details.
2.18 + *
2.19 + * You should have received a copy of the GNU General Public License
2.20 + * along with this program; if not, write to the Free Software
2.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor,
2.22 + * Boston, MA 02110-1301, USA
2.23 + */
2.24 +
2.25 +#include <l4/re/env.h>
2.26 +
2.27 +#include <stdio.h>
2.28 +#include <stdlib.h>
2.29 +
2.30 +#include "client.h"
2.31 +
2.32 +
2.33 +
2.34 +/* Default size of pipe regions. */
2.35 +
2.36 +const offset_t DEFAULT_PIPE_SIZE = 4096;
2.37 +
2.38 +
2.39 +
2.40 +/* Close a filesystem object. */
2.41 +
2.42 +void client_close(file_t *file)
2.43 +{
2.44 + if (file == NULL)
2.45 + return;
2.46 +
2.47 + file_close(file);
2.48 + free(file);
2.49 +}
2.50 +
2.51 +
2.52 +
2.53 +/* Open a filesystem object. */
2.54 +
2.55 +file_t *client_open(const char *name, flags_t flags)
2.56 +{
2.57 + file_t *file = (file_t *) malloc(sizeof(file_t));
2.58 +
2.59 + if (file == NULL)
2.60 + return NULL;
2.61 +
2.62 + l4_cap_idx_t server = l4re_env_get_cap("server");
2.63 +
2.64 + if (file_open(file, name, flags, server))
2.65 + {
2.66 + free(file);
2.67 + return NULL;
2.68 + }
2.69 +
2.70 + return file;
2.71 +}
2.72 +
2.73 +
2.74 +
2.75 +/* Open a pipe object. */
2.76 +
2.77 +long client_pipe(file_t **reader, file_t **writer)
2.78 +{
2.79 + *reader = (file_t *) malloc(sizeof(file_t));
2.80 +
2.81 + if (*reader == NULL)
2.82 + return -L4_ENOMEM;
2.83 +
2.84 + *writer = (file_t *) malloc(sizeof(file_t));
2.85 +
2.86 + if (*writer == NULL)
2.87 + {
2.88 + free(*reader);
2.89 + return -L4_ENOMEM;
2.90 + }
2.91 +
2.92 + l4_cap_idx_t server = l4re_env_get_cap("pipes");
2.93 +
2.94 + long err = pipe_open(DEFAULT_PIPE_SIZE, *reader, *writer, server);
2.95 +
2.96 + if (err)
2.97 + {
2.98 + free(*reader);
2.99 + free(*writer);
2.100 + }
2.101 +
2.102 + return err;
2.103 +}
2.104 +
2.105 +
2.106 +
2.107 +/* Flush data conditionally to the filesystem object. */
2.108 +
2.109 +static long _flush(file_t *file, offset_t position)
2.110 +{
2.111 + long err;
2.112 +
2.113 + /* Where the position is outside the current region, re-map. */
2.114 +
2.115 + if ((position < file->start_pos) || (position >= file->end_pos))
2.116 + {
2.117 + if (file->can_mmap)
2.118 + {
2.119 + if (file_mmap(file, position, file_span(file)))
2.120 + return -L4_EIO;
2.121 + }
2.122 +
2.123 + /* Strict conditions for region navigation in pipes. */
2.124 +
2.125 + else if ((position != file->end_pos) ||
2.126 + (client_next_region(file) == NULL))
2.127 + return -L4_EIO;
2.128 + }
2.129 +
2.130 + /* Otherwise, flush any written data in the current region and update the
2.131 + file size details. */
2.132 +
2.133 + else
2.134 + {
2.135 + err = client_flush(file);
2.136 +
2.137 + if (err)
2.138 + return err;
2.139 + }
2.140 +
2.141 + /* Update the current data offset. */
2.142 +
2.143 + file->data_current = position - file->start_pos;
2.144 + return L4_EOK;
2.145 +}
2.146 +
2.147 +
2.148 +
2.149 +/* Flush data explicitly to the filesystem object. */
2.150 +
2.151 +long client_flush(file_t *file)
2.152 +{
2.153 + if (file == NULL)
2.154 + return -L4_EINVAL;
2.155 +
2.156 + /* Flush and retain most buffer settings. */
2.157 +
2.158 + return file_flush(file);
2.159 +}
2.160 +
2.161 +
2.162 +
2.163 +/* Map a memory region to a file. */
2.164 +
2.165 +void *client_mmap(file_t *file, offset_t position, offset_t length)
2.166 +{
2.167 + if ((file == NULL) || (file_mmap(file, position, length)))
2.168 + return NULL;
2.169 +
2.170 + return file->memory;
2.171 +}
2.172 +
2.173 +
2.174 +
2.175 +/* Obtain the current region of a pipe. */
2.176 +
2.177 +void *client_current_region(file_t *file)
2.178 +{
2.179 + if ((file == NULL) || (pipe_current(file)))
2.180 + return NULL;
2.181 +
2.182 + return file->memory;
2.183 +}
2.184 +
2.185 +
2.186 +
2.187 +/* Obtain the next region of a pipe. */
2.188 +
2.189 +void *client_next_region(file_t *file)
2.190 +{
2.191 + if ((file == NULL) || (pipe_next(file)))
2.192 + return NULL;
2.193 +
2.194 + return file->memory;
2.195 +}
2.196 +
2.197 +
2.198 +
2.199 +/* Read from the filesystem object into the buffer provided. */
2.200 +
2.201 +offset_t client_read(file_t *file, void *buf, offset_t count)
2.202 +{
2.203 + if (file == NULL)
2.204 + return 0;
2.205 +
2.206 + /* Amount available in the descriptor buffer already. */
2.207 +
2.208 + offset_t available = file_data_available(file);
2.209 + offset_t to_transfer, total = 0;
2.210 +
2.211 + while (count > 0)
2.212 + {
2.213 + /* If there is no data, try and obtain more data. */
2.214 +
2.215 + if (!available)
2.216 + {
2.217 + /* Flush any unwritten data, preparing to read from the file position at
2.218 + the end of the data, and returning if no new data is available. */
2.219 +
2.220 + if (_flush(file, file_data_end_position(file)))
2.221 + break;
2.222 +
2.223 + available = file_data_available(file);
2.224 +
2.225 + if (!available)
2.226 + break;
2.227 + }
2.228 +
2.229 + /* Transfer data into the supplied buffer. */
2.230 +
2.231 + to_transfer = available <= count ? available : count;
2.232 +
2.233 + file_data_read(file, (char *) buf, to_transfer);
2.234 +
2.235 + /* Update counters. */
2.236 +
2.237 + available -= to_transfer;
2.238 +
2.239 + count -= to_transfer;
2.240 + total += to_transfer;
2.241 +
2.242 + buf = ((char *) buf + to_transfer);
2.243 + }
2.244 +
2.245 + return total;
2.246 +}
2.247 +
2.248 +
2.249 +
2.250 +/* Ensure that the buffer can provide the needed data. */
2.251 +
2.252 +offset_t client_seek(file_t *file, offset_t offset, int whence)
2.253 +{
2.254 + if (file == NULL)
2.255 + return 0;
2.256 +
2.257 + offset_t position, current = file_data_current_position(file), change;
2.258 +
2.259 + switch (whence)
2.260 + {
2.261 + case SEEK_SET:
2.262 + position = offset;
2.263 + break;
2.264 +
2.265 + case SEEK_CUR:
2.266 + position = current + offset;
2.267 + break;
2.268 +
2.269 + case SEEK_END:
2.270 + position = file->size + offset;
2.271 + break;
2.272 +
2.273 + default:
2.274 + /* NOTE: Set errno to EINVAL. */
2.275 + return -1;
2.276 + }
2.277 +
2.278 + /* Retain the current position if unchanged. */
2.279 +
2.280 + if (position == current)
2.281 + return position;
2.282 +
2.283 + /* Move forward in the file. */
2.284 +
2.285 + if (position > current)
2.286 + {
2.287 + change = position - current;
2.288 +
2.289 + /* Move towards the end of available data.
2.290 + Request new data if not enough is available. */
2.291 +
2.292 + if (change <= file_data_available(file))
2.293 + {
2.294 + file->data_current += change;
2.295 + return position;
2.296 + }
2.297 + }
2.298 +
2.299 + /* Move backward in the file. */
2.300 +
2.301 + else
2.302 + {
2.303 + change = current - position;
2.304 +
2.305 + /* Move towards the start of available data.
2.306 + Request new data if moving beyond the start of the data. */
2.307 +
2.308 + if (change <= file->data_current)
2.309 + {
2.310 + file->data_current -= change;
2.311 + return position;
2.312 + }
2.313 + }
2.314 +
2.315 + /* Handle unwritten data and reset the buffer for reading. */
2.316 +
2.317 + _flush(file, position);
2.318 + return position;
2.319 +}
2.320 +
2.321 +
2.322 +
2.323 +long client_tell(file_t *file)
2.324 +{
2.325 + if (file == NULL)
2.326 + return -L4_EINVAL;
2.327 +
2.328 + return file_data_current_position(file);
2.329 +}
2.330 +
2.331 +
2.332 +
2.333 +/* Write to the filesystem object from the buffer provided. */
2.334 +
2.335 +offset_t client_write(file_t *file, const void *buf, offset_t count)
2.336 +{
2.337 + if (file == NULL)
2.338 + return 0;
2.339 +
2.340 + /* Attempt to ensure that the file can accept the amount of data to be
2.341 + written. This may not resize to the needed amount if a file has a fixed
2.342 + size, but data will still be written to any available space. */
2.343 +
2.344 + offset_t needed_size = file_data_current_position(file) + count;
2.345 +
2.346 + if (file->size < needed_size)
2.347 + {
2.348 + file_resize(file, needed_size);
2.349 +
2.350 + if (file->size < needed_size)
2.351 + count = file->size - file_data_current_position(file);
2.352 + }
2.353 +
2.354 + /* Space remaining in the descriptor buffer. */
2.355 +
2.356 + offset_t space = file_data_space(file);
2.357 + offset_t to_transfer, total = 0;
2.358 +
2.359 + while (count > 0)
2.360 + {
2.361 + /* If no space is available, try and send data, reset the buffer. */
2.362 +
2.363 + if (!space)
2.364 + {
2.365 + /* Flush any unwritten data and continue writing from the current data
2.366 + position. */
2.367 +
2.368 + if (_flush(file, file_data_current_position(file)))
2.369 + break;
2.370 +
2.371 + space = file_data_space(file);
2.372 + }
2.373 +
2.374 + /* Transfer data into the supplied buffer. */
2.375 +
2.376 + to_transfer = space <= count ? space : count;
2.377 +
2.378 + file_data_write(file, (char *) buf, to_transfer);
2.379 +
2.380 + /* Update counters. */
2.381 +
2.382 + space -= to_transfer;
2.383 +
2.384 + count -= to_transfer;
2.385 + total += to_transfer;
2.386 +
2.387 + buf = ((char *) buf + to_transfer);
2.388 + }
2.389 +
2.390 + return total;
2.391 +}
2.392 +
2.393 +// vim: tabstop=2 expandtab shiftwidth=2
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3.2 +++ b/client/client.h Sun Apr 11 19:34:07 2021 +0200
3.3 @@ -0,0 +1,56 @@
3.4 +/*
3.5 + * Filesystem client functions.
3.6 + *
3.7 + * Copyright (C) 2018, 2019, 2020, 2021 Paul Boddie <paul@boddie.org.uk>
3.8 + *
3.9 + * This program is free software; you can redistribute it and/or
3.10 + * modify it under the terms of the GNU General Public License as
3.11 + * published by the Free Software Foundation; either version 2 of
3.12 + * the License, or (at your option) any later version.
3.13 + *
3.14 + * This program is distributed in the hope that it will be useful,
3.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
3.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3.17 + * GNU General Public License for more details.
3.18 + *
3.19 + * You should have received a copy of the GNU General Public License
3.20 + * along with this program; if not, write to the Free Software
3.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor,
3.22 + * Boston, MA 02110-1301, USA
3.23 + */
3.24 +
3.25 +#pragma once
3.26 +
3.27 +#include "file.h"
3.28 +
3.29 +EXTERN_C_BEGIN
3.30 +
3.31 +/* File operations. */
3.32 +
3.33 +void client_close(file_t *file);
3.34 +file_t *client_open(const char *name, flags_t flags);
3.35 +long client_pipe(file_t **reader, file_t **writer);
3.36 +
3.37 +/* File and region operations. */
3.38 +
3.39 +long client_flush(file_t *file);
3.40 +void *client_mmap(file_t *file, offset_t position, offset_t length);
3.41 +
3.42 +/* Pipe region operations. */
3.43 +
3.44 +void *client_current_region(file_t *file);
3.45 +void *client_next_region(file_t *file);
3.46 +
3.47 +/* File data operations. */
3.48 +
3.49 +offset_t client_read(file_t *file, void *buf, offset_t count);
3.50 +offset_t client_write(file_t *file, const void *buf, offset_t count);
3.51 +
3.52 +/* File navigation operations. */
3.53 +
3.54 +offset_t client_seek(file_t *file, offset_t offset, int whence);
3.55 +long client_tell(file_t *file);
3.56 +
3.57 +EXTERN_C_END
3.58 +
3.59 +// vim: tabstop=2 expandtab shiftwidth=2
4.1 --- a/client/file.cc Thu Apr 08 23:55:47 2021 +0200
4.2 +++ b/client/file.cc Sun Apr 11 19:34:07 2021 +0200
4.3 @@ -36,6 +36,44 @@
4.4
4.5
4.6
4.7 +/* Update the extent of the file in a region using the region start and end
4.8 + positions and the file size. */
4.9 +
4.10 +static void _update_extent(file_t *file)
4.11 +{
4.12 + /* Handle files ending after or within the region. */
4.13 +
4.14 + if (file->size > file->start_pos)
4.15 + {
4.16 + if (file->size > file->end_pos)
4.17 + file->data_end = file->end_pos - file->start_pos;
4.18 + else
4.19 + file->data_end = file->size - file->start_pos;
4.20 + }
4.21 +
4.22 + /* Handle files ending before the region. */
4.23 +
4.24 + else
4.25 + file->data_end = 0;
4.26 +}
4.27 +
4.28 +
4.29 +
4.30 +/* Initialise the given file structure. */
4.31 +
4.32 +void file_init(file_t *file)
4.33 +{
4.34 + file->memory = NULL;
4.35 + file->ref = L4_INVALID_CAP;
4.36 + file->start_pos = 0;
4.37 + file->end_pos = 0;
4.38 + file->data_end = 0;
4.39 + file->data_current = 0;
4.40 + file->can_mmap = 1;
4.41 +}
4.42 +
4.43 +
4.44 +
4.45 /* Release resources for the given file. */
4.46
4.47 void file_close(file_t *file)
4.48 @@ -49,7 +87,36 @@
4.49 file_init(file);
4.50 }
4.51
4.52 -/* Initialise a file structure for a context obtained from the given server. */
4.53 +/* Open a file using the given structure, indicating the filename and
4.54 + filesystem server. The file_mmap function should be used to obtain access to
4.55 + memory providing file data. This is a convenience function invoking
4.56 + file_context and file_context_open. */
4.57 +
4.58 +long file_open(file_t *file, const char *filename, flags_t flags, l4_cap_idx_t server)
4.59 +{
4.60 + file_t context;
4.61 + long err;
4.62 +
4.63 + err = file_context(&context, server);
4.64 + if (err)
4.65 + return err;
4.66 +
4.67 + if (!file_string_set(&context, filename, 0, NULL))
4.68 + return -L4_ENOMEM;
4.69 +
4.70 + err = file_context_open(file, flags, &context);
4.71 +
4.72 + /* Close the context, although a separate mechanism could permit contexts to
4.73 + open several files. */
4.74 +
4.75 + file_close(&context);
4.76 + return err;
4.77 +}
4.78 +
4.79 +
4.80 +
4.81 +/* Initialise a file structure for a context obtained from the given server
4.82 + attaching memory to communicate filename information. */
4.83
4.84 long file_context(file_t *file, l4_cap_idx_t server)
4.85 {
4.86 @@ -87,54 +154,50 @@
4.87 return openercontext.open(flags, &file->size, &file->ref);
4.88 }
4.89
4.90 -/* Initialise the given file structure. */
4.91 -
4.92 -void file_init(file_t *file)
4.93 -{
4.94 - file->memory = NULL;
4.95 - file->ref = L4_INVALID_CAP;
4.96 - file->start_pos = 0;
4.97 - file->end_pos = 0;
4.98 - file->data_end = 0;
4.99 -}
4.100 -
4.101 -/* Open a file using the given structure, indicating the filename and
4.102 - filesystem server. This is a convenience function invoking file_context and
4.103 - file_context_open. */
4.104 -
4.105 -long file_open(file_t *file, const char *filename, flags_t flags, l4_cap_idx_t server)
4.106 -{
4.107 - file_t context;
4.108 - long err;
4.109 -
4.110 - err = file_context(&context, server);
4.111 - if (err)
4.112 - return err;
4.113 -
4.114 - if (!file_string_set(&context, filename, 0, NULL))
4.115 - return -L4_ENOMEM;
4.116 -
4.117 - err = file_context_open(file, flags, &context);
4.118 - file_close(&context);
4.119 - return err;
4.120 -}
4.121
4.122
4.123 -
4.124 -/* Map a region of the given file to a memory region. */
4.125 +/* Flush populated data and obtain an updated file size and populated data
4.126 + details. */
4.127
4.128 -long file_mmap(file_t *file, offset_t position, offset_t length)
4.129 +long file_flush(file_t *file)
4.130 {
4.131 - client_MappedFile mapped_file(file->ref);
4.132 - long err = mapped_file.mmap(position, length, &file->start_pos, &file->end_pos, &file->data_end);
4.133 + client_File _file(file->ref);
4.134 + long err = _file.flush(file->data_current, &file->size);
4.135
4.136 if (err)
4.137 return err;
4.138
4.139 - return ipc_attach_dataspace(file->ref, file_span(file), (void **) &file->memory);
4.140 + _update_extent(file);
4.141 +
4.142 + return L4_EOK;
4.143 }
4.144
4.145 -/* Resize a file. */
4.146 +/* Map a region of the given file to a memory region, obtaining an updated file
4.147 + size and populated data details. Unmap any previously mapped region. */
4.148 +
4.149 +long file_mmap(file_t *file, offset_t position, offset_t length)
4.150 +{
4.151 + char *memory = file->memory;
4.152 + client_MappedFile mapped_file(file->ref);
4.153 + long err = mapped_file.mmap(position, length, &file->start_pos,
4.154 + &file->end_pos, &file->size);
4.155 +
4.156 + if (err)
4.157 + return err;
4.158 +
4.159 + _update_extent(file);
4.160 +
4.161 + err = ipc_attach_dataspace(file->ref, file_span(file), (void **) &file->memory);
4.162 + if (err)
4.163 + return err;
4.164 +
4.165 + if (memory != NULL)
4.166 + ipc_detach_dataspace(memory);
4.167 +
4.168 + return L4_EOK;
4.169 +}
4.170 +
4.171 +/* Resize a file, obtaining updated file size and populated data details. */
4.172
4.173 long file_resize(file_t *file, offset_t size)
4.174 {
4.175 @@ -142,21 +205,12 @@
4.176 offset_t file_size = size;
4.177 long err = _file.resize(&file_size);
4.178
4.179 - if (!err)
4.180 - {
4.181 - /* Determine the extent of the file in this region. */
4.182 + if (err)
4.183 + return err;
4.184
4.185 - if (file_size > file->end_pos)
4.186 - file->data_end = file_span(file);
4.187 - else
4.188 - file->data_end = file_size - file->start_pos;
4.189 -
4.190 - /* Update the file size locally. */
4.191 -
4.192 - file->size = file_size;
4.193 - }
4.194 -
4.195 - return err;
4.196 + file->size = file_size;
4.197 + _update_extent(file);
4.198 + return L4_EOK;
4.199 }
4.200
4.201
4.202 @@ -236,6 +290,72 @@
4.203
4.204
4.205
4.206 +/* Return the number of remaining populated bytes in the region. */
4.207 +
4.208 +offset_t file_data_available(file_t *file)
4.209 +{
4.210 + return file_populated_span(file) - file->data_current;
4.211 +}
4.212 +
4.213 +/* Return the current data offset in the region. */
4.214 +
4.215 +char *file_data_current(file_t *file)
4.216 +{
4.217 + return file->memory + file->data_current;
4.218 +}
4.219 +
4.220 +/* Return the current access position in the file. */
4.221 +
4.222 +offset_t file_data_current_position(file_t *file)
4.223 +{
4.224 + return file->start_pos + file->data_current;
4.225 +}
4.226 +
4.227 +/* Return the position of the end of the populated bytes in the region. */
4.228 +
4.229 +offset_t file_data_end_position(file_t *file)
4.230 +{
4.231 + return file->start_pos + file->data_end;
4.232 +}
4.233 +
4.234 +/* Return the amount of remaining space in the region. */
4.235 +
4.236 +offset_t file_data_space(file_t *file)
4.237 +{
4.238 + return file_span(file) - file->data_current;
4.239 +}
4.240 +
4.241 +
4.242 +
4.243 +/* Copy data to the given buffer from the current data position, updating the
4.244 + position. */
4.245 +
4.246 +void file_data_read(file_t *file, char *buf, size_t to_transfer)
4.247 +{
4.248 + memcpy(buf, file_data_current(file), to_transfer);
4.249 +
4.250 + /* Update position details. */
4.251 +
4.252 + file->data_current += to_transfer;
4.253 +}
4.254 +
4.255 +/* Copy data from the given buffer to the current data position, updating the
4.256 + position and the extent of populated data if this was exceeded. */
4.257 +
4.258 +void file_data_write(file_t *file, char *buf, size_t to_transfer)
4.259 +{
4.260 + memcpy(file_data_current(file), buf, to_transfer);
4.261 +
4.262 + /* Update position details. */
4.263 +
4.264 + file->data_current += to_transfer;
4.265 +
4.266 + if (file->data_current > file->data_end)
4.267 + file->data_end = file->data_current;
4.268 +}
4.269 +
4.270 +
4.271 +
4.272 /* Open two pipe endpoints using the given pipe server. */
4.273
4.274 long pipe_open(offset_t size, file_t *reader, file_t *writer, l4_cap_idx_t server)
4.275 @@ -248,6 +368,11 @@
4.276 file_init(reader);
4.277 file_init(writer);
4.278
4.279 + /* Pipes can usually only be accessed via region navigation. */
4.280 +
4.281 + reader->can_mmap = 0;
4.282 + writer->can_mmap = 0;
4.283 +
4.284 long err = opener.pipe(size, &reader->ref, &writer->ref);
4.285 if (err)
4.286 return err;
5.1 --- a/client/file.h Thu Apr 08 23:55:47 2021 +0200
5.2 +++ b/client/file.h Sun Apr 11 19:34:07 2021 +0200
5.3 @@ -42,12 +42,17 @@
5.4 /* File region parameters. */
5.5
5.6 offset_t start_pos, end_pos; /* start and end positions of region */
5.7 - offset_t data_end; /* amount of data in the region */
5.8 + offset_t data_end; /* amount/extent of data in the region */
5.9 + offset_t data_current; /* client access offset */
5.10
5.11 /* Total size of file. */
5.12
5.13 offset_t size;
5.14
5.15 + /* Arbitrary memory mapping support. */
5.16 +
5.17 + int can_mmap;
5.18 +
5.19 } file_t;
5.20
5.21
5.22 @@ -65,6 +70,7 @@
5.23
5.24 /* File and region operations. */
5.25
5.26 +long file_flush(file_t *file);
5.27 long file_mmap(file_t *file, offset_t position, offset_t length);
5.28 long file_resize(file_t *file, offset_t size);
5.29
5.30 @@ -78,6 +84,19 @@
5.31 char *file_string_get(file_t *file, offset_t offset);
5.32 int file_string_set(file_t *file, const char *data, offset_t offset, offset_t *written);
5.33
5.34 +/* Client data functions. */
5.35 +
5.36 +offset_t file_data_available(file_t *file);
5.37 +char *file_data_current(file_t *file);
5.38 +offset_t file_data_current_position(file_t *file);
5.39 +offset_t file_data_end_position(file_t *file);
5.40 +offset_t file_data_space(file_t *file);
5.41 +
5.42 +/* Client data transfer functions. */
5.43 +
5.44 +void file_data_read(file_t *file, char *buf, size_t to_transfer);
5.45 +void file_data_write(file_t *file, char *buf, size_t to_transfer);
5.46 +
5.47
5.48
5.49 /* Pipe operations. */
6.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
6.2 +++ b/conf/dstest_block_simple.cfg Sun Apr 11 19:34:07 2021 +0200
6.3 @@ -0,0 +1,23 @@
6.4 +-- vim:set ft=lua:
6.5 +
6.6 +local L4 = require("L4");
6.7 +
6.8 +local l = L4.default_loader;
6.9 +
6.10 +local server = l:new_channel();
6.11 +
6.12 +l:startv({
6.13 + caps = {
6.14 + server = server:svr(),
6.15 + },
6.16 + log = { "server", "r" },
6.17 + },
6.18 + "rom/dstest_block_server", "10");
6.19 +
6.20 +l:startv({
6.21 + caps = {
6.22 + server = server,
6.23 + },
6.24 + log = { "client", "g" },
6.25 + },
6.26 + "rom/dstest_block_client_simple", "rom/dstest_block_simple.cfg");
7.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
7.2 +++ b/conf/dstest_block_simple.list Sun Apr 11 19:34:07 2021 +0200
7.3 @@ -0,0 +1,25 @@
7.4 +entry dstest_block_simple
7.5 +roottask moe rom/dstest_block_simple.cfg
7.6 +module dstest_block_simple.cfg
7.7 +module l4re
7.8 +module ned
7.9 +module dstest_block_client_simple
7.10 +module dstest_block_server
7.11 +module lib4re-c.so
7.12 +module lib4re-c-util.so
7.13 +module lib4re.so
7.14 +module lib4re-util.so
7.15 +module libc_be_l4refile.so
7.16 +module libc_be_l4re.so
7.17 +module libc_be_socket_noop.so
7.18 +module libc_support_misc.so
7.19 +module libdl.so
7.20 +module libipc.so
7.21 +module libl4sys-direct.so
7.22 +module libl4sys.so
7.23 +module libl4util.so
7.24 +module libld-l4.so
7.25 +module libpthread.so
7.26 +module libstdc++.so
7.27 +module libsupc++.so
7.28 +module libuc_c.so
8.1 --- a/files/file_pager.cc Thu Apr 08 23:55:47 2021 +0200
8.2 +++ b/files/file_pager.cc Sun Apr 11 19:34:07 2021 +0200
8.3 @@ -44,20 +44,12 @@
8.4 return Pager::resize(size);
8.5 }
8.6
8.7 -long FilePager::mmap(offset_t position, offset_t length, offset_t *start_pos, offset_t *end_pos, offset_t *data_end)
8.8 +long FilePager::mmap(offset_t position, offset_t length, offset_t *start_pos,
8.9 + offset_t *end_pos, offset_t *size)
8.10 {
8.11 /* Set the limits of the paged region. */
8.12
8.13 - Pager::mmap(position, length, start_pos, end_pos, data_end);
8.14 -
8.15 - /* Obtain the amount of the region that is populated with file data. */
8.16 -
8.17 - *data_end = get_data_size() - _start;
8.18 -
8.19 - if (*data_end > _size)
8.20 - *data_end = _size;
8.21 -
8.22 - return L4_EOK;
8.23 + return Pager::mmap(position, length, start_pos, end_pos, size);
8.24 }
8.25
8.26
9.1 --- a/files/file_pager.h Thu Apr 08 23:55:47 2021 +0200
9.2 +++ b/files/file_pager.h Sun Apr 11 19:34:07 2021 +0200
9.3 @@ -36,9 +36,11 @@
9.4
9.5 /* Pager and mapped file methods. */
9.6
9.7 - virtual long map(unsigned long offset, l4_addr_t hot_spot, flags_t flags, l4_snd_fpage_t *region);
9.8 + virtual long map(unsigned long offset, l4_addr_t hot_spot, flags_t flags,
9.9 + l4_snd_fpage_t *region);
9.10
9.11 - virtual long mmap(offset_t position, offset_t length, offset_t *start_pos, offset_t *end_pos, offset_t *data_end);
9.12 + virtual long mmap(offset_t position, offset_t length, offset_t *start_pos,
9.13 + offset_t *end_pos, offset_t *size);
9.14 };
9.15
9.16 // vim: tabstop=4 expandtab shiftwidth=4
10.1 --- a/generic/pager.cc Thu Apr 08 23:55:47 2021 +0200
10.2 +++ b/generic/pager.cc Sun Apr 11 19:34:07 2021 +0200
10.3 @@ -46,14 +46,19 @@
10.4
10.5 /* Expose a region of the file. */
10.6
10.7 -long Pager::mmap(offset_t position, offset_t length, offset_t *start_pos, offset_t *end_pos, offset_t *data_end)
10.8 +long Pager::mmap(offset_t position, offset_t length, offset_t *start_pos,
10.9 + offset_t *end_pos, offset_t *size)
10.10 {
10.11 + /* Define region characteristics. */
10.12 +
10.13 _start = trunc(position, PAGE_SIZE);
10.14 _size = round(position + length, PAGE_SIZE) - _start;
10.15
10.16 + /* Return the start and end positions plus populated extent. */
10.17 +
10.18 *start_pos = _start;
10.19 *end_pos = _start + _size;
10.20 - *data_end = 0;
10.21 + *size = _mapper->get_data_size();
10.22
10.23 return L4_EOK;
10.24 }
10.25 @@ -61,7 +66,8 @@
10.26 /* Map a flexpage corresponding to the dataspace 'offset' involving a 'hot_spot'
10.27 (flexpage offset). */
10.28
10.29 -long Pager::map(offset_t offset, l4_addr_t hot_spot, flags_t flags, l4_snd_fpage_t *region)
10.30 +long Pager::map(offset_t offset, l4_addr_t hot_spot, flags_t flags,
10.31 + l4_snd_fpage_t *region)
10.32 {
10.33 offset_t file_offset = _start + offset;
10.34 offset_t max_offset = _start + _size;
11.1 --- a/generic/pager.h Thu Apr 08 23:55:47 2021 +0200
11.2 +++ b/generic/pager.h Sun Apr 11 19:34:07 2021 +0200
11.3 @@ -23,7 +23,8 @@
11.4
11.5 /* Paging methods. */
11.6
11.7 - virtual long map(offset_t offset, l4_addr_t hot_spot, flags_t flags, l4_snd_fpage_t *region);
11.8 + virtual long map(offset_t offset, l4_addr_t hot_spot, flags_t flags,
11.9 + l4_snd_fpage_t *region);
11.10
11.11 /* Limit methods. */
11.12
11.13 @@ -37,7 +38,8 @@
11.14
11.15 /* Mapped file methods. */
11.16
11.17 - virtual long mmap(offset_t position, offset_t length, offset_t *start_pos, offset_t *end_pos, offset_t *data_end);
11.18 + virtual long mmap(offset_t position, offset_t length, offset_t *start_pos,
11.19 + offset_t *end_pos, offset_t *size);
11.20 };
11.21
11.22 // vim: tabstop=4 expandtab shiftwidth=4
12.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
12.2 +++ b/tests/dstest_block_client_simple.cc Sun Apr 11 19:34:07 2021 +0200
12.3 @@ -0,0 +1,130 @@
12.4 +/*
12.5 + * Test dataspace operations.
12.6 + *
12.7 + * Copyright (C) 2020, 2021 Paul Boddie <paul@boddie.org.uk>
12.8 + *
12.9 + * This program is free software; you can redistribute it and/or
12.10 + * modify it under the terms of the GNU General Public License as
12.11 + * published by the Free Software Foundation; either version 2 of
12.12 + * the License, or (at your option) any later version.
12.13 + *
12.14 + * This program is distributed in the hope that it will be useful,
12.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
12.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12.17 + * GNU General Public License for more details.
12.18 + *
12.19 + * You should have received a copy of the GNU General Public License
12.20 + * along with this program; if not, write to the Free Software
12.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor,
12.22 + * Boston, MA 02110-1301, USA
12.23 + */
12.24 +
12.25 +#include <systypes/fcntl.h>
12.26 +
12.27 +#include <stdio.h>
12.28 +
12.29 +#include "client.h"
12.30 +
12.31 +
12.32 +
12.33 +int main(int argc, char *argv[])
12.34 +{
12.35 + if (argc < 2)
12.36 + {
12.37 + printf("Need a filename.\n");
12.38 + return 1;
12.39 + }
12.40 +
12.41 + /* Obtain filename and access parameters. */
12.42 +
12.43 + char *filename = argv[1];
12.44 +
12.45 + /* Invoke the open method to receive the file reference. */
12.46 +
12.47 + file_t *file = client_open(filename, O_RDWR);
12.48 +
12.49 + if (file == NULL)
12.50 + {
12.51 + printf("Could not obtain file.\n");
12.52 + return 1;
12.53 + }
12.54 +
12.55 + /* Map some memory. */
12.56 +
12.57 + void *addr = client_mmap(file, 0, 1024);
12.58 +
12.59 + if (addr == NULL)
12.60 + {
12.61 + printf("Could not map memory.\n");
12.62 + return 1;
12.63 + }
12.64 +
12.65 + printf("At mapped region from %ld to %ld with data at %ld to %ld.\n",
12.66 + file->start_pos, file->end_pos, file->data_current, file->data_end);
12.67 +
12.68 + /* Copy the sampled data to another file region. */
12.69 +
12.70 + offset_t size = file->size;
12.71 + char buffer[size];
12.72 + offset_t nread = client_read(file, buffer, size);
12.73 +
12.74 + if (nread != size)
12.75 + {
12.76 + printf("Could not read entire file: %ld out of %ld bytes.\n", nread, size);
12.77 + return 1;
12.78 + }
12.79 +
12.80 + printf("File contents...\n");
12.81 +
12.82 + fwrite(buffer, sizeof(char), nread, stdout);
12.83 +
12.84 + printf("Copy %ld bytes to end...\n", nread);
12.85 +
12.86 + for (int times = 0; times < 10; times++)
12.87 + {
12.88 + printf("Copy #%d...\n", times);
12.89 +
12.90 + offset_t nwritten = client_write(file, buffer, nread);
12.91 +
12.92 + if (nwritten != nread)
12.93 + {
12.94 + printf("Could not write file section: %ld instead of %ld bytes.\n",
12.95 + nwritten, nread);
12.96 + return 1;
12.97 + }
12.98 + }
12.99 +
12.100 + printf("File is now %ld in size.\n", file->size);
12.101 +
12.102 + printf("Seek to start...\n");
12.103 +
12.104 + client_seek(file, 0, SEEK_SET);
12.105 +
12.106 + printf("At mapped region from %ld to %ld with data at %ld to %ld.\n",
12.107 + file->start_pos, file->end_pos, file->data_current, file->data_end);
12.108 +
12.109 + printf("File contents...\n");
12.110 +
12.111 + offset_t position = 0;
12.112 +
12.113 + while (position < file->size)
12.114 + {
12.115 + offset_t nread = client_read(file, buffer, size);
12.116 +
12.117 + if ((nread != size) && (nread != file->size - position))
12.118 + {
12.119 + printf("Could not read file section: %ld instead of %ld or remaining %ld bytes.\n",
12.120 + nread, size, file->size - position);
12.121 + return 1;
12.122 + }
12.123 +
12.124 + fwrite(buffer, sizeof(char), nread, stdout);
12.125 + position += nread;
12.126 + }
12.127 +
12.128 + printf("File shown.\n");
12.129 +
12.130 + return 0;
12.131 +}
12.132 +
12.133 +// vim: tabstop=2 expandtab shiftwidth=2