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

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

initialize tmpfs from RAM disk

  • Property mode set to 100644
File size: 19.1 KB
Line 
1/*
2 * Copyright (c) 2008 Jakub Jermar
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 * @{
31 */
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"
41#include <ipc/ipc.h>
42#include <async.h>
43#include <errno.h>
44#include <atomic.h>
45#include <stdlib.h>
46#include <string.h>
47#include <stdio.h>
48#include <assert.h>
49#include <sys/types.h>
50#include <libadt/hash_table.h>
51#include <as.h>
52#include <libfs.h>
53#include <ipc/services.h>
54#include <ipc/devmap.h>
55#include <sys/mman.h>
56#include <byteorder.h>
57
58#define min(a, b) ((a) < (b) ? (a) : (b))
59#define max(a, b) ((a) > (b) ? (a) : (b))
60
61#define DENTRIES_BUCKETS 256
62
63#define NAMES_BUCKETS 4
64
65#define BLOCK_SIZE 1024 // FIXME
66#define RD_BASE 1024 // FIXME
67#define RD_READ_BLOCK (RD_BASE + 1)
68
69/*
70 * For now, we don't distinguish between different dev_handles/instances. All
71 * requests resolve to the only instance, rooted in the following variable.
72 */
73static tmpfs_dentry_t *root;
74
75/*
76 * Implementation of the libfs interface.
77 */
78
79/* Forward declarations of static functions. */
80static void *tmpfs_match(void *, const char *);
81static void *tmpfs_node_get(dev_handle_t, fs_index_t);
82static void tmpfs_node_put(void *);
83static void *tmpfs_create_node(int);
84static bool tmpfs_link_node(void *, void *, const char *);
85static int tmpfs_unlink_node(void *, void *);
86static int tmpfs_destroy_node(void *);
87
88/* Implementation of helper functions. */
89static fs_index_t tmpfs_index_get(void *nodep)
90{
91 return ((tmpfs_dentry_t *) nodep)->index;
92}
93
94static size_t tmpfs_size_get(void *nodep)
95{
96 return ((tmpfs_dentry_t *) nodep)->size;
97}
98
99static unsigned tmpfs_lnkcnt_get(void *nodep)
100{
101 return ((tmpfs_dentry_t *) nodep)->lnkcnt;
102}
103
104static bool tmpfs_has_children(void *nodep)
105{
106 return ((tmpfs_dentry_t *) nodep)->child != NULL;
107}
108
109static void *tmpfs_root_get(dev_handle_t dev_handle)
110{
111 return root;
112}
113
114static char tmpfs_plb_get_char(unsigned pos)
115{
116 return tmpfs_reg.plb_ro[pos % PLB_SIZE];
117}
118
119static bool tmpfs_is_directory(void *nodep)
120{
121 return ((tmpfs_dentry_t *) nodep)->type == TMPFS_DIRECTORY;
122}
123
124static bool tmpfs_is_file(void *nodep)
125{
126 return ((tmpfs_dentry_t *) nodep)->type == TMPFS_FILE;
127}
128
129/** libfs operations */
130libfs_ops_t tmpfs_libfs_ops = {
131 .match = tmpfs_match,
132 .node_get = tmpfs_node_get,
133 .node_put = tmpfs_node_put,
134 .create = tmpfs_create_node,
135 .destroy = tmpfs_destroy_node,
136 .link = tmpfs_link_node,
137 .unlink = tmpfs_unlink_node,
138 .index_get = tmpfs_index_get,
139 .size_get = tmpfs_size_get,
140 .lnkcnt_get = tmpfs_lnkcnt_get,
141 .has_children = tmpfs_has_children,
142 .root_get = tmpfs_root_get,
143 .plb_get_char = tmpfs_plb_get_char,
144 .is_directory = tmpfs_is_directory,
145 .is_file = tmpfs_is_file
146};
147
148/** Hash table of all directory entries. */
149hash_table_t dentries;
150
151struct rdentry {
152 uint8_t type;
153 uint32_t len;
154} __attribute__((packed));
155
156/* Implementation of hash table interface for the dentries hash table. */
157static hash_index_t dentries_hash(unsigned long *key)
158{
159 return *key % DENTRIES_BUCKETS;
160}
161
162static int dentries_compare(unsigned long *key, hash_count_t keys,
163 link_t *item)
164{
165 tmpfs_dentry_t *dentry = hash_table_get_instance(item, tmpfs_dentry_t,
166 dh_link);
167 return dentry->index == *key;
168}
169
170static void dentries_remove_callback(link_t *item)
171{
172}
173
174/** TMPFS dentries hash table operations. */
175hash_table_operations_t dentries_ops = {
176 .hash = dentries_hash,
177 .compare = dentries_compare,
178 .remove_callback = dentries_remove_callback
179};
180
181fs_index_t tmpfs_next_index = 1;
182
183typedef struct {
184 char *name;
185 tmpfs_dentry_t *parent;
186 link_t link;
187} tmpfs_name_t;
188
189/* Implementation of hash table interface for the names hash table. */
190static hash_index_t names_hash(unsigned long *key)
191{
192 tmpfs_dentry_t *dentry = (tmpfs_dentry_t *) *key;
193 return dentry->index % NAMES_BUCKETS;
194}
195
196static int names_compare(unsigned long *key, hash_count_t keys, link_t *item)
197{
198 tmpfs_dentry_t *dentry = (tmpfs_dentry_t *) *key;
199 tmpfs_name_t *namep = hash_table_get_instance(item, tmpfs_name_t,
200 link);
201 return dentry == namep->parent;
202}
203
204static void names_remove_callback(link_t *item)
205{
206 tmpfs_name_t *namep = hash_table_get_instance(item, tmpfs_name_t,
207 link);
208 free(namep->name);
209 free(namep);
210}
211
212/** TMPFS node names hash table operations. */
213static hash_table_operations_t names_ops = {
214 .hash = names_hash,
215 .compare = names_compare,
216 .remove_callback = names_remove_callback
217};
218
219static void tmpfs_name_initialize(tmpfs_name_t *namep)
220{
221 namep->name = NULL;
222 namep->parent = NULL;
223 link_initialize(&namep->link);
224}
225
226static bool tmpfs_dentry_initialize(tmpfs_dentry_t *dentry)
227{
228 dentry->index = 0;
229 dentry->sibling = NULL;
230 dentry->child = NULL;
231 dentry->type = TMPFS_NONE;
232 dentry->lnkcnt = 0;
233 dentry->size = 0;
234 dentry->data = NULL;
235 link_initialize(&dentry->dh_link);
236 return (bool)hash_table_create(&dentry->names, NAMES_BUCKETS, 1,
237 &names_ops);
238}
239
240static bool tmpfs_init(void)
241{
242 if (!hash_table_create(&dentries, DENTRIES_BUCKETS, 1, &dentries_ops))
243 return false;
244 root = (tmpfs_dentry_t *) tmpfs_create_node(L_DIRECTORY);
245 if (!root) {
246 hash_table_destroy(&dentries);
247 return false;
248 }
249 root->lnkcnt = 1;
250 return true;
251}
252
253static bool tmpfs_blockread(int phone, void *buffer, size_t *bufpos, size_t *buflen, size_t *pos, void *dst, size_t size)
254{
255 size_t offset = 0;
256 size_t left = size;
257
258 while (left > 0) {
259 size_t rd;
260
261 if (*bufpos + left < *buflen)
262 rd = left;
263 else
264 rd = *buflen - *bufpos;
265
266 if (rd > 0) {
267 memcpy(dst + offset, buffer + *bufpos, rd);
268 offset += rd;
269 *bufpos += rd;
270 *pos += rd;
271 left -= rd;
272 }
273
274 if (*bufpos == *buflen) {
275 int retval;
276 int rc = ipc_call_sync_2_1(phone, RD_READ_BLOCK, *pos / BLOCK_SIZE, BLOCK_SIZE, (sysarg_t *) &retval);
277 if ((rc != EOK) || (retval != EOK))
278 return false;
279
280 *bufpos = 0;
281 *buflen = BLOCK_SIZE;
282 }
283 }
284
285 return true;
286}
287
288static bool tmpfs_restore_recursion(int phone, void *block, size_t *bufpos, size_t *buflen, size_t *pos, tmpfs_dentry_t *parent)
289{
290 struct rdentry entry;
291
292 do {
293 char *fname;
294 tmpfs_dentry_t *node;
295 uint32_t size;
296
297 if (!tmpfs_blockread(phone, block, bufpos, buflen, pos, &entry, sizeof(entry)))
298 return false;
299
300 entry.len = uint32_t_le2host(entry.len);
301
302 switch (entry.type) {
303 case 0:
304 break;
305 case 1:
306 fname = malloc(entry.len + 1);
307 if (fname == NULL)
308 return false;
309
310 node = (tmpfs_dentry_t *) tmpfs_create_node(L_FILE);
311 if (node == NULL) {
312 free(fname);
313 return false;
314 }
315
316 if (!tmpfs_blockread(phone, block, bufpos, buflen, pos, fname, entry.len)) {
317 tmpfs_destroy_node((void *) node);
318 free(fname);
319 return false;
320 }
321 fname[entry.len] = 0;
322
323 if (!tmpfs_link_node((void *) parent, (void *) node, fname)) {
324 tmpfs_destroy_node((void *) node);
325 free(fname);
326 return false;
327 }
328 free(fname);
329
330 if (!tmpfs_blockread(phone, block, bufpos, buflen, pos, &size, sizeof(size)))
331 return false;
332
333 size = uint32_t_le2host(size);
334
335 node->data = malloc(size);
336 if (node->data == NULL)
337 return false;
338
339 node->size = size;
340 if (!tmpfs_blockread(phone, block, bufpos, buflen, pos, node->data, size))
341 return false;
342
343 break;
344 case 2:
345 fname = malloc(entry.len + 1);
346 if (fname == NULL)
347 return false;
348
349 node = (tmpfs_dentry_t *) tmpfs_create_node(L_DIRECTORY);
350 if (node == NULL) {
351 free(fname);
352 return false;
353 }
354
355 if (!tmpfs_blockread(phone, block, bufpos, buflen, pos, fname, entry.len)) {
356 tmpfs_destroy_node((void *) node);
357 free(fname);
358 return false;
359 }
360 fname[entry.len] = 0;
361
362 if (!tmpfs_link_node((void *) parent, (void *) node, fname)) {
363 tmpfs_destroy_node((void *) node);
364 free(fname);
365 return false;
366 }
367 free(fname);
368
369 if (!tmpfs_restore_recursion(phone, block, bufpos, buflen, pos, node))
370 return false;
371
372 break;
373 default:
374 return false;
375 }
376 } while (entry.type != 0);
377
378 return true;
379}
380
381static bool tmpfs_restore(dev_handle_t dev)
382{
383 void *block = mmap(NULL, BLOCK_SIZE,
384 PROTO_READ | PROTO_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
385
386 if (block == NULL)
387 return false;
388
389 int phone = ipc_connect_me_to(PHONE_NS, SERVICE_DEVMAP, DEVMAP_CONNECT_TO_DEVICE, dev);
390
391 if (phone < 0) {
392 munmap(block, BLOCK_SIZE);
393 return false;
394 }
395
396 if (ipc_share_out_start(phone, block, AS_AREA_READ | AS_AREA_WRITE) != EOK)
397 goto error;
398
399 size_t bufpos = 0;
400 size_t buflen = 0;
401 size_t pos = 0;
402
403 char tag[6];
404 if (!tmpfs_blockread(phone, block, &bufpos, &buflen, &pos, tag, 5))
405 goto error;
406
407 tag[5] = 0;
408 if (strcmp(tag, "TMPFS") != 0)
409 goto error;
410
411 if (!tmpfs_restore_recursion(phone, block, &bufpos, &buflen, &pos, root))
412 goto error;
413
414 ipc_hangup(phone);
415 munmap(block, BLOCK_SIZE);
416 return true;
417
418error:
419 ipc_hangup(phone);
420 munmap(block, BLOCK_SIZE);
421 return false;
422}
423
424/** Compare one component of path to a directory entry.
425 *
426 * @param parentp Pointer to node from which we descended.
427 * @param childp Pointer to node to compare the path component with.
428 * @param component Array of characters holding component name.
429 *
430 * @return True on match, false otherwise.
431 */
432static bool
433tmpfs_match_one(tmpfs_dentry_t *parentp, tmpfs_dentry_t *childp,
434 const char *component)
435{
436 unsigned long key = (unsigned long) parentp;
437 link_t *hlp = hash_table_find(&childp->names, &key);
438 assert(hlp);
439 tmpfs_name_t *namep = hash_table_get_instance(hlp, tmpfs_name_t, link);
440 return !strcmp(namep->name, component);
441}
442
443void *tmpfs_match(void *prnt, const char *component)
444{
445 tmpfs_dentry_t *parentp = (tmpfs_dentry_t *) prnt;
446 tmpfs_dentry_t *childp = parentp->child;
447
448 while (childp && !tmpfs_match_one(parentp, childp, component))
449 childp = childp->sibling;
450
451 return (void *) childp;
452}
453
454void *
455tmpfs_node_get(dev_handle_t dev_handle, fs_index_t index)
456{
457 unsigned long key = index;
458 link_t *lnk = hash_table_find(&dentries, &key);
459 if (!lnk)
460 return NULL;
461 return hash_table_get_instance(lnk, tmpfs_dentry_t, dh_link);
462}
463
464void tmpfs_node_put(void *node)
465{
466 /* nothing to do */
467}
468
469void *tmpfs_create_node(int lflag)
470{
471 assert((lflag & L_FILE) ^ (lflag & L_DIRECTORY));
472
473 tmpfs_dentry_t *node = malloc(sizeof(tmpfs_dentry_t));
474 if (!node)
475 return NULL;
476
477 if (!tmpfs_dentry_initialize(node)) {
478 free(node);
479 return NULL;
480 }
481 node->index = tmpfs_next_index++;
482 if (lflag & L_DIRECTORY)
483 node->type = TMPFS_DIRECTORY;
484 else
485 node->type = TMPFS_FILE;
486
487 /* Insert the new node into the dentry hash table. */
488 unsigned long key = node->index;
489 hash_table_insert(&dentries, &key, &node->dh_link);
490 return (void *) node;
491}
492
493bool tmpfs_link_node(void *prnt, void *chld, const char *nm)
494{
495 tmpfs_dentry_t *parentp = (tmpfs_dentry_t *) prnt;
496 tmpfs_dentry_t *childp = (tmpfs_dentry_t *) chld;
497
498 assert(parentp->type == TMPFS_DIRECTORY);
499
500 tmpfs_name_t *namep = malloc(sizeof(tmpfs_name_t));
501 if (!namep)
502 return false;
503 tmpfs_name_initialize(namep);
504 size_t len = strlen(nm);
505 namep->name = malloc(len + 1);
506 if (!namep->name) {
507 free(namep);
508 return false;
509 }
510 strcpy(namep->name, nm);
511 namep->parent = parentp;
512
513 childp->lnkcnt++;
514
515 unsigned long key = (unsigned long) parentp;
516 hash_table_insert(&childp->names, &key, &namep->link);
517
518 /* Insert the new node into the namespace. */
519 if (parentp->child) {
520 tmpfs_dentry_t *tmp = parentp->child;
521 while (tmp->sibling)
522 tmp = tmp->sibling;
523 tmp->sibling = childp;
524 } else {
525 parentp->child = childp;
526 }
527
528 return true;
529}
530
531int tmpfs_unlink_node(void *prnt, void *chld)
532{
533 tmpfs_dentry_t *parentp = (tmpfs_dentry_t *)prnt;
534 tmpfs_dentry_t *childp = (tmpfs_dentry_t *)chld;
535
536 if (!parentp)
537 return EBUSY;
538
539 if (childp->child)
540 return ENOTEMPTY;
541
542 if (parentp->child == childp) {
543 parentp->child = childp->sibling;
544 } else {
545 /* TODO: consider doubly linked list for organizing siblings. */
546 tmpfs_dentry_t *tmp = parentp->child;
547 while (tmp->sibling != childp)
548 tmp = tmp->sibling;
549 tmp->sibling = childp->sibling;
550 }
551 childp->sibling = NULL;
552
553 unsigned long key = (unsigned long) parentp;
554 hash_table_remove(&childp->names, &key, 1);
555
556 childp->lnkcnt--;
557
558 return EOK;
559}
560
561int tmpfs_destroy_node(void *nodep)
562{
563 tmpfs_dentry_t *dentry = (tmpfs_dentry_t *) nodep;
564
565 assert(!dentry->lnkcnt);
566 assert(!dentry->child);
567 assert(!dentry->sibling);
568
569 unsigned long key = dentry->index;
570 hash_table_remove(&dentries, &key, 1);
571
572 hash_table_destroy(&dentry->names);
573
574 if (dentry->type == TMPFS_FILE)
575 free(dentry->data);
576 free(dentry);
577 return EOK;
578}
579
580void tmpfs_mount(ipc_callid_t rid, ipc_call_t *request)
581{
582 dev_handle_t mr_dev_handle = (dev_handle_t) IPC_GET_ARG1(*request);
583 fs_index_t mr_index = (fs_index_t) IPC_GET_ARG2(*request);
584 fs_handle_t mp_fs_handle = (fs_handle_t) IPC_GET_ARG3(*request);
585 dev_handle_t mp_dev_handle = (dev_handle_t) IPC_GET_ARG4(*request);
586 fs_index_t mp_index = (fs_index_t) IPC_GET_ARG5(*request);
587
588 if ((mr_index == root->index) &&
589 (mp_fs_handle == tmpfs_reg.fs_handle) &&
590 (mp_index == mr_index)) {
591
592 if (mr_dev_handle >= 0) {
593 if (tmpfs_restore(mr_dev_handle))
594 ipc_answer_0(rid, EOK);
595 else
596 ipc_answer_0(rid, ELIMIT);
597 } else
598 ipc_answer_0(rid, EOK);
599 } else
600 ipc_answer_0(rid, ENOTSUP);
601}
602
603void tmpfs_lookup(ipc_callid_t rid, ipc_call_t *request)
604{
605 /* Initialize TMPFS. */
606 if (!root && !tmpfs_init()) {
607 ipc_answer_0(rid, ENOMEM);
608 return;
609 }
610 libfs_lookup(&tmpfs_libfs_ops, tmpfs_reg.fs_handle, rid, request);
611}
612
613void tmpfs_read(ipc_callid_t rid, ipc_call_t *request)
614{
615 dev_handle_t dev_handle = (dev_handle_t)IPC_GET_ARG1(*request);
616 fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request);
617 off_t pos = (off_t)IPC_GET_ARG3(*request);
618
619 /*
620 * Lookup the respective dentry.
621 */
622 link_t *hlp;
623 unsigned long key = index;
624 hlp = hash_table_find(&dentries, &key);
625 if (!hlp) {
626 ipc_answer_0(rid, ENOENT);
627 return;
628 }
629 tmpfs_dentry_t *dentry = hash_table_get_instance(hlp, tmpfs_dentry_t,
630 dh_link);
631
632 /*
633 * Receive the read request.
634 */
635 ipc_callid_t callid;
636 size_t len;
637 if (!ipc_data_read_receive(&callid, &len)) {
638 ipc_answer_0(callid, EINVAL);
639 ipc_answer_0(rid, EINVAL);
640 return;
641 }
642
643 size_t bytes;
644 if (dentry->type == TMPFS_FILE) {
645 bytes = max(0, min(dentry->size - pos, len));
646 (void) ipc_data_read_finalize(callid, dentry->data + pos,
647 bytes);
648 } else {
649 int i;
650 tmpfs_dentry_t *cur;
651
652 assert(dentry->type == TMPFS_DIRECTORY);
653
654 /*
655 * Yes, we really use O(n) algorithm here.
656 * If it bothers someone, it could be fixed by introducing a
657 * hash table.
658 */
659 for (i = 0, cur = dentry->child; i < pos && cur; i++,
660 cur = cur->sibling)
661 ;
662
663 if (!cur) {
664 ipc_answer_0(callid, ENOENT);
665 ipc_answer_1(rid, ENOENT, 0);
666 return;
667 }
668
669 unsigned long key = (unsigned long) dentry;
670 link_t *hlp = hash_table_find(&cur->names, &key);
671 assert(hlp);
672 tmpfs_name_t *namep = hash_table_get_instance(hlp, tmpfs_name_t,
673 link);
674
675 (void) ipc_data_read_finalize(callid, namep->name,
676 strlen(namep->name) + 1);
677 bytes = 1;
678 }
679
680 /*
681 * Answer the VFS_READ call.
682 */
683 ipc_answer_1(rid, EOK, bytes);
684}
685
686void tmpfs_write(ipc_callid_t rid, ipc_call_t *request)
687{
688 dev_handle_t dev_handle = (dev_handle_t)IPC_GET_ARG1(*request);
689 fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request);
690 off_t pos = (off_t)IPC_GET_ARG3(*request);
691
692 /*
693 * Lookup the respective dentry.
694 */
695 link_t *hlp;
696 unsigned long key = index;
697 hlp = hash_table_find(&dentries, &key);
698 if (!hlp) {
699 ipc_answer_0(rid, ENOENT);
700 return;
701 }
702 tmpfs_dentry_t *dentry = hash_table_get_instance(hlp, tmpfs_dentry_t,
703 dh_link);
704
705 /*
706 * Receive the write request.
707 */
708 ipc_callid_t callid;
709 size_t len;
710 if (!ipc_data_write_receive(&callid, &len)) {
711 ipc_answer_0(callid, EINVAL);
712 ipc_answer_0(rid, EINVAL);
713 return;
714 }
715
716 /*
717 * Check whether the file needs to grow.
718 */
719 if (pos + len <= dentry->size) {
720 /* The file size is not changing. */
721 (void) ipc_data_write_finalize(callid, dentry->data + pos, len);
722 ipc_answer_2(rid, EOK, len, dentry->size);
723 return;
724 }
725 size_t delta = (pos + len) - dentry->size;
726 /*
727 * At this point, we are deliberately extremely straightforward and
728 * simply realloc the contents of the file on every write that grows the
729 * file. In the end, the situation might not be as bad as it may look:
730 * our heap allocator can save us and just grow the block whenever
731 * possible.
732 */
733 void *newdata = realloc(dentry->data, dentry->size + delta);
734 if (!newdata) {
735 ipc_answer_0(callid, ENOMEM);
736 ipc_answer_2(rid, EOK, 0, dentry->size);
737 return;
738 }
739 /* Clear any newly allocated memory in order to emulate gaps. */
740 memset(newdata + dentry->size, 0, delta);
741 dentry->size += delta;
742 dentry->data = newdata;
743 (void) ipc_data_write_finalize(callid, dentry->data + pos, len);
744 ipc_answer_2(rid, EOK, len, dentry->size);
745}
746
747void tmpfs_truncate(ipc_callid_t rid, ipc_call_t *request)
748{
749 dev_handle_t dev_handle = (dev_handle_t)IPC_GET_ARG1(*request);
750 fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request);
751 size_t size = (off_t)IPC_GET_ARG3(*request);
752
753 /*
754 * Lookup the respective dentry.
755 */
756 link_t *hlp;
757 unsigned long key = index;
758 hlp = hash_table_find(&dentries, &key);
759 if (!hlp) {
760 ipc_answer_0(rid, ENOENT);
761 return;
762 }
763 tmpfs_dentry_t *dentry = hash_table_get_instance(hlp, tmpfs_dentry_t,
764 dh_link);
765
766 if (size == dentry->size) {
767 ipc_answer_0(rid, EOK);
768 return;
769 }
770
771 void *newdata = realloc(dentry->data, size);
772 if (!newdata) {
773 ipc_answer_0(rid, ENOMEM);
774 return;
775 }
776 if (size > dentry->size) {
777 size_t delta = size - dentry->size;
778 memset(newdata + dentry->size, 0, delta);
779 }
780 dentry->size = size;
781 dentry->data = newdata;
782 ipc_answer_0(rid, EOK);
783}
784
785void tmpfs_destroy(ipc_callid_t rid, ipc_call_t *request)
786{
787 dev_handle_t dev_handle = (dev_handle_t)IPC_GET_ARG1(*request);
788 fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request);
789 int rc;
790
791 link_t *hlp;
792 unsigned long key = index;
793 hlp = hash_table_find(&dentries, &key);
794 if (!hlp) {
795 ipc_answer_0(rid, ENOENT);
796 return;
797 }
798 tmpfs_dentry_t *dentry = hash_table_get_instance(hlp, tmpfs_dentry_t,
799 dh_link);
800 rc = tmpfs_destroy_node(dentry);
801 ipc_answer_0(rid, rc);
802}
803
804/**
805 * @}
806 */
Note: See TracBrowser for help on using the repository browser.