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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 32443b0 was 7f880ee8, checked in by Jakub Jermar <jakub@…>, 17 years ago

Return value argument to ipc_call_sync_X_Y() may not be int or it will
break on 64-machines that are sensitive to unaligned memory accesses.
Moreover, overcasting int * to sysarg_t * is not a good idea either
even if the int is by chance aligned on a 64-bit boundary as some
unknown memory will get overwritten during the assignment. Change the
type of the retval argument to ipcarg_t.

  • 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 ipcarg_t retval;
276 int rc = ipc_call_sync_2_1(phone, RD_READ_BLOCK,
277 *pos / BLOCK_SIZE, BLOCK_SIZE,
278 &retval);
279 if ((rc != EOK) || (retval != EOK))
280 return false;
281
282 *bufpos = 0;
283 *buflen = BLOCK_SIZE;
284 }
285 }
286
287 return true;
288}
289
290static bool tmpfs_restore_recursion(int phone, void *block, size_t *bufpos, size_t *buflen, size_t *pos, tmpfs_dentry_t *parent)
291{
292 struct rdentry entry;
293
294 do {
295 char *fname;
296 tmpfs_dentry_t *node;
297 uint32_t size;
298
299 if (!tmpfs_blockread(phone, block, bufpos, buflen, pos, &entry, sizeof(entry)))
300 return false;
301
302 entry.len = uint32_t_le2host(entry.len);
303
304 switch (entry.type) {
305 case 0:
306 break;
307 case 1:
308 fname = malloc(entry.len + 1);
309 if (fname == NULL)
310 return false;
311
312 node = (tmpfs_dentry_t *) tmpfs_create_node(L_FILE);
313 if (node == NULL) {
314 free(fname);
315 return false;
316 }
317
318 if (!tmpfs_blockread(phone, block, bufpos, buflen, pos, fname, entry.len)) {
319 tmpfs_destroy_node((void *) node);
320 free(fname);
321 return false;
322 }
323 fname[entry.len] = 0;
324
325 if (!tmpfs_link_node((void *) parent, (void *) node, fname)) {
326 tmpfs_destroy_node((void *) node);
327 free(fname);
328 return false;
329 }
330 free(fname);
331
332 if (!tmpfs_blockread(phone, block, bufpos, buflen, pos, &size, sizeof(size)))
333 return false;
334
335 size = uint32_t_le2host(size);
336
337 node->data = malloc(size);
338 if (node->data == NULL)
339 return false;
340
341 node->size = size;
342 if (!tmpfs_blockread(phone, block, bufpos, buflen, pos, node->data, size))
343 return false;
344
345 break;
346 case 2:
347 fname = malloc(entry.len + 1);
348 if (fname == NULL)
349 return false;
350
351 node = (tmpfs_dentry_t *) tmpfs_create_node(L_DIRECTORY);
352 if (node == NULL) {
353 free(fname);
354 return false;
355 }
356
357 if (!tmpfs_blockread(phone, block, bufpos, buflen, pos, fname, entry.len)) {
358 tmpfs_destroy_node((void *) node);
359 free(fname);
360 return false;
361 }
362 fname[entry.len] = 0;
363
364 if (!tmpfs_link_node((void *) parent, (void *) node, fname)) {
365 tmpfs_destroy_node((void *) node);
366 free(fname);
367 return false;
368 }
369 free(fname);
370
371 if (!tmpfs_restore_recursion(phone, block, bufpos, buflen, pos, node))
372 return false;
373
374 break;
375 default:
376 return false;
377 }
378 } while (entry.type != 0);
379
380 return true;
381}
382
383static bool tmpfs_restore(dev_handle_t dev)
384{
385 void *block = mmap(NULL, BLOCK_SIZE,
386 PROTO_READ | PROTO_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
387
388 if (block == NULL)
389 return false;
390
391 int phone = ipc_connect_me_to(PHONE_NS, SERVICE_DEVMAP, DEVMAP_CONNECT_TO_DEVICE, dev);
392
393 if (phone < 0) {
394 munmap(block, BLOCK_SIZE);
395 return false;
396 }
397
398 if (ipc_share_out_start(phone, block, AS_AREA_READ | AS_AREA_WRITE) != EOK)
399 goto error;
400
401 size_t bufpos = 0;
402 size_t buflen = 0;
403 size_t pos = 0;
404
405 char tag[6];
406 if (!tmpfs_blockread(phone, block, &bufpos, &buflen, &pos, tag, 5))
407 goto error;
408
409 tag[5] = 0;
410 if (strcmp(tag, "TMPFS") != 0)
411 goto error;
412
413 if (!tmpfs_restore_recursion(phone, block, &bufpos, &buflen, &pos, root))
414 goto error;
415
416 ipc_hangup(phone);
417 munmap(block, BLOCK_SIZE);
418 return true;
419
420error:
421 ipc_hangup(phone);
422 munmap(block, BLOCK_SIZE);
423 return false;
424}
425
426/** Compare one component of path to a directory entry.
427 *
428 * @param parentp Pointer to node from which we descended.
429 * @param childp Pointer to node to compare the path component with.
430 * @param component Array of characters holding component name.
431 *
432 * @return True on match, false otherwise.
433 */
434static bool
435tmpfs_match_one(tmpfs_dentry_t *parentp, tmpfs_dentry_t *childp,
436 const char *component)
437{
438 unsigned long key = (unsigned long) parentp;
439 link_t *hlp = hash_table_find(&childp->names, &key);
440 assert(hlp);
441 tmpfs_name_t *namep = hash_table_get_instance(hlp, tmpfs_name_t, link);
442 return !strcmp(namep->name, component);
443}
444
445void *tmpfs_match(void *prnt, const char *component)
446{
447 tmpfs_dentry_t *parentp = (tmpfs_dentry_t *) prnt;
448 tmpfs_dentry_t *childp = parentp->child;
449
450 while (childp && !tmpfs_match_one(parentp, childp, component))
451 childp = childp->sibling;
452
453 return (void *) childp;
454}
455
456void *
457tmpfs_node_get(dev_handle_t dev_handle, fs_index_t index)
458{
459 unsigned long key = index;
460 link_t *lnk = hash_table_find(&dentries, &key);
461 if (!lnk)
462 return NULL;
463 return hash_table_get_instance(lnk, tmpfs_dentry_t, dh_link);
464}
465
466void tmpfs_node_put(void *node)
467{
468 /* nothing to do */
469}
470
471void *tmpfs_create_node(int lflag)
472{
473 assert((lflag & L_FILE) ^ (lflag & L_DIRECTORY));
474
475 tmpfs_dentry_t *node = malloc(sizeof(tmpfs_dentry_t));
476 if (!node)
477 return NULL;
478
479 if (!tmpfs_dentry_initialize(node)) {
480 free(node);
481 return NULL;
482 }
483 node->index = tmpfs_next_index++;
484 if (lflag & L_DIRECTORY)
485 node->type = TMPFS_DIRECTORY;
486 else
487 node->type = TMPFS_FILE;
488
489 /* Insert the new node into the dentry hash table. */
490 unsigned long key = node->index;
491 hash_table_insert(&dentries, &key, &node->dh_link);
492 return (void *) node;
493}
494
495bool tmpfs_link_node(void *prnt, void *chld, const char *nm)
496{
497 tmpfs_dentry_t *parentp = (tmpfs_dentry_t *) prnt;
498 tmpfs_dentry_t *childp = (tmpfs_dentry_t *) chld;
499
500 assert(parentp->type == TMPFS_DIRECTORY);
501
502 tmpfs_name_t *namep = malloc(sizeof(tmpfs_name_t));
503 if (!namep)
504 return false;
505 tmpfs_name_initialize(namep);
506 size_t len = strlen(nm);
507 namep->name = malloc(len + 1);
508 if (!namep->name) {
509 free(namep);
510 return false;
511 }
512 strcpy(namep->name, nm);
513 namep->parent = parentp;
514
515 childp->lnkcnt++;
516
517 unsigned long key = (unsigned long) parentp;
518 hash_table_insert(&childp->names, &key, &namep->link);
519
520 /* Insert the new node into the namespace. */
521 if (parentp->child) {
522 tmpfs_dentry_t *tmp = parentp->child;
523 while (tmp->sibling)
524 tmp = tmp->sibling;
525 tmp->sibling = childp;
526 } else {
527 parentp->child = childp;
528 }
529
530 return true;
531}
532
533int tmpfs_unlink_node(void *prnt, void *chld)
534{
535 tmpfs_dentry_t *parentp = (tmpfs_dentry_t *)prnt;
536 tmpfs_dentry_t *childp = (tmpfs_dentry_t *)chld;
537
538 if (!parentp)
539 return EBUSY;
540
541 if (childp->child)
542 return ENOTEMPTY;
543
544 if (parentp->child == childp) {
545 parentp->child = childp->sibling;
546 } else {
547 /* TODO: consider doubly linked list for organizing siblings. */
548 tmpfs_dentry_t *tmp = parentp->child;
549 while (tmp->sibling != childp)
550 tmp = tmp->sibling;
551 tmp->sibling = childp->sibling;
552 }
553 childp->sibling = NULL;
554
555 unsigned long key = (unsigned long) parentp;
556 hash_table_remove(&childp->names, &key, 1);
557
558 childp->lnkcnt--;
559
560 return EOK;
561}
562
563int tmpfs_destroy_node(void *nodep)
564{
565 tmpfs_dentry_t *dentry = (tmpfs_dentry_t *) nodep;
566
567 assert(!dentry->lnkcnt);
568 assert(!dentry->child);
569 assert(!dentry->sibling);
570
571 unsigned long key = dentry->index;
572 hash_table_remove(&dentries, &key, 1);
573
574 hash_table_destroy(&dentry->names);
575
576 if (dentry->type == TMPFS_FILE)
577 free(dentry->data);
578 free(dentry);
579 return EOK;
580}
581
582void tmpfs_mount(ipc_callid_t rid, ipc_call_t *request)
583{
584 dev_handle_t mr_dev_handle = (dev_handle_t) IPC_GET_ARG1(*request);
585 fs_index_t mr_index = (fs_index_t) IPC_GET_ARG2(*request);
586 fs_handle_t mp_fs_handle = (fs_handle_t) IPC_GET_ARG3(*request);
587 dev_handle_t mp_dev_handle = (dev_handle_t) IPC_GET_ARG4(*request);
588 fs_index_t mp_index = (fs_index_t) IPC_GET_ARG5(*request);
589
590 if ((mr_index == root->index) &&
591 (mp_fs_handle == tmpfs_reg.fs_handle) &&
592 (mp_index == mr_index)) {
593
594 if (mr_dev_handle >= 0) {
595 if (tmpfs_restore(mr_dev_handle))
596 ipc_answer_0(rid, EOK);
597 else
598 ipc_answer_0(rid, ELIMIT);
599 } else
600 ipc_answer_0(rid, EOK);
601 } else
602 ipc_answer_0(rid, ENOTSUP);
603}
604
605void tmpfs_lookup(ipc_callid_t rid, ipc_call_t *request)
606{
607 /* Initialize TMPFS. */
608 if (!root && !tmpfs_init()) {
609 ipc_answer_0(rid, ENOMEM);
610 return;
611 }
612 libfs_lookup(&tmpfs_libfs_ops, tmpfs_reg.fs_handle, rid, request);
613}
614
615void tmpfs_read(ipc_callid_t rid, ipc_call_t *request)
616{
617 dev_handle_t dev_handle = (dev_handle_t)IPC_GET_ARG1(*request);
618 fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request);
619 off_t pos = (off_t)IPC_GET_ARG3(*request);
620
621 /*
622 * Lookup the respective dentry.
623 */
624 link_t *hlp;
625 unsigned long key = index;
626 hlp = hash_table_find(&dentries, &key);
627 if (!hlp) {
628 ipc_answer_0(rid, ENOENT);
629 return;
630 }
631 tmpfs_dentry_t *dentry = hash_table_get_instance(hlp, tmpfs_dentry_t,
632 dh_link);
633
634 /*
635 * Receive the read request.
636 */
637 ipc_callid_t callid;
638 size_t len;
639 if (!ipc_data_read_receive(&callid, &len)) {
640 ipc_answer_0(callid, EINVAL);
641 ipc_answer_0(rid, EINVAL);
642 return;
643 }
644
645 size_t bytes;
646 if (dentry->type == TMPFS_FILE) {
647 bytes = max(0, min(dentry->size - pos, len));
648 (void) ipc_data_read_finalize(callid, dentry->data + pos,
649 bytes);
650 } else {
651 int i;
652 tmpfs_dentry_t *cur;
653
654 assert(dentry->type == TMPFS_DIRECTORY);
655
656 /*
657 * Yes, we really use O(n) algorithm here.
658 * If it bothers someone, it could be fixed by introducing a
659 * hash table.
660 */
661 for (i = 0, cur = dentry->child; i < pos && cur; i++,
662 cur = cur->sibling)
663 ;
664
665 if (!cur) {
666 ipc_answer_0(callid, ENOENT);
667 ipc_answer_1(rid, ENOENT, 0);
668 return;
669 }
670
671 unsigned long key = (unsigned long) dentry;
672 link_t *hlp = hash_table_find(&cur->names, &key);
673 assert(hlp);
674 tmpfs_name_t *namep = hash_table_get_instance(hlp, tmpfs_name_t,
675 link);
676
677 (void) ipc_data_read_finalize(callid, namep->name,
678 strlen(namep->name) + 1);
679 bytes = 1;
680 }
681
682 /*
683 * Answer the VFS_READ call.
684 */
685 ipc_answer_1(rid, EOK, bytes);
686}
687
688void tmpfs_write(ipc_callid_t rid, ipc_call_t *request)
689{
690 dev_handle_t dev_handle = (dev_handle_t)IPC_GET_ARG1(*request);
691 fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request);
692 off_t pos = (off_t)IPC_GET_ARG3(*request);
693
694 /*
695 * Lookup the respective dentry.
696 */
697 link_t *hlp;
698 unsigned long key = index;
699 hlp = hash_table_find(&dentries, &key);
700 if (!hlp) {
701 ipc_answer_0(rid, ENOENT);
702 return;
703 }
704 tmpfs_dentry_t *dentry = hash_table_get_instance(hlp, tmpfs_dentry_t,
705 dh_link);
706
707 /*
708 * Receive the write request.
709 */
710 ipc_callid_t callid;
711 size_t len;
712 if (!ipc_data_write_receive(&callid, &len)) {
713 ipc_answer_0(callid, EINVAL);
714 ipc_answer_0(rid, EINVAL);
715 return;
716 }
717
718 /*
719 * Check whether the file needs to grow.
720 */
721 if (pos + len <= dentry->size) {
722 /* The file size is not changing. */
723 (void) ipc_data_write_finalize(callid, dentry->data + pos, len);
724 ipc_answer_2(rid, EOK, len, dentry->size);
725 return;
726 }
727 size_t delta = (pos + len) - dentry->size;
728 /*
729 * At this point, we are deliberately extremely straightforward and
730 * simply realloc the contents of the file on every write that grows the
731 * file. In the end, the situation might not be as bad as it may look:
732 * our heap allocator can save us and just grow the block whenever
733 * possible.
734 */
735 void *newdata = realloc(dentry->data, dentry->size + delta);
736 if (!newdata) {
737 ipc_answer_0(callid, ENOMEM);
738 ipc_answer_2(rid, EOK, 0, dentry->size);
739 return;
740 }
741 /* Clear any newly allocated memory in order to emulate gaps. */
742 memset(newdata + dentry->size, 0, delta);
743 dentry->size += delta;
744 dentry->data = newdata;
745 (void) ipc_data_write_finalize(callid, dentry->data + pos, len);
746 ipc_answer_2(rid, EOK, len, dentry->size);
747}
748
749void tmpfs_truncate(ipc_callid_t rid, ipc_call_t *request)
750{
751 dev_handle_t dev_handle = (dev_handle_t)IPC_GET_ARG1(*request);
752 fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request);
753 size_t size = (off_t)IPC_GET_ARG3(*request);
754
755 /*
756 * Lookup the respective dentry.
757 */
758 link_t *hlp;
759 unsigned long key = index;
760 hlp = hash_table_find(&dentries, &key);
761 if (!hlp) {
762 ipc_answer_0(rid, ENOENT);
763 return;
764 }
765 tmpfs_dentry_t *dentry = hash_table_get_instance(hlp, tmpfs_dentry_t,
766 dh_link);
767
768 if (size == dentry->size) {
769 ipc_answer_0(rid, EOK);
770 return;
771 }
772
773 void *newdata = realloc(dentry->data, size);
774 if (!newdata) {
775 ipc_answer_0(rid, ENOMEM);
776 return;
777 }
778 if (size > dentry->size) {
779 size_t delta = size - dentry->size;
780 memset(newdata + dentry->size, 0, delta);
781 }
782 dentry->size = size;
783 dentry->data = newdata;
784 ipc_answer_0(rid, EOK);
785}
786
787void tmpfs_destroy(ipc_callid_t rid, ipc_call_t *request)
788{
789 dev_handle_t dev_handle = (dev_handle_t)IPC_GET_ARG1(*request);
790 fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request);
791 int rc;
792
793 link_t *hlp;
794 unsigned long key = index;
795 hlp = hash_table_find(&dentries, &key);
796 if (!hlp) {
797 ipc_answer_0(rid, ENOENT);
798 return;
799 }
800 tmpfs_dentry_t *dentry = hash_table_get_instance(hlp, tmpfs_dentry_t,
801 dh_link);
802 rc = tmpfs_destroy_node(dentry);
803 ipc_answer_0(rid, rc);
804}
805
806/**
807 * @}
808 */
Note: See TracBrowser for help on using the repository browser.