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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 75701004 was 75701004, checked in by Martin Decky <martin@…>, 7 years ago

use a TAR as the archive format for populating TMPFS root file system

Also remove the logic of populating a TMPFS file system from the TMPFS
file system driver. A more elegant separation of concerns is to populate
the file system from the client. This is now done by the init task (if
required) and should work universally for any file system.

  • 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
29/** @addtogroup fs
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 <atomic.h>
46#include <stdlib.h>
[19f857a]47#include <str.h>
[4b11571]48#include <stdio.h>
[5973fd0]49#include <assert.h>
[8d2dd7f2]50#include <stddef.h>
[d9c8c81]51#include <adt/hash_table.h>
[062d900]52#include <adt/hash.h>
[a4eb8a60]53#include <as.h>
[2c448fb]54#include <libfs.h>
[a4eb8a60]55
[8d049ee0]56/** All root nodes have index 0. */
57#define TMPFS_SOME_ROOT 0
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
[062d900]149static size_t nodes_key_hash(void *k)
[a4eb8a60]150{
[062d900]151 node_key_t *key = (node_key_t *)k;
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
[062d900]161static bool nodes_key_equal(void *key_arg, const ht_link_t *item)
162{
163 tmpfs_node_t *node = hash_table_get_inst(item, tmpfs_node_t, nh_link);
164 node_key_t *key = (node_key_t *)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;
[cf95bc0]310 tmpfs_node_initialize(nodep);
311 nodep->bp = malloc(sizeof(fs_node_t));
312 if (!nodep->bp) {
313 free(nodep);
[54e4479]314 return ENOMEM;
[3298ddc]315 }
[83937ccd]316 fs_node_initialize(nodep->bp);
[cf95bc0]317 nodep->bp->data = nodep; /* link the FS and TMPFS nodes */
[54e4479]318
[15f3c3f]319 rc = tmpfs_root_get(&rootfn, service_id);
[54e4479]320 assert(rc == EOK);
321 if (!rootfn)
[cf95bc0]322 nodep->index = TMPFS_SOME_ROOT;
[8d049ee0]323 else
[cf95bc0]324 nodep->index = tmpfs_next_index++;
[15f3c3f]325 nodep->service_id = service_id;
[1b20da0]326 if (lflag & L_DIRECTORY)
[cf95bc0]327 nodep->type = TMPFS_DIRECTORY;
[1b20da0]328 else
[cf95bc0]329 nodep->type = TMPFS_FILE;
[72bde81]330
[cf95bc0]331 /* Insert the new node into the nodes hash table. */
[062d900]332 hash_table_insert(&nodes, &nodep->nh_link);
[54e4479]333 *rfn = FS_NODE(nodep);
334 return EOK;
335}
336
[b7fd2a0]337errno_t tmpfs_destroy_node(fs_node_t *fn)
[54e4479]338{
339 tmpfs_node_t *nodep = TMPFS_NODE(fn);
[a35b458]340
[54e4479]341 assert(!nodep->lnkcnt);
[b72efe8]342 assert(list_empty(&nodep->cs_list));
[a35b458]343
[062d900]344 hash_table_remove_item(&nodes, &nodep->nh_link);
[54e4479]345
[9bddf37]346 /*
347 * The nodes_remove_callback() function takes care of the actual
348 * resource deallocation.
349 */
[54e4479]350 return EOK;
[fdb7795]351}
352
[b7fd2a0]353errno_t tmpfs_link_node(fs_node_t *pfn, fs_node_t *cfn, const char *nm)
[fdb7795]354{
[cf95bc0]355 tmpfs_node_t *parentp = TMPFS_NODE(pfn);
356 tmpfs_node_t *childp = TMPFS_NODE(cfn);
357 tmpfs_dentry_t *dentryp;
[fdb7795]358
359 assert(parentp->type == TMPFS_DIRECTORY);
360
[cf95bc0]361 /* Check for duplicit entries. */
[feeac0d]362 list_foreach(parentp->cs_list, link, tmpfs_dentry_t, dp) {
363 if (!str_cmp(dp->name, nm))
[cf95bc0]364 return EEXIST;
365 }
366
367 /* Allocate and initialize the dentry. */
368 dentryp = malloc(sizeof(tmpfs_dentry_t));
369 if (!dentryp)
[0013b9ce]370 return ENOMEM;
[cf95bc0]371 tmpfs_dentry_initialize(dentryp);
372
373 /* Populate and link the new dentry. */
[92fd52d7]374 size_t size = str_size(nm);
[cf95bc0]375 dentryp->name = malloc(size + 1);
376 if (!dentryp->name) {
377 free(dentryp);
[0013b9ce]378 return ENOMEM;
[3298ddc]379 }
[cf95bc0]380 str_cpy(dentryp->name, size + 1, nm);
381 dentryp->node = childp;
[adc8a63]382 childp->lnkcnt++;
[b72efe8]383 list_append(&dentryp->link, &parentp->cs_list);
[72bde81]384
[0013b9ce]385 return EOK;
[b8b23c8]386}
[4b11571]387
[b7fd2a0]388errno_t tmpfs_unlink_node(fs_node_t *pfn, fs_node_t *cfn, const char *nm)
[b8b23c8]389{
[cf95bc0]390 tmpfs_node_t *parentp = TMPFS_NODE(pfn);
391 tmpfs_node_t *childp = NULL;
392 tmpfs_dentry_t *dentryp;
[16105cba]393
[7b6d98b]394 if (!parentp)
[16105cba]395 return EBUSY;
[feeac0d]396
397 list_foreach(parentp->cs_list, link, tmpfs_dentry_t, dp) {
398 if (!str_cmp(dp->name, nm)) {
399 dentryp = dp;
[cf95bc0]400 childp = dentryp->node;
401 assert(FS_NODE(childp) == cfn);
402 break;
[b72efe8]403 }
[16105cba]404 }
405
[cf95bc0]406 if (!childp)
407 return ENOENT;
[a35b458]408
[b72efe8]409 if ((childp->lnkcnt == 1) && !list_empty(&childp->cs_list))
[cf95bc0]410 return ENOTEMPTY;
[fdb7795]411
[cf95bc0]412 list_remove(&dentryp->link);
413 free(dentryp);
[7b6d98b]414 childp->lnkcnt--;
[adc8a63]415
[16105cba]416 return EOK;
[d5cdffe]417}
418
[efcebe1]419/*
420 * Implementation of the VFS_OUT interface.
421 */
422
[b7fd2a0]423static errno_t tmpfs_fsprobe(service_id_t service_id, vfs_fs_probe_info_t *info)
[d2c8533]424{
425 return ENOTSUP;
426}
427
[b7fd2a0]428static errno_t
[4f30222]429tmpfs_mounted(service_id_t service_id, const char *opts, fs_index_t *index,
430 aoff64_t *size)
[64b67c3]431{
[fc2e71e]432 fs_node_t *rootfn;
[b7fd2a0]433 errno_t rc;
[a35b458]434
[d42976c]435 /* Check if this device is not already mounted. */
[15f3c3f]436 rc = tmpfs_root_get(&rootfn, service_id);
[fc2e71e]437 if ((rc == EOK) && (rootfn)) {
[0055cfd]438 (void) tmpfs_node_put(rootfn);
[efcebe1]439 return EEXIST;
[fc2e71e]440 }
441
[8d049ee0]442 /* Initialize TMPFS instance. */
[86ffa27f]443 if (!tmpfs_instance_init(service_id))
[efcebe1]444 return ENOMEM;
[f49b0ea]445
[15f3c3f]446 rc = tmpfs_root_get(&rootfn, service_id);
[54e4479]447 assert(rc == EOK);
448 tmpfs_node_t *rootp = TMPFS_NODE(rootfn);
[f49b0ea]449
[efcebe1]450 *index = rootp->index;
451 *size = rootp->size;
[e056e820]452
[efcebe1]453 return EOK;
[3c11713]454}
455
[b7fd2a0]456static errno_t tmpfs_unmounted(service_id_t service_id)
[f49b0ea]457{
[86ffa27f]458 tmpfs_instance_done(service_id);
[efcebe1]459 return EOK;
[d5cdffe]460}
461
[b7fd2a0]462static errno_t tmpfs_read(service_id_t service_id, fs_index_t index, aoff64_t pos,
[efcebe1]463 size_t *rbytes)
[a4eb8a60]464{
465 /*
[cf95bc0]466 * Lookup the respective TMPFS node.
[a4eb8a60]467 */
[062d900]468 node_key_t key = {
469 .service_id = service_id,
470 .index = index
[8d049ee0]471 };
[a35b458]472
[062d900]473 ht_link_t *hlp = hash_table_find(&nodes, &key);
[efcebe1]474 if (!hlp)
475 return ENOENT;
[a35b458]476
[062d900]477 tmpfs_node_t *nodep = hash_table_get_inst(hlp, tmpfs_node_t, nh_link);
[a35b458]478
[a4eb8a60]479 /*
[a92da0a]480 * Receive the read request.
[a4eb8a60]481 */
[a46e56b]482 cap_call_handle_t chandle;
[92fd52d7]483 size_t size;
[a46e56b]484 if (!async_data_read_receive(&chandle, &size)) {
485 async_answer_0(chandle, EINVAL);
[efcebe1]486 return EINVAL;
[a4eb8a60]487 }
488
[5973fd0]489 size_t bytes;
[cf95bc0]490 if (nodep->type == TMPFS_FILE) {
[ed903174]491 bytes = min(nodep->size - pos, size);
[a46e56b]492 (void) async_data_read_finalize(chandle, nodep->data + pos,
[5973fd0]493 bytes);
494 } else {
[cf95bc0]495 tmpfs_dentry_t *dentryp;
496 link_t *lnk;
[a35b458]497
[cf95bc0]498 assert(nodep->type == TMPFS_DIRECTORY);
[a35b458]499
[5973fd0]500 /*
501 * Yes, we really use O(n) algorithm here.
502 * If it bothers someone, it could be fixed by introducing a
503 * hash table.
504 */
[b72efe8]505 lnk = list_nth(&nodep->cs_list, pos);
[a35b458]506
[b72efe8]507 if (lnk == NULL) {
[a46e56b]508 async_answer_0(chandle, ENOENT);
[efcebe1]509 return ENOENT;
[5973fd0]510 }
511
[cf95bc0]512 dentryp = list_get_instance(lnk, tmpfs_dentry_t, link);
[3298ddc]513
[a46e56b]514 (void) async_data_read_finalize(chandle, dentryp->name,
[cf95bc0]515 str_size(dentryp->name) + 1);
[5973fd0]516 bytes = 1;
517 }
[7dab6b8]518
[efcebe1]519 *rbytes = bytes;
520 return EOK;
[a4eb8a60]521}
522
[b7fd2a0]523static errno_t
[86ffa27f]524tmpfs_write(service_id_t service_id, fs_index_t index, aoff64_t pos,
[efcebe1]525 size_t *wbytes, aoff64_t *nsize)
[ee1b8ca]526{
527 /*
[cf95bc0]528 * Lookup the respective TMPFS node.
[ee1b8ca]529 */
[062d900]530 node_key_t key = {
531 .service_id = service_id,
532 .index = index
[8d049ee0]533 };
[a35b458]534
[062d900]535 ht_link_t *hlp = hash_table_find(&nodes, &key);
[a35b458]536
[efcebe1]537 if (!hlp)
538 return ENOENT;
[a35b458]539
[062d900]540 tmpfs_node_t *nodep = hash_table_get_inst(hlp, tmpfs_node_t, nh_link);
[ee1b8ca]541
542 /*
543 * Receive the write request.
544 */
[a46e56b]545 cap_call_handle_t chandle;
[92fd52d7]546 size_t size;
[a46e56b]547 if (!async_data_write_receive(&chandle, &size)) {
548 async_answer_0(chandle, EINVAL);
[efcebe1]549 return EINVAL;
[ee1b8ca]550 }
551
[c1bf5cb]552 /*
553 * Check whether the file needs to grow.
554 */
[cf95bc0]555 if (pos + size <= nodep->size) {
[c1bf5cb]556 /* The file size is not changing. */
[a46e56b]557 (void) async_data_write_finalize(chandle, nodep->data + pos,
[efcebe1]558 size);
559 goto out;
[c1bf5cb]560 }
[cf95bc0]561 size_t delta = (pos + size) - nodep->size;
[ee1b8ca]562 /*
563 * At this point, we are deliberately extremely straightforward and
[c1bf5cb]564 * simply realloc the contents of the file on every write that grows the
565 * file. In the end, the situation might not be as bad as it may look:
566 * our heap allocator can save us and just grow the block whenever
567 * possible.
[ee1b8ca]568 */
[cf95bc0]569 void *newdata = realloc(nodep->data, nodep->size + delta);
[ee1b8ca]570 if (!newdata) {
[a46e56b]571 async_answer_0(chandle, ENOMEM);
[efcebe1]572 size = 0;
573 goto out;
[ee1b8ca]574 }
[0ee4322]575 /* Clear any newly allocated memory in order to emulate gaps. */
[cf95bc0]576 memset(newdata + nodep->size, 0, delta);
577 nodep->size += delta;
578 nodep->data = newdata;
[a46e56b]579 (void) async_data_write_finalize(chandle, nodep->data + pos, size);
[efcebe1]580
581out:
582 *wbytes = size;
583 *nsize = nodep->size;
584 return EOK;
[ee1b8ca]585}
586
[b7fd2a0]587static errno_t tmpfs_truncate(service_id_t service_id, fs_index_t index,
[efcebe1]588 aoff64_t size)
[0ee4322]589{
590 /*
[cf95bc0]591 * Lookup the respective TMPFS node.
[0ee4322]592 */
[062d900]593 node_key_t key = {
594 .service_id = service_id,
595 .index = index
[8d049ee0]596 };
[a35b458]597
[062d900]598 ht_link_t *hlp = hash_table_find(&nodes, &key);
[a35b458]599
[efcebe1]600 if (!hlp)
601 return ENOENT;
[062d900]602 tmpfs_node_t *nodep = hash_table_get_inst(hlp, tmpfs_node_t, nh_link);
[a35b458]603
[efcebe1]604 if (size == nodep->size)
605 return EOK;
[a35b458]606
[efcebe1]607 if (size > SIZE_MAX)
608 return ENOMEM;
[a35b458]609
[cf95bc0]610 void *newdata = realloc(nodep->data, size);
[efcebe1]611 if (!newdata)
612 return ENOMEM;
[a35b458]613
[cf95bc0]614 if (size > nodep->size) {
615 size_t delta = size - nodep->size;
616 memset(newdata + nodep->size, 0, delta);
[0ee4322]617 }
[a35b458]618
[cf95bc0]619 nodep->size = size;
620 nodep->data = newdata;
[efcebe1]621 return EOK;
[0ee4322]622}
623
[b7fd2a0]624static errno_t tmpfs_close(service_id_t service_id, fs_index_t index)
[c20aa06]625{
[efcebe1]626 return EOK;
[c20aa06]627}
628
[b7fd2a0]629static errno_t tmpfs_destroy(service_id_t service_id, fs_index_t index)
[f17667a]630{
[062d900]631 node_key_t key = {
632 .service_id = service_id,
633 .index = index
[8d049ee0]634 };
[a35b458]635
[062d900]636 ht_link_t *hlp = hash_table_find(&nodes, &key);
[efcebe1]637 if (!hlp)
638 return ENOENT;
[062d900]639 tmpfs_node_t *nodep = hash_table_get_inst(hlp, tmpfs_node_t,
[cf95bc0]640 nh_link);
[efcebe1]641 return tmpfs_destroy_node(FS_NODE(nodep));
[c20aa06]642}
643
[b7fd2a0]644static errno_t tmpfs_sync(service_id_t service_id, fs_index_t index)
[c20aa06]645{
[69a60c4]646 /*
647 * TMPFS keeps its data structures always consistent,
648 * thus the sync operation is a no-op.
649 */
[efcebe1]650 return EOK;
[c20aa06]651}
652
[efcebe1]653vfs_out_ops_t tmpfs_ops = {
[d2c8533]654 .fsprobe = tmpfs_fsprobe,
[efcebe1]655 .mounted = tmpfs_mounted,
656 .unmounted = tmpfs_unmounted,
657 .read = tmpfs_read,
658 .write = tmpfs_write,
659 .truncate = tmpfs_truncate,
660 .close = tmpfs_close,
661 .destroy = tmpfs_destroy,
662 .sync = tmpfs_sync,
663};
664
[d5cdffe]665/**
666 * @}
[c20aa06]667 */
[efcebe1]668
Note: See TracBrowser for help on using the repository browser.