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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since eadaeae8 was a35b458, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 7 years ago

style: Remove trailing whitespace on _all_ lines, including empty ones, for particular file types.

Command used: tools/srepl '\s\+$' '' -- *.c *.h *.py *.sh *.s *.S *.ag

Currently, whitespace on empty lines is very inconsistent.
There are two basic choices: Either remove the whitespace, or keep empty lines
indented to the level of surrounding code. The former is AFAICT more common,
and also much easier to do automatically.

Alternatively, we could write script for automatic indentation, and use that
instead. However, if such a script exists, it's possible to use the indented
style locally, by having the editor apply relevant conversions on load/save,
without affecting remote repository. IMO, it makes more sense to adopt
the simpler rule.

  • Property mode set to 100644
File size: 15.2 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{
[062d900]240 service_id_t sid = *(service_id_t*)arg;
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);
[594303b]449 if (str_cmp(opts, "restore") == 0) {
[86ffa27f]450 if (!tmpfs_restore(service_id))
[efcebe1]451 return ELIMIT;
[f49b0ea]452 }
453
[efcebe1]454 *index = rootp->index;
455 *size = rootp->size;
[e056e820]456
[efcebe1]457 return EOK;
[3c11713]458}
459
[b7fd2a0]460static errno_t tmpfs_unmounted(service_id_t service_id)
[f49b0ea]461{
[86ffa27f]462 tmpfs_instance_done(service_id);
[efcebe1]463 return EOK;
[d5cdffe]464}
465
[b7fd2a0]466static errno_t tmpfs_read(service_id_t service_id, fs_index_t index, aoff64_t pos,
[efcebe1]467 size_t *rbytes)
[a4eb8a60]468{
469 /*
[cf95bc0]470 * Lookup the respective TMPFS node.
[a4eb8a60]471 */
[062d900]472 node_key_t key = {
473 .service_id = service_id,
474 .index = index
[8d049ee0]475 };
[a35b458]476
[062d900]477 ht_link_t *hlp = hash_table_find(&nodes, &key);
[efcebe1]478 if (!hlp)
479 return ENOENT;
[a35b458]480
[062d900]481 tmpfs_node_t *nodep = hash_table_get_inst(hlp, tmpfs_node_t, nh_link);
[a35b458]482
[a4eb8a60]483 /*
[a92da0a]484 * Receive the read request.
[a4eb8a60]485 */
486 ipc_callid_t callid;
[92fd52d7]487 size_t size;
[0da4e41]488 if (!async_data_read_receive(&callid, &size)) {
[ffa2c8ef]489 async_answer_0(callid, EINVAL);
[efcebe1]490 return EINVAL;
[a4eb8a60]491 }
492
[5973fd0]493 size_t bytes;
[cf95bc0]494 if (nodep->type == TMPFS_FILE) {
[ed903174]495 bytes = min(nodep->size - pos, size);
[0da4e41]496 (void) async_data_read_finalize(callid, nodep->data + pos,
[5973fd0]497 bytes);
498 } else {
[cf95bc0]499 tmpfs_dentry_t *dentryp;
500 link_t *lnk;
[a35b458]501
[cf95bc0]502 assert(nodep->type == TMPFS_DIRECTORY);
[a35b458]503
[5973fd0]504 /*
505 * Yes, we really use O(n) algorithm here.
506 * If it bothers someone, it could be fixed by introducing a
507 * hash table.
508 */
[b72efe8]509 lnk = list_nth(&nodep->cs_list, pos);
[a35b458]510
[b72efe8]511 if (lnk == NULL) {
[ffa2c8ef]512 async_answer_0(callid, ENOENT);
[efcebe1]513 return ENOENT;
[5973fd0]514 }
515
[cf95bc0]516 dentryp = list_get_instance(lnk, tmpfs_dentry_t, link);
[3298ddc]517
[0da4e41]518 (void) async_data_read_finalize(callid, dentryp->name,
[cf95bc0]519 str_size(dentryp->name) + 1);
[5973fd0]520 bytes = 1;
521 }
[7dab6b8]522
[efcebe1]523 *rbytes = bytes;
524 return EOK;
[a4eb8a60]525}
526
[b7fd2a0]527static errno_t
[86ffa27f]528tmpfs_write(service_id_t service_id, fs_index_t index, aoff64_t pos,
[efcebe1]529 size_t *wbytes, aoff64_t *nsize)
[ee1b8ca]530{
531 /*
[cf95bc0]532 * Lookup the respective TMPFS node.
[ee1b8ca]533 */
[062d900]534 node_key_t key = {
535 .service_id = service_id,
536 .index = index
[8d049ee0]537 };
[a35b458]538
[062d900]539 ht_link_t *hlp = hash_table_find(&nodes, &key);
[a35b458]540
[efcebe1]541 if (!hlp)
542 return ENOENT;
[a35b458]543
[062d900]544 tmpfs_node_t *nodep = hash_table_get_inst(hlp, tmpfs_node_t, nh_link);
[ee1b8ca]545
546 /*
547 * Receive the write request.
548 */
549 ipc_callid_t callid;
[92fd52d7]550 size_t size;
[0da4e41]551 if (!async_data_write_receive(&callid, &size)) {
[1b20da0]552 async_answer_0(callid, EINVAL);
[efcebe1]553 return EINVAL;
[ee1b8ca]554 }
555
[c1bf5cb]556 /*
557 * Check whether the file needs to grow.
558 */
[cf95bc0]559 if (pos + size <= nodep->size) {
[c1bf5cb]560 /* The file size is not changing. */
[efcebe1]561 (void) async_data_write_finalize(callid, nodep->data + pos,
562 size);
563 goto out;
[c1bf5cb]564 }
[cf95bc0]565 size_t delta = (pos + size) - nodep->size;
[ee1b8ca]566 /*
567 * At this point, we are deliberately extremely straightforward and
[c1bf5cb]568 * simply realloc the contents of the file on every write that grows the
569 * file. In the end, the situation might not be as bad as it may look:
570 * our heap allocator can save us and just grow the block whenever
571 * possible.
[ee1b8ca]572 */
[cf95bc0]573 void *newdata = realloc(nodep->data, nodep->size + delta);
[ee1b8ca]574 if (!newdata) {
[ffa2c8ef]575 async_answer_0(callid, ENOMEM);
[efcebe1]576 size = 0;
577 goto out;
[ee1b8ca]578 }
[0ee4322]579 /* Clear any newly allocated memory in order to emulate gaps. */
[cf95bc0]580 memset(newdata + nodep->size, 0, delta);
581 nodep->size += delta;
582 nodep->data = newdata;
[0da4e41]583 (void) async_data_write_finalize(callid, nodep->data + pos, size);
[efcebe1]584
585out:
586 *wbytes = size;
587 *nsize = nodep->size;
588 return EOK;
[ee1b8ca]589}
590
[b7fd2a0]591static errno_t tmpfs_truncate(service_id_t service_id, fs_index_t index,
[efcebe1]592 aoff64_t size)
[0ee4322]593{
594 /*
[cf95bc0]595 * Lookup the respective TMPFS node.
[0ee4322]596 */
[062d900]597 node_key_t key = {
598 .service_id = service_id,
599 .index = index
[8d049ee0]600 };
[a35b458]601
[062d900]602 ht_link_t *hlp = hash_table_find(&nodes, &key);
[a35b458]603
[efcebe1]604 if (!hlp)
605 return ENOENT;
[062d900]606 tmpfs_node_t *nodep = hash_table_get_inst(hlp, tmpfs_node_t, nh_link);
[a35b458]607
[efcebe1]608 if (size == nodep->size)
609 return EOK;
[a35b458]610
[efcebe1]611 if (size > SIZE_MAX)
612 return ENOMEM;
[a35b458]613
[cf95bc0]614 void *newdata = realloc(nodep->data, size);
[efcebe1]615 if (!newdata)
616 return ENOMEM;
[a35b458]617
[cf95bc0]618 if (size > nodep->size) {
619 size_t delta = size - nodep->size;
620 memset(newdata + nodep->size, 0, delta);
[0ee4322]621 }
[a35b458]622
[cf95bc0]623 nodep->size = size;
624 nodep->data = newdata;
[efcebe1]625 return EOK;
[0ee4322]626}
627
[b7fd2a0]628static errno_t tmpfs_close(service_id_t service_id, fs_index_t index)
[c20aa06]629{
[efcebe1]630 return EOK;
[c20aa06]631}
632
[b7fd2a0]633static errno_t tmpfs_destroy(service_id_t service_id, fs_index_t index)
[f17667a]634{
[062d900]635 node_key_t key = {
636 .service_id = service_id,
637 .index = index
[8d049ee0]638 };
[a35b458]639
[062d900]640 ht_link_t *hlp = hash_table_find(&nodes, &key);
[efcebe1]641 if (!hlp)
642 return ENOENT;
[062d900]643 tmpfs_node_t *nodep = hash_table_get_inst(hlp, tmpfs_node_t,
[cf95bc0]644 nh_link);
[efcebe1]645 return tmpfs_destroy_node(FS_NODE(nodep));
[c20aa06]646}
647
[b7fd2a0]648static errno_t tmpfs_sync(service_id_t service_id, fs_index_t index)
[c20aa06]649{
[69a60c4]650 /*
651 * TMPFS keeps its data structures always consistent,
652 * thus the sync operation is a no-op.
653 */
[efcebe1]654 return EOK;
[c20aa06]655}
656
[efcebe1]657vfs_out_ops_t tmpfs_ops = {
[d2c8533]658 .fsprobe = tmpfs_fsprobe,
[efcebe1]659 .mounted = tmpfs_mounted,
660 .unmounted = tmpfs_unmounted,
661 .read = tmpfs_read,
662 .write = tmpfs_write,
663 .truncate = tmpfs_truncate,
664 .close = tmpfs_close,
665 .destroy = tmpfs_destroy,
666 .sync = tmpfs_sync,
667};
668
[d5cdffe]669/**
670 * @}
[c20aa06]671 */
[efcebe1]672
Note: See TracBrowser for help on using the repository browser.