# HG changeset patch # User Paul Boddie # Date 1618162447 -7200 # Node ID 00dc578063750732c4adcf3fdac2f94469556f2e # Parent 94aa665bf1154e5b8ea11d8df5e8c80bc459abb1 Changed mmap to return the file size, not the populated extent of the region. Introduced a higher-level client library for file access. Adjusted handling of the region state in the file library. Added a test of the higher-level client library. diff -r 94aa665bf115 -r 00dc57806375 Makefile --- a/Makefile Thu Apr 08 23:55:47 2021 +0200 +++ b/Makefile Sun Apr 11 19:34:07 2021 +0200 @@ -2,8 +2,14 @@ L4DIR ?= $(PKGDIR)/../.. TARGET = \ - dstest_block_client dstest_host_client dstest_pipe_client dstest_test_client \ - dstest_block_server dstest_host_server dstest_pipe_server dstest_test_server + dstest_block_client dstest_block_client_simple \ + dstest_host_client \ + dstest_pipe_client \ + dstest_test_client \ + dstest_block_server \ + dstest_host_server \ + dstest_pipe_server \ + dstest_test_server MODE = static @@ -45,6 +51,8 @@ PLAIN_SRC_CC_dstest_block_client = tests/dstest_block_client.cc client/file.cc +PLAIN_SRC_CC_dstest_block_client_simple = tests/dstest_block_client_simple.cc client/client.cc client/file.cc + PLAIN_SRC_CC_dstest_host_client = tests/dstest_host_client.cc client/file.cc PLAIN_SRC_CC_dstest_pipe_client = tests/dstest_pipe_client.cc client/file.cc @@ -97,6 +105,11 @@ $(PLAIN_SRC_CC_dstest_block_client) \ $(COMMON_SRC_CC) +SRC_CC_dstest_block_client_simple = \ + $(CLIENT_INTERFACES_SRC_CC) \ + $(PLAIN_SRC_CC_dstest_block_client_simple) \ + $(COMMON_SRC_CC) + SRC_CC_dstest_host_client = \ $(CLIENT_INTERFACES_SRC_CC) \ $(PLAIN_SRC_CC_dstest_host_client) \ @@ -145,6 +158,8 @@ $(PLAIN_SRC_CC_dstest_block_client): $(CLIENT_INTERFACES_SRC_CC) +$(PLAIN_SRC_CC_dstest_block_client_simple): $(CLIENT_INTERFACES_SRC_CC) + $(PLAIN_SRC_CC_dstest_host_client): $(CLIENT_INTERFACES_SRC_CC) $(PLAIN_SRC_CC_dstest_pipe_client): $(CLIENT_INTERFACES_SRC_CC) diff -r 94aa665bf115 -r 00dc57806375 client/client.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/client/client.cc Sun Apr 11 19:34:07 2021 +0200 @@ -0,0 +1,390 @@ +/* + * Filesystem client functions. + * + * Copyright (C) 2018, 2019, 2020, 2021 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include + +#include +#include + +#include "client.h" + + + +/* Default size of pipe regions. */ + +const offset_t DEFAULT_PIPE_SIZE = 4096; + + + +/* Close a filesystem object. */ + +void client_close(file_t *file) +{ + if (file == NULL) + return; + + file_close(file); + free(file); +} + + + +/* Open a filesystem object. */ + +file_t *client_open(const char *name, flags_t flags) +{ + file_t *file = (file_t *) malloc(sizeof(file_t)); + + if (file == NULL) + return NULL; + + l4_cap_idx_t server = l4re_env_get_cap("server"); + + if (file_open(file, name, flags, server)) + { + free(file); + return NULL; + } + + return file; +} + + + +/* Open a pipe object. */ + +long client_pipe(file_t **reader, file_t **writer) +{ + *reader = (file_t *) malloc(sizeof(file_t)); + + if (*reader == NULL) + return -L4_ENOMEM; + + *writer = (file_t *) malloc(sizeof(file_t)); + + if (*writer == NULL) + { + free(*reader); + return -L4_ENOMEM; + } + + l4_cap_idx_t server = l4re_env_get_cap("pipes"); + + long err = pipe_open(DEFAULT_PIPE_SIZE, *reader, *writer, server); + + if (err) + { + free(*reader); + free(*writer); + } + + return err; +} + + + +/* Flush data conditionally to the filesystem object. */ + +static long _flush(file_t *file, offset_t position) +{ + long err; + + /* Where the position is outside the current region, re-map. */ + + if ((position < file->start_pos) || (position >= file->end_pos)) + { + if (file->can_mmap) + { + if (file_mmap(file, position, file_span(file))) + return -L4_EIO; + } + + /* Strict conditions for region navigation in pipes. */ + + else if ((position != file->end_pos) || + (client_next_region(file) == NULL)) + return -L4_EIO; + } + + /* Otherwise, flush any written data in the current region and update the + file size details. */ + + else + { + err = client_flush(file); + + if (err) + return err; + } + + /* Update the current data offset. */ + + file->data_current = position - file->start_pos; + return L4_EOK; +} + + + +/* Flush data explicitly to the filesystem object. */ + +long client_flush(file_t *file) +{ + if (file == NULL) + return -L4_EINVAL; + + /* Flush and retain most buffer settings. */ + + return file_flush(file); +} + + + +/* Map a memory region to a file. */ + +void *client_mmap(file_t *file, offset_t position, offset_t length) +{ + if ((file == NULL) || (file_mmap(file, position, length))) + return NULL; + + return file->memory; +} + + + +/* Obtain the current region of a pipe. */ + +void *client_current_region(file_t *file) +{ + if ((file == NULL) || (pipe_current(file))) + return NULL; + + return file->memory; +} + + + +/* Obtain the next region of a pipe. */ + +void *client_next_region(file_t *file) +{ + if ((file == NULL) || (pipe_next(file))) + return NULL; + + return file->memory; +} + + + +/* Read from the filesystem object into the buffer provided. */ + +offset_t client_read(file_t *file, void *buf, offset_t count) +{ + if (file == NULL) + return 0; + + /* Amount available in the descriptor buffer already. */ + + offset_t available = file_data_available(file); + offset_t to_transfer, total = 0; + + while (count > 0) + { + /* If there is no data, try and obtain more data. */ + + if (!available) + { + /* Flush any unwritten data, preparing to read from the file position at + the end of the data, and returning if no new data is available. */ + + if (_flush(file, file_data_end_position(file))) + break; + + available = file_data_available(file); + + if (!available) + break; + } + + /* Transfer data into the supplied buffer. */ + + to_transfer = available <= count ? available : count; + + file_data_read(file, (char *) buf, to_transfer); + + /* Update counters. */ + + available -= to_transfer; + + count -= to_transfer; + total += to_transfer; + + buf = ((char *) buf + to_transfer); + } + + return total; +} + + + +/* Ensure that the buffer can provide the needed data. */ + +offset_t client_seek(file_t *file, offset_t offset, int whence) +{ + if (file == NULL) + return 0; + + offset_t position, current = file_data_current_position(file), change; + + switch (whence) + { + case SEEK_SET: + position = offset; + break; + + case SEEK_CUR: + position = current + offset; + break; + + case SEEK_END: + position = file->size + offset; + break; + + default: + /* NOTE: Set errno to EINVAL. */ + return -1; + } + + /* Retain the current position if unchanged. */ + + if (position == current) + return position; + + /* Move forward in the file. */ + + if (position > current) + { + change = position - current; + + /* Move towards the end of available data. + Request new data if not enough is available. */ + + if (change <= file_data_available(file)) + { + file->data_current += change; + return position; + } + } + + /* Move backward in the file. */ + + else + { + change = current - position; + + /* Move towards the start of available data. + Request new data if moving beyond the start of the data. */ + + if (change <= file->data_current) + { + file->data_current -= change; + return position; + } + } + + /* Handle unwritten data and reset the buffer for reading. */ + + _flush(file, position); + return position; +} + + + +long client_tell(file_t *file) +{ + if (file == NULL) + return -L4_EINVAL; + + return file_data_current_position(file); +} + + + +/* Write to the filesystem object from the buffer provided. */ + +offset_t client_write(file_t *file, const void *buf, offset_t count) +{ + if (file == NULL) + return 0; + + /* Attempt to ensure that the file can accept the amount of data to be + written. This may not resize to the needed amount if a file has a fixed + size, but data will still be written to any available space. */ + + offset_t needed_size = file_data_current_position(file) + count; + + if (file->size < needed_size) + { + file_resize(file, needed_size); + + if (file->size < needed_size) + count = file->size - file_data_current_position(file); + } + + /* Space remaining in the descriptor buffer. */ + + offset_t space = file_data_space(file); + offset_t to_transfer, total = 0; + + while (count > 0) + { + /* If no space is available, try and send data, reset the buffer. */ + + if (!space) + { + /* Flush any unwritten data and continue writing from the current data + position. */ + + if (_flush(file, file_data_current_position(file))) + break; + + space = file_data_space(file); + } + + /* Transfer data into the supplied buffer. */ + + to_transfer = space <= count ? space : count; + + file_data_write(file, (char *) buf, to_transfer); + + /* Update counters. */ + + space -= to_transfer; + + count -= to_transfer; + total += to_transfer; + + buf = ((char *) buf + to_transfer); + } + + return total; +} + +// vim: tabstop=2 expandtab shiftwidth=2 diff -r 94aa665bf115 -r 00dc57806375 client/client.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/client/client.h Sun Apr 11 19:34:07 2021 +0200 @@ -0,0 +1,56 @@ +/* + * Filesystem client functions. + * + * Copyright (C) 2018, 2019, 2020, 2021 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#pragma once + +#include "file.h" + +EXTERN_C_BEGIN + +/* File operations. */ + +void client_close(file_t *file); +file_t *client_open(const char *name, flags_t flags); +long client_pipe(file_t **reader, file_t **writer); + +/* File and region operations. */ + +long client_flush(file_t *file); +void *client_mmap(file_t *file, offset_t position, offset_t length); + +/* Pipe region operations. */ + +void *client_current_region(file_t *file); +void *client_next_region(file_t *file); + +/* File data operations. */ + +offset_t client_read(file_t *file, void *buf, offset_t count); +offset_t client_write(file_t *file, const void *buf, offset_t count); + +/* File navigation operations. */ + +offset_t client_seek(file_t *file, offset_t offset, int whence); +long client_tell(file_t *file); + +EXTERN_C_END + +// vim: tabstop=2 expandtab shiftwidth=2 diff -r 94aa665bf115 -r 00dc57806375 client/file.cc --- a/client/file.cc Thu Apr 08 23:55:47 2021 +0200 +++ b/client/file.cc Sun Apr 11 19:34:07 2021 +0200 @@ -36,6 +36,44 @@ +/* Update the extent of the file in a region using the region start and end + positions and the file size. */ + +static void _update_extent(file_t *file) +{ + /* Handle files ending after or within the region. */ + + if (file->size > file->start_pos) + { + if (file->size > file->end_pos) + file->data_end = file->end_pos - file->start_pos; + else + file->data_end = file->size - file->start_pos; + } + + /* Handle files ending before the region. */ + + else + file->data_end = 0; +} + + + +/* Initialise the given file structure. */ + +void file_init(file_t *file) +{ + file->memory = NULL; + file->ref = L4_INVALID_CAP; + file->start_pos = 0; + file->end_pos = 0; + file->data_end = 0; + file->data_current = 0; + file->can_mmap = 1; +} + + + /* Release resources for the given file. */ void file_close(file_t *file) @@ -49,7 +87,36 @@ file_init(file); } -/* Initialise a file structure for a context obtained from the given server. */ +/* Open a file using the given structure, indicating the filename and + filesystem server. The file_mmap function should be used to obtain access to + memory providing file data. This is a convenience function invoking + file_context and file_context_open. */ + +long file_open(file_t *file, const char *filename, flags_t flags, l4_cap_idx_t server) +{ + file_t context; + long err; + + err = file_context(&context, server); + if (err) + return err; + + if (!file_string_set(&context, filename, 0, NULL)) + return -L4_ENOMEM; + + err = file_context_open(file, flags, &context); + + /* Close the context, although a separate mechanism could permit contexts to + open several files. */ + + file_close(&context); + return err; +} + + + +/* Initialise a file structure for a context obtained from the given server + attaching memory to communicate filename information. */ long file_context(file_t *file, l4_cap_idx_t server) { @@ -87,54 +154,50 @@ return openercontext.open(flags, &file->size, &file->ref); } -/* Initialise the given file structure. */ - -void file_init(file_t *file) -{ - file->memory = NULL; - file->ref = L4_INVALID_CAP; - file->start_pos = 0; - file->end_pos = 0; - file->data_end = 0; -} - -/* Open a file using the given structure, indicating the filename and - filesystem server. This is a convenience function invoking file_context and - file_context_open. */ - -long file_open(file_t *file, const char *filename, flags_t flags, l4_cap_idx_t server) -{ - file_t context; - long err; - - err = file_context(&context, server); - if (err) - return err; - - if (!file_string_set(&context, filename, 0, NULL)) - return -L4_ENOMEM; - - err = file_context_open(file, flags, &context); - file_close(&context); - return err; -} - -/* Map a region of the given file to a memory region. */ +/* Flush populated data and obtain an updated file size and populated data + details. */ -long file_mmap(file_t *file, offset_t position, offset_t length) +long file_flush(file_t *file) { - client_MappedFile mapped_file(file->ref); - long err = mapped_file.mmap(position, length, &file->start_pos, &file->end_pos, &file->data_end); + client_File _file(file->ref); + long err = _file.flush(file->data_current, &file->size); if (err) return err; - return ipc_attach_dataspace(file->ref, file_span(file), (void **) &file->memory); + _update_extent(file); + + return L4_EOK; } -/* Resize a file. */ +/* Map a region of the given file to a memory region, obtaining an updated file + size and populated data details. Unmap any previously mapped region. */ + +long file_mmap(file_t *file, offset_t position, offset_t length) +{ + char *memory = file->memory; + client_MappedFile mapped_file(file->ref); + long err = mapped_file.mmap(position, length, &file->start_pos, + &file->end_pos, &file->size); + + if (err) + return err; + + _update_extent(file); + + err = ipc_attach_dataspace(file->ref, file_span(file), (void **) &file->memory); + if (err) + return err; + + if (memory != NULL) + ipc_detach_dataspace(memory); + + return L4_EOK; +} + +/* Resize a file, obtaining updated file size and populated data details. */ long file_resize(file_t *file, offset_t size) { @@ -142,21 +205,12 @@ offset_t file_size = size; long err = _file.resize(&file_size); - if (!err) - { - /* Determine the extent of the file in this region. */ + if (err) + return err; - if (file_size > file->end_pos) - file->data_end = file_span(file); - else - file->data_end = file_size - file->start_pos; - - /* Update the file size locally. */ - - file->size = file_size; - } - - return err; + file->size = file_size; + _update_extent(file); + return L4_EOK; } @@ -236,6 +290,72 @@ +/* Return the number of remaining populated bytes in the region. */ + +offset_t file_data_available(file_t *file) +{ + return file_populated_span(file) - file->data_current; +} + +/* Return the current data offset in the region. */ + +char *file_data_current(file_t *file) +{ + return file->memory + file->data_current; +} + +/* Return the current access position in the file. */ + +offset_t file_data_current_position(file_t *file) +{ + return file->start_pos + file->data_current; +} + +/* Return the position of the end of the populated bytes in the region. */ + +offset_t file_data_end_position(file_t *file) +{ + return file->start_pos + file->data_end; +} + +/* Return the amount of remaining space in the region. */ + +offset_t file_data_space(file_t *file) +{ + return file_span(file) - file->data_current; +} + + + +/* Copy data to the given buffer from the current data position, updating the + position. */ + +void file_data_read(file_t *file, char *buf, size_t to_transfer) +{ + memcpy(buf, file_data_current(file), to_transfer); + + /* Update position details. */ + + file->data_current += to_transfer; +} + +/* Copy data from the given buffer to the current data position, updating the + position and the extent of populated data if this was exceeded. */ + +void file_data_write(file_t *file, char *buf, size_t to_transfer) +{ + memcpy(file_data_current(file), buf, to_transfer); + + /* Update position details. */ + + file->data_current += to_transfer; + + if (file->data_current > file->data_end) + file->data_end = file->data_current; +} + + + /* Open two pipe endpoints using the given pipe server. */ long pipe_open(offset_t size, file_t *reader, file_t *writer, l4_cap_idx_t server) @@ -248,6 +368,11 @@ file_init(reader); file_init(writer); + /* Pipes can usually only be accessed via region navigation. */ + + reader->can_mmap = 0; + writer->can_mmap = 0; + long err = opener.pipe(size, &reader->ref, &writer->ref); if (err) return err; diff -r 94aa665bf115 -r 00dc57806375 client/file.h --- a/client/file.h Thu Apr 08 23:55:47 2021 +0200 +++ b/client/file.h Sun Apr 11 19:34:07 2021 +0200 @@ -42,12 +42,17 @@ /* File region parameters. */ offset_t start_pos, end_pos; /* start and end positions of region */ - offset_t data_end; /* amount of data in the region */ + offset_t data_end; /* amount/extent of data in the region */ + offset_t data_current; /* client access offset */ /* Total size of file. */ offset_t size; + /* Arbitrary memory mapping support. */ + + int can_mmap; + } file_t; @@ -65,6 +70,7 @@ /* File and region operations. */ +long file_flush(file_t *file); long file_mmap(file_t *file, offset_t position, offset_t length); long file_resize(file_t *file, offset_t size); @@ -78,6 +84,19 @@ char *file_string_get(file_t *file, offset_t offset); int file_string_set(file_t *file, const char *data, offset_t offset, offset_t *written); +/* Client data functions. */ + +offset_t file_data_available(file_t *file); +char *file_data_current(file_t *file); +offset_t file_data_current_position(file_t *file); +offset_t file_data_end_position(file_t *file); +offset_t file_data_space(file_t *file); + +/* Client data transfer functions. */ + +void file_data_read(file_t *file, char *buf, size_t to_transfer); +void file_data_write(file_t *file, char *buf, size_t to_transfer); + /* Pipe operations. */ diff -r 94aa665bf115 -r 00dc57806375 conf/dstest_block_simple.cfg --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/conf/dstest_block_simple.cfg Sun Apr 11 19:34:07 2021 +0200 @@ -0,0 +1,23 @@ +-- vim:set ft=lua: + +local L4 = require("L4"); + +local l = L4.default_loader; + +local server = l:new_channel(); + +l:startv({ + caps = { + server = server:svr(), + }, + log = { "server", "r" }, + }, + "rom/dstest_block_server", "10"); + +l:startv({ + caps = { + server = server, + }, + log = { "client", "g" }, + }, + "rom/dstest_block_client_simple", "rom/dstest_block_simple.cfg"); diff -r 94aa665bf115 -r 00dc57806375 conf/dstest_block_simple.list --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/conf/dstest_block_simple.list Sun Apr 11 19:34:07 2021 +0200 @@ -0,0 +1,25 @@ +entry dstest_block_simple +roottask moe rom/dstest_block_simple.cfg +module dstest_block_simple.cfg +module l4re +module ned +module dstest_block_client_simple +module dstest_block_server +module lib4re-c.so +module lib4re-c-util.so +module lib4re.so +module lib4re-util.so +module libc_be_l4refile.so +module libc_be_l4re.so +module libc_be_socket_noop.so +module libc_support_misc.so +module libdl.so +module libipc.so +module libl4sys-direct.so +module libl4sys.so +module libl4util.so +module libld-l4.so +module libpthread.so +module libstdc++.so +module libsupc++.so +module libuc_c.so diff -r 94aa665bf115 -r 00dc57806375 files/file_pager.cc --- a/files/file_pager.cc Thu Apr 08 23:55:47 2021 +0200 +++ b/files/file_pager.cc Sun Apr 11 19:34:07 2021 +0200 @@ -44,20 +44,12 @@ return Pager::resize(size); } -long FilePager::mmap(offset_t position, offset_t length, offset_t *start_pos, offset_t *end_pos, offset_t *data_end) +long FilePager::mmap(offset_t position, offset_t length, offset_t *start_pos, + offset_t *end_pos, offset_t *size) { /* Set the limits of the paged region. */ - Pager::mmap(position, length, start_pos, end_pos, data_end); - - /* Obtain the amount of the region that is populated with file data. */ - - *data_end = get_data_size() - _start; - - if (*data_end > _size) - *data_end = _size; - - return L4_EOK; + return Pager::mmap(position, length, start_pos, end_pos, size); } diff -r 94aa665bf115 -r 00dc57806375 files/file_pager.h --- a/files/file_pager.h Thu Apr 08 23:55:47 2021 +0200 +++ b/files/file_pager.h Sun Apr 11 19:34:07 2021 +0200 @@ -36,9 +36,11 @@ /* Pager and mapped file methods. */ - virtual long map(unsigned long offset, l4_addr_t hot_spot, flags_t flags, l4_snd_fpage_t *region); + virtual long map(unsigned long offset, l4_addr_t hot_spot, flags_t flags, + l4_snd_fpage_t *region); - virtual long mmap(offset_t position, offset_t length, offset_t *start_pos, offset_t *end_pos, offset_t *data_end); + virtual long mmap(offset_t position, offset_t length, offset_t *start_pos, + offset_t *end_pos, offset_t *size); }; // vim: tabstop=4 expandtab shiftwidth=4 diff -r 94aa665bf115 -r 00dc57806375 generic/pager.cc --- a/generic/pager.cc Thu Apr 08 23:55:47 2021 +0200 +++ b/generic/pager.cc Sun Apr 11 19:34:07 2021 +0200 @@ -46,14 +46,19 @@ /* Expose a region of the file. */ -long Pager::mmap(offset_t position, offset_t length, offset_t *start_pos, offset_t *end_pos, offset_t *data_end) +long Pager::mmap(offset_t position, offset_t length, offset_t *start_pos, + offset_t *end_pos, offset_t *size) { + /* Define region characteristics. */ + _start = trunc(position, PAGE_SIZE); _size = round(position + length, PAGE_SIZE) - _start; + /* Return the start and end positions plus populated extent. */ + *start_pos = _start; *end_pos = _start + _size; - *data_end = 0; + *size = _mapper->get_data_size(); return L4_EOK; } @@ -61,7 +66,8 @@ /* Map a flexpage corresponding to the dataspace 'offset' involving a 'hot_spot' (flexpage offset). */ -long Pager::map(offset_t offset, l4_addr_t hot_spot, flags_t flags, l4_snd_fpage_t *region) +long Pager::map(offset_t offset, l4_addr_t hot_spot, flags_t flags, + l4_snd_fpage_t *region) { offset_t file_offset = _start + offset; offset_t max_offset = _start + _size; diff -r 94aa665bf115 -r 00dc57806375 generic/pager.h --- a/generic/pager.h Thu Apr 08 23:55:47 2021 +0200 +++ b/generic/pager.h Sun Apr 11 19:34:07 2021 +0200 @@ -23,7 +23,8 @@ /* Paging methods. */ - virtual long map(offset_t offset, l4_addr_t hot_spot, flags_t flags, l4_snd_fpage_t *region); + virtual long map(offset_t offset, l4_addr_t hot_spot, flags_t flags, + l4_snd_fpage_t *region); /* Limit methods. */ @@ -37,7 +38,8 @@ /* Mapped file methods. */ - virtual long mmap(offset_t position, offset_t length, offset_t *start_pos, offset_t *end_pos, offset_t *data_end); + virtual long mmap(offset_t position, offset_t length, offset_t *start_pos, + offset_t *end_pos, offset_t *size); }; // vim: tabstop=4 expandtab shiftwidth=4 diff -r 94aa665bf115 -r 00dc57806375 tests/dstest_block_client_simple.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/dstest_block_client_simple.cc Sun Apr 11 19:34:07 2021 +0200 @@ -0,0 +1,130 @@ +/* + * Test dataspace operations. + * + * Copyright (C) 2020, 2021 Paul Boddie + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + */ + +#include + +#include + +#include "client.h" + + + +int main(int argc, char *argv[]) +{ + if (argc < 2) + { + printf("Need a filename.\n"); + return 1; + } + + /* Obtain filename and access parameters. */ + + char *filename = argv[1]; + + /* Invoke the open method to receive the file reference. */ + + file_t *file = client_open(filename, O_RDWR); + + if (file == NULL) + { + printf("Could not obtain file.\n"); + return 1; + } + + /* Map some memory. */ + + void *addr = client_mmap(file, 0, 1024); + + if (addr == NULL) + { + printf("Could not map memory.\n"); + return 1; + } + + printf("At mapped region from %ld to %ld with data at %ld to %ld.\n", + file->start_pos, file->end_pos, file->data_current, file->data_end); + + /* Copy the sampled data to another file region. */ + + offset_t size = file->size; + char buffer[size]; + offset_t nread = client_read(file, buffer, size); + + if (nread != size) + { + printf("Could not read entire file: %ld out of %ld bytes.\n", nread, size); + return 1; + } + + printf("File contents...\n"); + + fwrite(buffer, sizeof(char), nread, stdout); + + printf("Copy %ld bytes to end...\n", nread); + + for (int times = 0; times < 10; times++) + { + printf("Copy #%d...\n", times); + + offset_t nwritten = client_write(file, buffer, nread); + + if (nwritten != nread) + { + printf("Could not write file section: %ld instead of %ld bytes.\n", + nwritten, nread); + return 1; + } + } + + printf("File is now %ld in size.\n", file->size); + + printf("Seek to start...\n"); + + client_seek(file, 0, SEEK_SET); + + printf("At mapped region from %ld to %ld with data at %ld to %ld.\n", + file->start_pos, file->end_pos, file->data_current, file->data_end); + + printf("File contents...\n"); + + offset_t position = 0; + + while (position < file->size) + { + offset_t nread = client_read(file, buffer, size); + + if ((nread != size) && (nread != file->size - position)) + { + printf("Could not read file section: %ld instead of %ld or remaining %ld bytes.\n", + nread, size, file->size - position); + return 1; + } + + fwrite(buffer, sizeof(char), nread, stdout); + position += nread; + } + + printf("File shown.\n"); + + return 0; +} + +// vim: tabstop=2 expandtab shiftwidth=2