source: mainline/uspace/srv/fs/tmpfs/tmpfs_ops.c@ 5e801dc

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 5e801dc was 5e801dc, checked in by GitHub <noreply@…>, 6 years ago

Indicate and enforce constness of hash table key in certain functions (#158)

The assumption here is that modifying key in the hash/equal functions in something completely unexpected, and not something you would ever want to do intentionally, so it makes sense to disallow it entirely to get that extra level of checking.

  • Property mode set to 100644
File size: 15.1 KB
RevLine 
[d5cdffe]1/*
[41a0d27]2 * Copyright (c) 2008 Jakub Jermar
[d5cdffe]3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
[b1834a01]29/** @addtogroup tmpfs
[d5cdffe]30 * @{
[ed903174]31 */
[d5cdffe]32
33/**
34 * @file tmpfs_ops.c
35 * @brief Implementation of VFS operations for the TMPFS file system
36 * server.
37 */
38
39#include "tmpfs.h"
40#include "../../vfs/vfs.h"
[ed903174]41#include <macros.h>
[9539be6]42#include <stdint.h>
[d5cdffe]43#include <async.h>
44#include <errno.h>
[4b11571]45#include <stdlib.h>
[19f857a]46#include <str.h>
[4b11571]47#include <stdio.h>
[5973fd0]48#include <assert.h>
[8d2dd7f2]49#include <stddef.h>
[d9c8c81]50#include <adt/hash_table.h>
[062d900]51#include <adt/hash.h>
[a4eb8a60]52#include <as.h>
[2c448fb]53#include <libfs.h>
[a4eb8a60]54
[8d049ee0]55/** All root nodes have index 0. */
[984a9ba]56#define TMPFS_SOME_ROOT 0
57
[8d049ee0]58/** Global counter for assigning node indices. Shared by all instances. */
59fs_index_t tmpfs_next_index = 1;
[adb5fe3]60
[2c448fb]61/*
62 * Implementation of the libfs interface.
63 */
[b5553a2]64
[fdb7795]65/* Forward declarations of static functions. */
[b7fd2a0]66static errno_t tmpfs_match(fs_node_t **, fs_node_t *, const char *);
67static errno_t tmpfs_node_get(fs_node_t **, service_id_t, fs_index_t);
68static errno_t tmpfs_node_open(fs_node_t *);
69static errno_t tmpfs_node_put(fs_node_t *);
70static errno_t tmpfs_create_node(fs_node_t **, service_id_t, int);
71static errno_t tmpfs_destroy_node(fs_node_t *);
72static errno_t tmpfs_link_node(fs_node_t *, fs_node_t *, const char *);
73static errno_t tmpfs_unlink_node(fs_node_t *, fs_node_t *, const char *);
[2c448fb]74
75/* Implementation of helper functions. */
[b7fd2a0]76static errno_t tmpfs_root_get(fs_node_t **rfn, service_id_t service_id)
[2c448fb]77{
[1b20da0]78 return tmpfs_node_get(rfn, service_id, TMPFS_SOME_ROOT);
[2c448fb]79}
80
[b7fd2a0]81static errno_t tmpfs_has_children(bool *has_children, fs_node_t *fn)
[2c448fb]82{
[b72efe8]83 *has_children = !list_empty(&TMPFS_NODE(fn)->cs_list);
[54e4479]84 return EOK;
[2c448fb]85}
86
[54e4479]87static fs_index_t tmpfs_index_get(fs_node_t *fn)
[2c448fb]88{
[54e4479]89 return TMPFS_NODE(fn)->index;
[2c448fb]90}
91
[ed903174]92static aoff64_t tmpfs_size_get(fs_node_t *fn)
[2c448fb]93{
[54e4479]94 return TMPFS_NODE(fn)->size;
[2c448fb]95}
96
[54e4479]97static unsigned tmpfs_lnkcnt_get(fs_node_t *fn)
[2c448fb]98{
[54e4479]99 return TMPFS_NODE(fn)->lnkcnt;
[2c448fb]100}
101
[b6035ba]102static bool tmpfs_is_directory(fs_node_t *fn)
[2c448fb]103{
[b6035ba]104 return TMPFS_NODE(fn)->type == TMPFS_DIRECTORY;
[2c448fb]105}
106
[b6035ba]107static bool tmpfs_is_file(fs_node_t *fn)
[2c448fb]108{
[b6035ba]109 return TMPFS_NODE(fn)->type == TMPFS_FILE;
[2c448fb]110}
111
[b33870b]112static service_id_t tmpfs_service_get(fs_node_t *fn)
[1313ee9]113{
114 return 0;
115}
116
[2c448fb]117/** libfs operations */
118libfs_ops_t tmpfs_libfs_ops = {
[54e4479]119 .root_get = tmpfs_root_get,
[2c448fb]120 .match = tmpfs_match,
[a8e9ab8d]121 .node_get = tmpfs_node_get,
[1313ee9]122 .node_open = tmpfs_node_open,
[06901c6b]123 .node_put = tmpfs_node_put,
[2c448fb]124 .create = tmpfs_create_node,
125 .destroy = tmpfs_destroy_node,
126 .link = tmpfs_link_node,
127 .unlink = tmpfs_unlink_node,
[54e4479]128 .has_children = tmpfs_has_children,
[2c448fb]129 .index_get = tmpfs_index_get,
130 .size_get = tmpfs_size_get,
131 .lnkcnt_get = tmpfs_lnkcnt_get,
132 .is_directory = tmpfs_is_directory,
[1313ee9]133 .is_file = tmpfs_is_file,
[b33870b]134 .service_get = tmpfs_service_get
[2c448fb]135};
[fdb7795]136
[cf95bc0]137/** Hash table of all TMPFS nodes. */
138hash_table_t nodes;
[a4eb8a60]139
[1b20da0]140/*
141 * Implementation of hash table interface for the nodes hash table.
[062d900]142 */
143
144typedef struct {
145 service_id_t service_id;
146 fs_index_t index;
147} node_key_t;
[8d049ee0]148
[5e801dc]149static size_t nodes_key_hash(const void *k)
[a4eb8a60]150{
[5e801dc]151 const node_key_t *key = k;
[062d900]152 return hash_combine(key->service_id, key->index);
[a4eb8a60]153}
154
[062d900]155static size_t nodes_hash(const ht_link_t *item)
[a4eb8a60]156{
[062d900]157 tmpfs_node_t *nodep = hash_table_get_inst(item, tmpfs_node_t, nh_link);
158 return hash_combine(nodep->service_id, nodep->index);
159}
[0055cfd]160
[5e801dc]161static bool nodes_key_equal(const void *key_arg, const ht_link_t *item)
[062d900]162{
163 tmpfs_node_t *node = hash_table_get_inst(item, tmpfs_node_t, nh_link);
[5e801dc]164 const node_key_t *key = key_arg;
[a35b458]165
[062d900]166 return key->service_id == node->service_id && key->index == node->index;
[a4eb8a60]167}
168
[062d900]169static void nodes_remove_callback(ht_link_t *item)
[a4eb8a60]170{
[062d900]171 tmpfs_node_t *nodep = hash_table_get_inst(item, tmpfs_node_t, nh_link);
[9bddf37]172
[b72efe8]173 while (!list_empty(&nodep->cs_list)) {
174 tmpfs_dentry_t *dentryp = list_get_instance(
175 list_first(&nodep->cs_list), tmpfs_dentry_t, link);
[9bddf37]176
177 assert(nodep->type == TMPFS_DIRECTORY);
178 list_remove(&dentryp->link);
179 free(dentryp);
180 }
181
182 if (nodep->data) {
183 assert(nodep->type == TMPFS_FILE);
184 free(nodep->data);
185 }
186 free(nodep->bp);
187 free(nodep);
[a4eb8a60]188}
189
[cf95bc0]190/** TMPFS nodes hash table operations. */
[062d900]191hash_table_ops_t nodes_ops = {
[cf95bc0]192 .hash = nodes_hash,
[062d900]193 .key_hash = nodes_key_hash,
194 .key_equal = nodes_key_equal,
[4e00f87]195 .equal = NULL,
[cf95bc0]196 .remove_callback = nodes_remove_callback
[a4eb8a60]197};
198
[cf95bc0]199static void tmpfs_node_initialize(tmpfs_node_t *nodep)
[3298ddc]200{
[cf95bc0]201 nodep->bp = NULL;
202 nodep->index = 0;
[15f3c3f]203 nodep->service_id = 0;
[cf95bc0]204 nodep->type = TMPFS_NONE;
205 nodep->lnkcnt = 0;
206 nodep->size = 0;
207 nodep->data = NULL;
[b72efe8]208 list_initialize(&nodep->cs_list);
[3298ddc]209}
210
[cf95bc0]211static void tmpfs_dentry_initialize(tmpfs_dentry_t *dentryp)
[3298ddc]212{
[cf95bc0]213 link_initialize(&dentryp->link);
214 dentryp->name = NULL;
215 dentryp->node = NULL;
[4b11571]216}
217
[8d049ee0]218bool tmpfs_init(void)
[4b11571]219{
[062d900]220 if (!hash_table_create(&nodes, 0, 0, &nodes_ops))
[a4eb8a60]221 return false;
[a35b458]222
[8d049ee0]223 return true;
224}
225
[15f3c3f]226static bool tmpfs_instance_init(service_id_t service_id)
[8d049ee0]227{
[b6035ba]228 fs_node_t *rfn;
[b7fd2a0]229 errno_t rc;
[a35b458]230
[15f3c3f]231 rc = tmpfs_create_node(&rfn, service_id, L_DIRECTORY);
[54e4479]232 if (rc != EOK || !rfn)
[3298ddc]233 return false;
[b6035ba]234 TMPFS_NODE(rfn)->lnkcnt = 0; /* FS root is not linked */
[3298ddc]235 return true;
[4b11571]236}
237
[062d900]238static bool rm_service_id_nodes(ht_link_t *item, void *arg)
[e056e820]239{
[18b6a88]240 service_id_t sid = *(service_id_t *)arg;
[062d900]241 tmpfs_node_t *node = hash_table_get_inst(item, tmpfs_node_t, nh_link);
[a35b458]242
[062d900]243 if (node->service_id == sid) {
244 hash_table_remove_item(&nodes, &node->nh_link);
245 }
246 return true;
247}
248
249static void tmpfs_instance_done(service_id_t service_id)
[1b20da0]250{
[062d900]251 hash_table_apply(&nodes, rm_service_id_nodes, &service_id);
[e056e820]252}
253
[b7fd2a0]254errno_t tmpfs_match(fs_node_t **rfn, fs_node_t *pfn, const char *component)
[736c164]255{
[cf95bc0]256 tmpfs_node_t *parentp = TMPFS_NODE(pfn);
[736c164]257
[feeac0d]258 list_foreach(parentp->cs_list, link, tmpfs_dentry_t, dentryp) {
[54e4479]259 if (!str_cmp(dentryp->name, component)) {
260 *rfn = FS_NODE(dentryp->node);
261 return EOK;
262 }
[cf95bc0]263 }
[736c164]264
[54e4479]265 *rfn = NULL;
266 return EOK;
[736c164]267}
268
[b7fd2a0]269errno_t tmpfs_node_get(fs_node_t **rfn, service_id_t service_id, fs_index_t index)
[a8e9ab8d]270{
[062d900]271 node_key_t key = {
272 .service_id = service_id,
273 .index = index
[8d049ee0]274 };
[a35b458]275
[062d900]276 ht_link_t *lnk = hash_table_find(&nodes, &key);
[a35b458]277
[54e4479]278 if (lnk) {
279 tmpfs_node_t *nodep;
[062d900]280 nodep = hash_table_get_inst(lnk, tmpfs_node_t, nh_link);
[54e4479]281 *rfn = FS_NODE(nodep);
282 } else {
283 *rfn = NULL;
284 }
[1b20da0]285 return EOK;
[a8e9ab8d]286}
287
[b7fd2a0]288errno_t tmpfs_node_open(fs_node_t *fn)
[1313ee9]289{
290 /* nothing to do */
291 return EOK;
292}
293
[b7fd2a0]294errno_t tmpfs_node_put(fs_node_t *fn)
[06901c6b]295{
296 /* nothing to do */
[54e4479]297 return EOK;
[06901c6b]298}
299
[b7fd2a0]300errno_t tmpfs_create_node(fs_node_t **rfn, service_id_t service_id, int lflag)
[b8b23c8]301{
[54e4479]302 fs_node_t *rootfn;
[b7fd2a0]303 errno_t rc;
[54e4479]304
[72bde81]305 assert((lflag & L_FILE) ^ (lflag & L_DIRECTORY));
306
[cf95bc0]307 tmpfs_node_t *nodep = malloc(sizeof(tmpfs_node_t));
308 if (!nodep)
[54e4479]309 return ENOMEM;
[984a9ba]310
[cf95bc0]311 tmpfs_node_initialize(nodep);
312 nodep->bp = malloc(sizeof(fs_node_t));
313 if (!nodep->bp) {
314 free(nodep);
[54e4479]315 return ENOMEM;
[3298ddc]316 }
[984a9ba]317
[83937ccd]318 fs_node_initialize(nodep->bp);
[984a9ba]319 nodep->bp->data = nodep; /* Link the FS and TMPFS nodes */
[54e4479]320
[15f3c3f]321 rc = tmpfs_root_get(&rootfn, service_id);
[54e4479]322 assert(rc == EOK);
323 if (!rootfn)
[cf95bc0]324 nodep->index = TMPFS_SOME_ROOT;
[8d049ee0]325 else
[cf95bc0]326 nodep->index = tmpfs_next_index++;
[984a9ba]327
[15f3c3f]328 nodep->service_id = service_id;
[1b20da0]329 if (lflag & L_DIRECTORY)
[cf95bc0]330 nodep->type = TMPFS_DIRECTORY;
[1b20da0]331 else
[cf95bc0]332 nodep->type = TMPFS_FILE;
[72bde81]333
[cf95bc0]334 /* Insert the new node into the nodes hash table. */
[062d900]335 hash_table_insert(&nodes, &nodep->nh_link);
[54e4479]336 *rfn = FS_NODE(nodep);
337 return EOK;
338}
339
[b7fd2a0]340errno_t tmpfs_destroy_node(fs_node_t *fn)
[54e4479]341{
342 tmpfs_node_t *nodep = TMPFS_NODE(fn);
[a35b458]343
[54e4479]344 assert(!nodep->lnkcnt);
[b72efe8]345 assert(list_empty(&nodep->cs_list));
[a35b458]346
[062d900]347 hash_table_remove_item(&nodes, &nodep->nh_link);
[54e4479]348
[9bddf37]349 /*
350 * The nodes_remove_callback() function takes care of the actual
351 * resource deallocation.
352 */
[54e4479]353 return EOK;
[fdb7795]354}
355
[b7fd2a0]356errno_t tmpfs_link_node(fs_node_t *pfn, fs_node_t *cfn, const char *nm)
[fdb7795]357{
[cf95bc0]358 tmpfs_node_t *parentp = TMPFS_NODE(pfn);
359 tmpfs_node_t *childp = TMPFS_NODE(cfn);
360 tmpfs_dentry_t *dentryp;
[fdb7795]361
362 assert(parentp->type == TMPFS_DIRECTORY);
363
[cf95bc0]364 /* Check for duplicit entries. */
[feeac0d]365 list_foreach(parentp->cs_list, link, tmpfs_dentry_t, dp) {
366 if (!str_cmp(dp->name, nm))
[cf95bc0]367 return EEXIST;
368 }
369
370 /* Allocate and initialize the dentry. */
371 dentryp = malloc(sizeof(tmpfs_dentry_t));
372 if (!dentryp)
[0013b9ce]373 return ENOMEM;
[cf95bc0]374 tmpfs_dentry_initialize(dentryp);
375
376 /* Populate and link the new dentry. */
[92fd52d7]377 size_t size = str_size(nm);
[cf95bc0]378 dentryp->name = malloc(size + 1);
379 if (!dentryp->name) {
380 free(dentryp);
[0013b9ce]381 return ENOMEM;
[3298ddc]382 }
[cf95bc0]383 str_cpy(dentryp->name, size + 1, nm);
384 dentryp->node = childp;
[adc8a63]385 childp->lnkcnt++;
[b72efe8]386 list_append(&dentryp->link, &parentp->cs_list);
[72bde81]387
[0013b9ce]388 return EOK;
[b8b23c8]389}
[4b11571]390
[b7fd2a0]391errno_t tmpfs_unlink_node(fs_node_t *pfn, fs_node_t *cfn, const char *nm)
[b8b23c8]392{
[cf95bc0]393 tmpfs_node_t *parentp = TMPFS_NODE(pfn);
394 tmpfs_node_t *childp = NULL;
395 tmpfs_dentry_t *dentryp;
[16105cba]396
[7b6d98b]397 if (!parentp)
[16105cba]398 return EBUSY;
[feeac0d]399
400 list_foreach(parentp->cs_list, link, tmpfs_dentry_t, dp) {
401 if (!str_cmp(dp->name, nm)) {
402 dentryp = dp;
[cf95bc0]403 childp = dentryp->node;
404 assert(FS_NODE(childp) == cfn);
405 break;
[b72efe8]406 }
[16105cba]407 }
408
[cf95bc0]409 if (!childp)
410 return ENOENT;
[a35b458]411
[b72efe8]412 if ((childp->lnkcnt == 1) && !list_empty(&childp->cs_list))
[cf95bc0]413 return ENOTEMPTY;
[fdb7795]414
[cf95bc0]415 list_remove(&dentryp->link);
416 free(dentryp);
[7b6d98b]417 childp->lnkcnt--;
[adc8a63]418
[16105cba]419 return EOK;
[d5cdffe]420}
421
[efcebe1]422/*
423 * Implementation of the VFS_OUT interface.
424 */
425
[b7fd2a0]426static errno_t tmpfs_fsprobe(service_id_t service_id, vfs_fs_probe_info_t *info)
[d2c8533]427{
428 return ENOTSUP;
429}
430
[b7fd2a0]431static errno_t
[4f30222]432tmpfs_mounted(service_id_t service_id, const char *opts, fs_index_t *index,
433 aoff64_t *size)
[64b67c3]434{
[fc2e71e]435 fs_node_t *rootfn;
[b7fd2a0]436 errno_t rc;
[a35b458]437
[d42976c]438 /* Check if this device is not already mounted. */
[15f3c3f]439 rc = tmpfs_root_get(&rootfn, service_id);
[fc2e71e]440 if ((rc == EOK) && (rootfn)) {
[0055cfd]441 (void) tmpfs_node_put(rootfn);
[efcebe1]442 return EEXIST;
[fc2e71e]443 }
444
[8d049ee0]445 /* Initialize TMPFS instance. */
[86ffa27f]446 if (!tmpfs_instance_init(service_id))
[efcebe1]447 return ENOMEM;
[f49b0ea]448
[15f3c3f]449 rc = tmpfs_root_get(&rootfn, service_id);
[54e4479]450 assert(rc == EOK);
451 tmpfs_node_t *rootp = TMPFS_NODE(rootfn);
[f49b0ea]452
[efcebe1]453 *index = rootp->index;
454 *size = rootp->size;
[e056e820]455
[efcebe1]456 return EOK;
[3c11713]457}
458
[b7fd2a0]459static errno_t tmpfs_unmounted(service_id_t service_id)
[f49b0ea]460{
[86ffa27f]461 tmpfs_instance_done(service_id);
[efcebe1]462 return EOK;
[d5cdffe]463}
464
[b7fd2a0]465static errno_t tmpfs_read(service_id_t service_id, fs_index_t index, aoff64_t pos,
[efcebe1]466 size_t *rbytes)
[a4eb8a60]467{
468 /*
[cf95bc0]469 * Lookup the respective TMPFS node.
[a4eb8a60]470 */
[062d900]471 node_key_t key = {
472 .service_id = service_id,
473 .index = index
[8d049ee0]474 };
[a35b458]475
[062d900]476 ht_link_t *hlp = hash_table_find(&nodes, &key);
[efcebe1]477 if (!hlp)
478 return ENOENT;
[a35b458]479
[062d900]480 tmpfs_node_t *nodep = hash_table_get_inst(hlp, tmpfs_node_t, nh_link);
[a35b458]481
[a4eb8a60]482 /*
[a92da0a]483 * Receive the read request.
[a4eb8a60]484 */
[984a9ba]485 ipc_call_t call;
[92fd52d7]486 size_t size;
[984a9ba]487 if (!async_data_read_receive(&call, &size)) {
488 async_answer_0(&call, EINVAL);
[efcebe1]489 return EINVAL;
[a4eb8a60]490 }
491
[5973fd0]492 size_t bytes;
[cf95bc0]493 if (nodep->type == TMPFS_FILE) {
[ed903174]494 bytes = min(nodep->size - pos, size);
[984a9ba]495 (void) async_data_read_finalize(&call, nodep->data + pos,
[5973fd0]496 bytes);
497 } else {
[cf95bc0]498 tmpfs_dentry_t *dentryp;
499 link_t *lnk;
[a35b458]500
[cf95bc0]501 assert(nodep->type == TMPFS_DIRECTORY);
[a35b458]502
[5973fd0]503 /*
504 * Yes, we really use O(n) algorithm here.
505 * If it bothers someone, it could be fixed by introducing a
506 * hash table.
507 */
[b72efe8]508 lnk = list_nth(&nodep->cs_list, pos);
[a35b458]509
[b72efe8]510 if (lnk == NULL) {
[984a9ba]511 async_answer_0(&call, ENOENT);
[efcebe1]512 return ENOENT;
[5973fd0]513 }
514
[cf95bc0]515 dentryp = list_get_instance(lnk, tmpfs_dentry_t, link);
[3298ddc]516
[984a9ba]517 (void) async_data_read_finalize(&call, dentryp->name,
[cf95bc0]518 str_size(dentryp->name) + 1);
[5973fd0]519 bytes = 1;
520 }
[7dab6b8]521
[efcebe1]522 *rbytes = bytes;
523 return EOK;
[a4eb8a60]524}
525
[b7fd2a0]526static errno_t
[86ffa27f]527tmpfs_write(service_id_t service_id, fs_index_t index, aoff64_t pos,
[efcebe1]528 size_t *wbytes, aoff64_t *nsize)
[ee1b8ca]529{
530 /*
[cf95bc0]531 * Lookup the respective TMPFS node.
[ee1b8ca]532 */
[062d900]533 node_key_t key = {
534 .service_id = service_id,
535 .index = index
[8d049ee0]536 };
[a35b458]537
[062d900]538 ht_link_t *hlp = hash_table_find(&nodes, &key);
[a35b458]539
[efcebe1]540 if (!hlp)
541 return ENOENT;
[a35b458]542
[062d900]543 tmpfs_node_t *nodep = hash_table_get_inst(hlp, tmpfs_node_t, nh_link);
[ee1b8ca]544
545 /*
546 * Receive the write request.
547 */
[984a9ba]548 ipc_call_t call;
[92fd52d7]549 size_t size;
[984a9ba]550 if (!async_data_write_receive(&call, &size)) {
551 async_answer_0(&call, EINVAL);
[efcebe1]552 return EINVAL;
[ee1b8ca]553 }
554
[c1bf5cb]555 /*
556 * Check whether the file needs to grow.
557 */
[cf95bc0]558 if (pos + size <= nodep->size) {
[c1bf5cb]559 /* The file size is not changing. */
[984a9ba]560 (void) async_data_write_finalize(&call, nodep->data + pos,
[efcebe1]561 size);
562 goto out;
[c1bf5cb]563 }
[cf95bc0]564 size_t delta = (pos + size) - nodep->size;
[ee1b8ca]565 /*
566 * At this point, we are deliberately extremely straightforward and
[c1bf5cb]567 * simply realloc the contents of the file on every write that grows the
568 * file. In the end, the situation might not be as bad as it may look:
569 * our heap allocator can save us and just grow the block whenever
570 * possible.
[ee1b8ca]571 */
[cf95bc0]572 void *newdata = realloc(nodep->data, nodep->size + delta);
[ee1b8ca]573 if (!newdata) {
[984a9ba]574 async_answer_0(&call, ENOMEM);
[efcebe1]575 size = 0;
576 goto out;
[ee1b8ca]577 }
[0ee4322]578 /* Clear any newly allocated memory in order to emulate gaps. */
[cf95bc0]579 memset(newdata + nodep->size, 0, delta);
580 nodep->size += delta;
581 nodep->data = newdata;
[984a9ba]582 (void) async_data_write_finalize(&call, nodep->data + pos, size);
[efcebe1]583
584out:
585 *wbytes = size;
586 *nsize = nodep->size;
587 return EOK;
[ee1b8ca]588}
589
[b7fd2a0]590static errno_t tmpfs_truncate(service_id_t service_id, fs_index_t index,
[efcebe1]591 aoff64_t size)
[0ee4322]592{
593 /*
[cf95bc0]594 * Lookup the respective TMPFS node.
[0ee4322]595 */
[062d900]596 node_key_t key = {
597 .service_id = service_id,
598 .index = index
[8d049ee0]599 };
[a35b458]600
[062d900]601 ht_link_t *hlp = hash_table_find(&nodes, &key);
[efcebe1]602 if (!hlp)
603 return ENOENT;
[062d900]604 tmpfs_node_t *nodep = hash_table_get_inst(hlp, tmpfs_node_t, nh_link);
[a35b458]605
[efcebe1]606 if (size == nodep->size)
607 return EOK;
[a35b458]608
[efcebe1]609 if (size > SIZE_MAX)
610 return ENOMEM;
[a35b458]611
[cf95bc0]612 void *newdata = realloc(nodep->data, size);
[ec39720]613 if (!newdata && size)
[efcebe1]614 return ENOMEM;
[a35b458]615
[cf95bc0]616 if (size > nodep->size) {
617 size_t delta = size - nodep->size;
618 memset(newdata + nodep->size, 0, delta);
[0ee4322]619 }
[a35b458]620
[cf95bc0]621 nodep->size = size;
622 nodep->data = newdata;
[efcebe1]623 return EOK;
[0ee4322]624}
625
[b7fd2a0]626static errno_t tmpfs_close(service_id_t service_id, fs_index_t index)
[c20aa06]627{
[efcebe1]628 return EOK;
[c20aa06]629}
630
[b7fd2a0]631static errno_t tmpfs_destroy(service_id_t service_id, fs_index_t index)
[f17667a]632{
[062d900]633 node_key_t key = {
634 .service_id = service_id,
635 .index = index
[8d049ee0]636 };
[a35b458]637
[062d900]638 ht_link_t *hlp = hash_table_find(&nodes, &key);
[efcebe1]639 if (!hlp)
640 return ENOENT;
[062d900]641 tmpfs_node_t *nodep = hash_table_get_inst(hlp, tmpfs_node_t,
[cf95bc0]642 nh_link);
[efcebe1]643 return tmpfs_destroy_node(FS_NODE(nodep));
[c20aa06]644}
645
[b7fd2a0]646static errno_t tmpfs_sync(service_id_t service_id, fs_index_t index)
[c20aa06]647{
[69a60c4]648 /*
649 * TMPFS keeps its data structures always consistent,
650 * thus the sync operation is a no-op.
651 */
[efcebe1]652 return EOK;
[c20aa06]653}
654
[efcebe1]655vfs_out_ops_t tmpfs_ops = {
[d2c8533]656 .fsprobe = tmpfs_fsprobe,
[efcebe1]657 .mounted = tmpfs_mounted,
658 .unmounted = tmpfs_unmounted,
659 .read = tmpfs_read,
660 .write = tmpfs_write,
661 .truncate = tmpfs_truncate,
662 .close = tmpfs_close,
663 .destroy = tmpfs_destroy,
664 .sync = tmpfs_sync,
665};
666
[d5cdffe]667/**
668 * @}
[c20aa06]669 */
Note: See TracBrowser for help on using the repository browser.