1.1 --- a/libfsclient/lib/src/client.cc Sat May 15 23:38:39 2021 +0200
1.2 +++ b/libfsclient/lib/src/client.cc Tue May 18 00:55:20 2021 +0200
1.3 @@ -34,6 +34,114 @@
1.4
1.5
1.6
1.7 +/* Access the given position and synchronise state with the file object. */
1.8 +
1.9 +static long _access(file_t *file, offset_t position)
1.10 +{
1.11 + long err;
1.12 +
1.13 + if (file->can_mmap)
1.14 + {
1.15 + /* Where the position is outside the current region, re-map. */
1.16 +
1.17 + if ((position < file->start_pos) || (position >= file->end_pos))
1.18 + {
1.19 + if (file_mmap(file, position, file_span(file)))
1.20 + return -L4_EIO;
1.21 + }
1.22 +
1.23 + /* Otherwise, flush any written data in the current region and update the
1.24 + file size details. */
1.25 +
1.26 + else
1.27 + {
1.28 + err = client_flush(file);
1.29 + if (err)
1.30 + return err;
1.31 + }
1.32 + }
1.33 + else
1.34 + {
1.35 + /* Strict conditions for region navigation in pipes. */
1.36 +
1.37 + if ((position < file->start_pos) || (position > file->end_pos))
1.38 + {
1.39 + return -L4_EIO;
1.40 + }
1.41 +
1.42 + /* The next region is only available at the end of the mapped memory. */
1.43 +
1.44 + else if (position == file->end_pos)
1.45 + {
1.46 + err = client_next_region(file);
1.47 + if (err)
1.48 + return err;
1.49 +
1.50 + file->data_current = 0;
1.51 + return L4_EOK;
1.52 + }
1.53 +
1.54 + /* Within the current pipe region, synchronise with the pipe object. */
1.55 +
1.56 + else
1.57 + {
1.58 + err = client_current_region(file);
1.59 + if (err)
1.60 + return err;
1.61 + }
1.62 + }
1.63 +
1.64 + /* Update the current data offset. */
1.65 +
1.66 + file->data_current = position - file->start_pos;
1.67 +
1.68 + return L4_EOK;
1.69 +}
1.70 +
1.71 +
1.72 +
1.73 +/* Return whether an access could occur, blocking if necessary. */
1.74 +
1.75 +static int _access_blocking(file_t *file, offset_t position)
1.76 +{
1.77 + long err;
1.78 +
1.79 + while ((err = _access(file, position)))
1.80 + {
1.81 + /* Exit if blocking is not configured or suitable. */
1.82 +
1.83 + if ((err != -L4_EBUSY) || !file->can_block)
1.84 + return 0;
1.85 +
1.86 + /* Handle an inability to access by blocking, exiting if waiting failed. */
1.87 +
1.88 + if (client_wait(file))
1.89 + return 0;
1.90 + }
1.91 +
1.92 + return 1;
1.93 +}
1.94 +
1.95 +
1.96 +
1.97 +/* Ensure that memory is mapped for accessing the given file, using the
1.98 + indicated count as a region size hint. */
1.99 +
1.100 +static void *_map_memory(file_t *file, offset_t count)
1.101 +{
1.102 + if (file->memory == NULL)
1.103 + {
1.104 + if (file->can_mmap)
1.105 + return client_mmap(file, client_tell(file), count);
1.106 + else if (pipe_current(file))
1.107 + return NULL;
1.108 + }
1.109 +
1.110 + return file->memory;
1.111 +}
1.112 +
1.113 +
1.114 +
1.115 /* Close a filesystem object. */
1.116
1.117 void client_close(file_t *file)
1.118 @@ -108,72 +216,6 @@
1.119
1.120
1.121
1.122 -/* Access the given position and synchronise state with the file object. */
1.123 -
1.124 -static long _access(file_t *file, offset_t position)
1.125 -{
1.126 - long err;
1.127 -
1.128 - if (file->can_mmap)
1.129 - {
1.130 - /* Where the position is outside the current region, re-map. */
1.131 -
1.132 - if ((position < file->start_pos) || (position >= file->end_pos))
1.133 - {
1.134 - if (file_mmap(file, position, file_span(file)))
1.135 - return -L4_EIO;
1.136 - }
1.137 -
1.138 - /* Otherwise, flush any written data in the current region and update the
1.139 - file size details. */
1.140 -
1.141 - else
1.142 - {
1.143 - err = client_flush(file);
1.144 - if (err)
1.145 - return err;
1.146 - }
1.147 - }
1.148 - else
1.149 - {
1.150 - /* Strict conditions for region navigation in pipes. */
1.151 -
1.152 - if ((position < file->start_pos) || (position > file->end_pos))
1.153 - {
1.154 - return -L4_EIO;
1.155 - }
1.156 -
1.157 - /* The next region is only available at the end of the mapped memory. */
1.158 -
1.159 - else if (position == file->end_pos)
1.160 - {
1.161 - err = client_next_region(file);
1.162 - if (err)
1.163 - return err;
1.164 - }
1.165 -
1.166 - /* Within the current pipe region, synchronise with the pipe object. */
1.167 -
1.168 - else
1.169 - {
1.170 - err = client_current_region(file);
1.171 - if (err)
1.172 - return err;
1.173 - }
1.174 - }
1.175 -
1.176 - /* Update the current data offset. */
1.177 -
1.178 - if (file->has_size)
1.179 - file->data_current = position - file->start_pos;
1.180 - else
1.181 - file->data_current = 0;
1.182 -
1.183 - return L4_EOK;
1.184 -}
1.185 -
1.186 -
1.187 -
1.188 /* Flush data explicitly to the filesystem object. */
1.189
1.190 long client_flush(file_t *file)
1.191 @@ -224,24 +266,6 @@
1.192
1.193
1.194
1.195 -/* Ensure that memory is mapped for accessing the given file, using the
1.196 - indicated count as a region size hint. */
1.197 -
1.198 -static void *_map_memory(file_t *file, offset_t count)
1.199 -{
1.200 - if (file->memory == NULL)
1.201 - {
1.202 - if (file->can_mmap)
1.203 - return client_mmap(file, client_tell(file), count);
1.204 - else if (pipe_current(file))
1.205 - return NULL;
1.206 - }
1.207 -
1.208 - return file->memory;
1.209 -}
1.210 -
1.211 -
1.212 -
1.213 /* Read from the filesystem object into the buffer provided. */
1.214
1.215 offset_t client_read(file_t *file, void *buf, offset_t count)
1.216 @@ -268,7 +292,7 @@
1.217 /* Flush any unwritten data, preparing to read from the file position at
1.218 the end of the data, and returning if no new data is available. */
1.219
1.220 - if (_access(file, file_data_end_position(file)))
1.221 + if (!_access_blocking(file, file_data_end_position(file)))
1.222 break;
1.223
1.224 available = file_data_available(file);
1.225 @@ -323,7 +347,7 @@
1.226
1.227 default:
1.228 /* NOTE: Set errno to EINVAL. */
1.229 - return -1;
1.230 + return current;
1.231 }
1.232
1.233 /* Retain the current position if unchanged. */
1.234 @@ -365,12 +389,53 @@
1.235
1.236 /* Handle unwritten data and reset the buffer for reading. */
1.237
1.238 - _access(file, position);
1.239 + if (_access(file, position))
1.240 + return current;
1.241 +
1.242 return position;
1.243 }
1.244
1.245
1.246
1.247 +/* Set or unset blocking access for a file. */
1.248 +
1.249 +long client_set_blocking(file_t *file, int can_block)
1.250 +{
1.251 + long err;
1.252 +
1.253 + if (file->can_block == can_block)
1.254 + return L4_EOK;
1.255 +
1.256 + // NOTE: Set appropriate flags.
1.257 +
1.258 + if (can_block)
1.259 + err = client_subscribe(file, 0);
1.260 + else
1.261 + err = client_unsubscribe(file);
1.262 +
1.263 + if (err)
1.264 + return err;
1.265 +
1.266 + file->can_block = can_block;
1.267 + return L4_EOK;
1.268 +}
1.269 +
1.270 +
1.271 +
1.272 +/* Subscribe from events concerning a file. */
1.273 +
1.274 +long client_subscribe(file_t *file, flags_t flags)
1.275 +{
1.276 + if (file == NULL)
1.277 + return -L4_EINVAL;
1.278 +
1.279 + return file_notify_subscribe(file, flags);
1.280 +}
1.281 +
1.282 +
1.283 +
1.284 +/* Return the current position in the file. */
1.285 +
1.286 long client_tell(file_t *file)
1.287 {
1.288 if (file == NULL)
1.289 @@ -381,6 +446,30 @@
1.290
1.291
1.292
1.293 +/* Unsubscribe from events concerning a file. */
1.294 +
1.295 +long client_unsubscribe(file_t *file)
1.296 +{
1.297 + if (file == NULL)
1.298 + return -L4_EINVAL;
1.299 +
1.300 + return file_notify_unsubscribe(file);
1.301 +}
1.302 +
1.303 +
1.304 +
1.305 +/* Register for events concerning a file. */
1.306 +
1.307 +long client_wait(file_t *file)
1.308 +{
1.309 + if (file == NULL)
1.310 + return -L4_EINVAL;
1.311 +
1.312 + return file_notify_wait(file);
1.313 +}
1.314 +
1.315 +
1.316 +
1.317 /* Write to the filesystem object from the buffer provided. */
1.318
1.319 offset_t client_write(file_t *file, const void *buf, offset_t count)
1.320 @@ -424,7 +513,7 @@
1.321 /* Flush any unwritten data and continue writing from the current data
1.322 position. */
1.323
1.324 - if (_access(file, file_data_current_position(file)))
1.325 + if (!_access_blocking(file, file_data_current_position(file)))
1.326 break;
1.327
1.328 space = file_data_space(file);