1.1 --- a/client/file.cc Tue Apr 13 00:03:18 2021 +0200
1.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
1.3 @@ -1,452 +0,0 @@
1.4 -/*
1.5 - * File access convenience functions.
1.6 - *
1.7 - * Copyright (C) 2021 Paul Boddie <paul@boddie.org.uk>
1.8 - *
1.9 - * This program is free software; you can redistribute it and/or
1.10 - * modify it under the terms of the GNU General Public License as
1.11 - * published by the Free Software Foundation; either version 2 of
1.12 - * the License, or (at your option) any later version.
1.13 - *
1.14 - * This program is distributed in the hope that it will be useful,
1.15 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
1.16 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1.17 - * GNU General Public License for more details.
1.18 - *
1.19 - * You should have received a copy of the GNU General Public License
1.20 - * along with this program; if not, write to the Free Software
1.21 - * Foundation, Inc., 51 Franklin Street, Fifth Floor,
1.22 - * Boston, MA 02110-1301, USA
1.23 - */
1.24 -
1.25 -#include <ipc/cap_alloc.h>
1.26 -#include <ipc/mem_ipc.h>
1.27 -
1.28 -#include <string.h>
1.29 -
1.30 -#include "dataspace_client.h"
1.31 -#include "file_client.h"
1.32 -#include "opener_client.h"
1.33 -#include "opener_context_client.h"
1.34 -#include "pipe_client.h"
1.35 -#include "pipe_opener_client.h"
1.36 -#include "mapped_file_client.h"
1.37 -
1.38 -#include "file.h"
1.39 -
1.40 -
1.41 -
1.42 -/* Update the extent of the file in a region using the region start and end
1.43 - positions and the file size. */
1.44 -
1.45 -static void _update_extent(file_t *file)
1.46 -{
1.47 - /* Handle files ending after or within the region. */
1.48 -
1.49 - if (file->size > file->start_pos)
1.50 - {
1.51 - if (file->size > file->end_pos)
1.52 - file->data_end = file->end_pos - file->start_pos;
1.53 - else
1.54 - file->data_end = file->size - file->start_pos;
1.55 - }
1.56 -
1.57 - /* Handle files ending before the region. */
1.58 -
1.59 - else
1.60 - file->data_end = 0;
1.61 -}
1.62 -
1.63 -
1.64 -
1.65 -/* Initialise the given file structure. */
1.66 -
1.67 -void file_init(file_t *file)
1.68 -{
1.69 - file->memory = NULL;
1.70 - file->ref = L4_INVALID_CAP;
1.71 - file->start_pos = 0;
1.72 - file->end_pos = 0;
1.73 - file->data_end = 0;
1.74 - file->data_current = 0;
1.75 - file->can_mmap = 1;
1.76 -}
1.77 -
1.78 -
1.79 -
1.80 -/* Release resources for the given file. */
1.81 -
1.82 -void file_close(file_t *file)
1.83 -{
1.84 - if (l4_is_valid_cap(file->ref))
1.85 - ipc_cap_free_um(file->ref);
1.86 -
1.87 - if (file->memory != NULL)
1.88 - ipc_detach_dataspace(file->memory);
1.89 -
1.90 - file_init(file);
1.91 -}
1.92 -
1.93 -/* Open a file using the given structure, indicating the filename and
1.94 - filesystem server. The file_mmap function should be used to obtain access to
1.95 - memory providing file data. This is a convenience function invoking
1.96 - file_context and file_context_open. */
1.97 -
1.98 -long file_open(file_t *file, const char *filename, flags_t flags, l4_cap_idx_t server)
1.99 -{
1.100 - file_t context;
1.101 - long err;
1.102 -
1.103 - err = file_context(&context, server);
1.104 - if (err)
1.105 - return err;
1.106 -
1.107 - if (!file_string_set(&context, filename, 0, NULL))
1.108 - return -L4_ENOMEM;
1.109 -
1.110 - err = file_context_open(file, flags, &context);
1.111 -
1.112 - /* Close the context, although a separate mechanism could permit contexts to
1.113 - open several files. */
1.114 -
1.115 - file_close(&context);
1.116 - return err;
1.117 -}
1.118 -
1.119 -
1.120 -
1.121 -/* Initialise a file structure for a context obtained from the given server
1.122 - attaching memory to communicate filename information. */
1.123 -
1.124 -long file_context(file_t *file, l4_cap_idx_t server)
1.125 -{
1.126 - if (l4_is_invalid_cap(server))
1.127 - return -L4_EINVAL;
1.128 -
1.129 - client_Opener opener(server);
1.130 - offset_t size;
1.131 - flags_t flags;
1.132 - long err;
1.133 -
1.134 - file_init(file);
1.135 -
1.136 - err = opener.context(&file->ref);
1.137 - if (err)
1.138 - return err;
1.139 -
1.140 - client_Dataspace context_ds(file->ref);
1.141 -
1.142 - err = context_ds.info(&size, &flags);
1.143 - if (err)
1.144 - return err;
1.145 -
1.146 - file->start_pos = 0;
1.147 - file->end_pos = size;
1.148 -
1.149 - return ipc_attach_dataspace(file->ref, size, (void **) &file->memory);
1.150 -}
1.151 -
1.152 -/* Open a file using the given structure and context. */
1.153 -
1.154 -long file_context_open(file_t *file, flags_t flags, file_t *context)
1.155 -{
1.156 - client_OpenerContext openercontext(context->ref);
1.157 - file_init(file);
1.158 - return openercontext.open(flags, &file->size, &file->ref);
1.159 -}
1.160 -
1.161 -
1.162 -
1.163 -/* Flush populated data and obtain an updated file size and populated data
1.164 - details. */
1.165 -
1.166 -long file_flush(file_t *file)
1.167 -{
1.168 - client_File _file(file->ref);
1.169 - long err = _file.flush(file->data_current, &file->size);
1.170 -
1.171 - if (err)
1.172 - return err;
1.173 -
1.174 - _update_extent(file);
1.175 -
1.176 - return L4_EOK;
1.177 -}
1.178 -
1.179 -/* Map a region of the given file to a memory region, obtaining an updated file
1.180 - size and populated data details. Unmap any previously mapped region. */
1.181 -
1.182 -long file_mmap(file_t *file, offset_t position, offset_t length)
1.183 -{
1.184 - char *memory = file->memory;
1.185 - client_MappedFile mapped_file(file->ref);
1.186 - long err = mapped_file.mmap(position, length, &file->start_pos,
1.187 - &file->end_pos, &file->size);
1.188 -
1.189 - if (err)
1.190 - return err;
1.191 -
1.192 - _update_extent(file);
1.193 -
1.194 - err = ipc_attach_dataspace(file->ref, file_span(file), (void **) &file->memory);
1.195 - if (err)
1.196 - return err;
1.197 -
1.198 - if (memory != NULL)
1.199 - ipc_detach_dataspace(memory);
1.200 -
1.201 - return L4_EOK;
1.202 -}
1.203 -
1.204 -/* Resize a file, obtaining updated file size and populated data details. */
1.205 -
1.206 -long file_resize(file_t *file, offset_t size)
1.207 -{
1.208 - client_File _file(file->ref);
1.209 - offset_t file_size = size;
1.210 - long err = _file.resize(&file_size);
1.211 -
1.212 - if (err)
1.213 - return err;
1.214 -
1.215 - file->size = file_size;
1.216 - _update_extent(file);
1.217 - return L4_EOK;
1.218 -}
1.219 -
1.220 -
1.221 -
1.222 -/* Return the amount of data in the mapped region for the given file. */
1.223 -
1.224 -offset_t file_populated_span(file_t *file)
1.225 -{
1.226 - offset_t size = file_span(file);
1.227 - return (file->data_end < size) ? file->data_end : size;
1.228 -}
1.229 -
1.230 -/* Return the size of the mapped region for the given file. */
1.231 -
1.232 -offset_t file_span(file_t *file)
1.233 -{
1.234 - return file->end_pos - file->start_pos;
1.235 -}
1.236 -
1.237 -
1.238 -
1.239 -/* Get a pointer to any terminated string at the given offset or NULL if the
1.240 - data from offset is not terminated. */
1.241 -
1.242 -char *file_string_get(file_t *file, offset_t offset)
1.243 -{
1.244 - offset_t limit = file_span(file) - offset;
1.245 -
1.246 - if (strnlen(file->memory + offset, limit) < limit)
1.247 - return file->memory + offset;
1.248 - else
1.249 - return NULL;
1.250 -}
1.251 -
1.252 -/* Copy a string to the mapped region at the given offset, returning 1 (true)
1.253 - where all characters were copied, 0 (false) otherwise. The precise number of
1.254 - characters copied, excluding the zero terminator is provided via the written
1.255 - parameter if it is not specified as NULL. */
1.256 -
1.257 -int file_string_set(file_t *file, const char *data, offset_t offset,
1.258 - offset_t *written)
1.259 -{
1.260 - offset_t i, pos, limit = file_span(file);
1.261 -
1.262 - /* Do not attempt to copy data with an invalid offset. */
1.263 -
1.264 - if (offset >= limit)
1.265 - {
1.266 - if (written != NULL)
1.267 - *written = 0;
1.268 - return 0;
1.269 - }
1.270 -
1.271 - /* Copy the data to the given offset, stopping at the end of the region. */
1.272 -
1.273 - for (i = 0, pos = offset; pos < limit; i++, pos++)
1.274 - {
1.275 - file->memory[pos] = data[i];
1.276 -
1.277 - /* Terminator written, can return immediately. */
1.278 -
1.279 - if (!data[i])
1.280 - {
1.281 - if (written != NULL)
1.282 - *written = pos - offset;
1.283 - return 1;
1.284 - }
1.285 - }
1.286 -
1.287 - /* Terminate the incomplete string at the end of the region. */
1.288 -
1.289 - file->memory[limit - 1] = '\0';
1.290 - if (written != NULL)
1.291 - *written = limit - 1 - offset;
1.292 - return 0;
1.293 -}
1.294 -
1.295 -
1.296 -
1.297 -/* Return the number of remaining populated bytes in the region. */
1.298 -
1.299 -offset_t file_data_available(file_t *file)
1.300 -{
1.301 - return file_populated_span(file) - file->data_current;
1.302 -}
1.303 -
1.304 -/* Return the current data offset in the region. */
1.305 -
1.306 -char *file_data_current(file_t *file)
1.307 -{
1.308 - return file->memory + file->data_current;
1.309 -}
1.310 -
1.311 -/* Return the current access position in the file. */
1.312 -
1.313 -offset_t file_data_current_position(file_t *file)
1.314 -{
1.315 - return file->start_pos + file->data_current;
1.316 -}
1.317 -
1.318 -/* Return the position of the end of the populated bytes in the region. */
1.319 -
1.320 -offset_t file_data_end_position(file_t *file)
1.321 -{
1.322 - return file->start_pos + file->data_end;
1.323 -}
1.324 -
1.325 -/* Return the amount of remaining space in the region. */
1.326 -
1.327 -offset_t file_data_space(file_t *file)
1.328 -{
1.329 - return file_span(file) - file->data_current;
1.330 -}
1.331 -
1.332 -
1.333 -
1.334 -/* Copy data to the given buffer from the current data position, updating the
1.335 - position. */
1.336 -
1.337 -void file_data_read(file_t *file, char *buf, size_t to_transfer)
1.338 -{
1.339 - memcpy(buf, file_data_current(file), to_transfer);
1.340 -
1.341 - /* Update position details. */
1.342 -
1.343 - file->data_current += to_transfer;
1.344 -}
1.345 -
1.346 -/* Copy data from the given buffer to the current data position, updating the
1.347 - position and the extent of populated data if this was exceeded. */
1.348 -
1.349 -void file_data_write(file_t *file, char *buf, size_t to_transfer)
1.350 -{
1.351 - memcpy(file_data_current(file), buf, to_transfer);
1.352 -
1.353 - /* Update position details. */
1.354 -
1.355 - file->data_current += to_transfer;
1.356 -
1.357 - if (file->data_current > file->data_end)
1.358 - file->data_end = file->data_current;
1.359 -}
1.360 -
1.361 -
1.362 -
1.363 -/* Open two pipe endpoints using the given pipe server. */
1.364 -
1.365 -long pipe_open(offset_t size, file_t *reader, file_t *writer, l4_cap_idx_t server)
1.366 -{
1.367 - if (l4_is_invalid_cap(server))
1.368 - return -L4_EINVAL;
1.369 -
1.370 - client_PipeOpener opener(server);
1.371 -
1.372 - file_init(reader);
1.373 - file_init(writer);
1.374 -
1.375 - /* Pipes can usually only be accessed via region navigation. */
1.376 -
1.377 - reader->can_mmap = 0;
1.378 - writer->can_mmap = 0;
1.379 -
1.380 - long err = opener.pipe(size, &reader->ref, &writer->ref);
1.381 - if (err)
1.382 - return err;
1.383 -
1.384 - err = pipe_next(writer) || pipe_next(reader);
1.385 -
1.386 - if (err)
1.387 - {
1.388 - file_close(reader);
1.389 - file_close(writer);
1.390 - }
1.391 -
1.392 - return err;
1.393 -}
1.394 -
1.395 -/* Access the current region for a pipe endpoint. */
1.396 -
1.397 -long pipe_current(file_t *pipe)
1.398 -{
1.399 - client_Pipe _pipe(pipe->ref);
1.400 - long err = _pipe.current_region(&pipe->data_end, &pipe->size);
1.401 - char *memory = pipe->memory;
1.402 -
1.403 - if (err)
1.404 - return err;
1.405 -
1.406 - pipe->end_pos = pipe->size;
1.407 -
1.408 - err = ipc_attach_dataspace(pipe->ref, file_span(pipe), (void **) &pipe->memory);
1.409 - if (err)
1.410 - return err;
1.411 -
1.412 - if (memory != NULL)
1.413 - ipc_detach_dataspace(memory);
1.414 -
1.415 - return L4_EOK;
1.416 -}
1.417 -
1.418 -/* Access the next region for a pipe endpoint, updating the eventual size of
1.419 - the current region. */
1.420 -
1.421 -long pipe_next(file_t *pipe)
1.422 -{
1.423 - client_Pipe _pipe(pipe->ref);
1.424 - long err = _pipe.next_region(&pipe->data_end, &pipe->size);
1.425 - char *memory = pipe->memory;
1.426 -
1.427 - if (err)
1.428 - return err;
1.429 -
1.430 - pipe->end_pos = pipe->size;
1.431 -
1.432 - err = ipc_attach_dataspace(pipe->ref, file_span(pipe), (void **) &pipe->memory);
1.433 - if (err)
1.434 - return err;
1.435 -
1.436 - if (memory != NULL)
1.437 - ipc_detach_dataspace(memory);
1.438 -
1.439 - return L4_EOK;
1.440 -}
1.441 -
1.442 -/* Set the size of the written region. */
1.443 -
1.444 -long pipe_written(file_t *pipe, offset_t size)
1.445 -{
1.446 - if (size <= pipe->size)
1.447 - {
1.448 - pipe->data_end = size;
1.449 - return L4_EOK;
1.450 - }
1.451 - else
1.452 - return -L4_EINVAL;
1.453 -}
1.454 -
1.455 -// vim: tabstop=2 expandtab shiftwidth=2