tmpfs_ops.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2008 Jakub Jermar
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  *
00009  * - Redistributions of source code must retain the above copyright
00010  *   notice, this list of conditions and the following disclaimer.
00011  * - Redistributions in binary form must reproduce the above copyright
00012  *   notice, this list of conditions and the following disclaimer in the
00013  *   documentation and/or other materials provided with the distribution.
00014  * - The name of the author may not be used to endorse or promote products
00015  *   derived from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00018  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00019  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
00020  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
00021  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
00022  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00023  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00024  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00025  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00026  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00027  */
00028 
00039 #include "tmpfs.h"
00040 #include "../../vfs/vfs.h"
00041 #include <macros.h>
00042 #include <stdint.h>
00043 #include <async.h>
00044 #include <errno.h>
00045 #include <atomic.h>
00046 #include <stdlib.h>
00047 #include <str.h>
00048 #include <stdio.h>
00049 #include <assert.h>
00050 #include <sys/types.h>
00051 #include <adt/hash_table.h>
00052 #include <as.h>
00053 #include <libfs.h>
00054 
00055 #define min(a, b)               ((a) < (b) ? (a) : (b))
00056 #define max(a, b)               ((a) > (b) ? (a) : (b))
00057 
00058 #define NODES_BUCKETS   256
00059 
00061 #define TMPFS_SOME_ROOT         0
00062 
00063 fs_index_t tmpfs_next_index = 1;
00064 
00065 /*
00066  * Implementation of the libfs interface.
00067  */
00068 
00069 /* Forward declarations of static functions. */
00070 static int tmpfs_match(fs_node_t **, fs_node_t *, const char *);
00071 static int tmpfs_node_get(fs_node_t **, devmap_handle_t, fs_index_t);
00072 static int tmpfs_node_open(fs_node_t *);
00073 static int tmpfs_node_put(fs_node_t *);
00074 static int tmpfs_create_node(fs_node_t **, devmap_handle_t, int);
00075 static int tmpfs_destroy_node(fs_node_t *);
00076 static int tmpfs_link_node(fs_node_t *, fs_node_t *, const char *);
00077 static int tmpfs_unlink_node(fs_node_t *, fs_node_t *, const char *);
00078 
00079 /* Implementation of helper functions. */
00080 static int tmpfs_root_get(fs_node_t **rfn, devmap_handle_t devmap_handle)
00081 {
00082         return tmpfs_node_get(rfn, devmap_handle, TMPFS_SOME_ROOT); 
00083 }
00084 
00085 static int tmpfs_has_children(bool *has_children, fs_node_t *fn)
00086 {
00087         *has_children = !list_empty(&TMPFS_NODE(fn)->cs_head);
00088         return EOK;
00089 }
00090 
00091 static fs_index_t tmpfs_index_get(fs_node_t *fn)
00092 {
00093         return TMPFS_NODE(fn)->index;
00094 }
00095 
00096 static aoff64_t tmpfs_size_get(fs_node_t *fn)
00097 {
00098         return TMPFS_NODE(fn)->size;
00099 }
00100 
00101 static unsigned tmpfs_lnkcnt_get(fs_node_t *fn)
00102 {
00103         return TMPFS_NODE(fn)->lnkcnt;
00104 }
00105 
00106 static char tmpfs_plb_get_char(unsigned pos)
00107 {
00108         return tmpfs_reg.plb_ro[pos % PLB_SIZE];
00109 }
00110 
00111 static bool tmpfs_is_directory(fs_node_t *fn)
00112 {
00113         return TMPFS_NODE(fn)->type == TMPFS_DIRECTORY;
00114 }
00115 
00116 static bool tmpfs_is_file(fs_node_t *fn)
00117 {
00118         return TMPFS_NODE(fn)->type == TMPFS_FILE;
00119 }
00120 
00121 static devmap_handle_t tmpfs_device_get(fs_node_t *fn)
00122 {
00123         return 0;
00124 }
00125 
00127 libfs_ops_t tmpfs_libfs_ops = {
00128         .root_get = tmpfs_root_get,
00129         .match = tmpfs_match,
00130         .node_get = tmpfs_node_get,
00131         .node_open = tmpfs_node_open,
00132         .node_put = tmpfs_node_put,
00133         .create = tmpfs_create_node,
00134         .destroy = tmpfs_destroy_node,
00135         .link = tmpfs_link_node,
00136         .unlink = tmpfs_unlink_node,
00137         .has_children = tmpfs_has_children,
00138         .index_get = tmpfs_index_get,
00139         .size_get = tmpfs_size_get,
00140         .lnkcnt_get = tmpfs_lnkcnt_get,
00141         .plb_get_char = tmpfs_plb_get_char,
00142         .is_directory = tmpfs_is_directory,
00143         .is_file = tmpfs_is_file,
00144         .device_get = tmpfs_device_get
00145 };
00146 
00148 hash_table_t nodes;
00149 
00150 #define NODES_KEY_DEV   0       
00151 #define NODES_KEY_INDEX 1
00152 
00153 /* Implementation of hash table interface for the nodes hash table. */
00154 static hash_index_t nodes_hash(unsigned long key[])
00155 {
00156         return key[NODES_KEY_INDEX] % NODES_BUCKETS;
00157 }
00158 
00159 static int nodes_compare(unsigned long key[], hash_count_t keys, link_t *item)
00160 {
00161         tmpfs_node_t *nodep = hash_table_get_instance(item, tmpfs_node_t,
00162             nh_link);
00163         
00164         switch (keys) {
00165         case 1:
00166                 return (nodep->devmap_handle == key[NODES_KEY_DEV]);
00167         case 2: 
00168                 return ((nodep->devmap_handle == key[NODES_KEY_DEV]) &&
00169                     (nodep->index == key[NODES_KEY_INDEX]));
00170         default:
00171                 assert((keys == 1) || (keys == 2));
00172         }
00173 
00174         return 0;
00175 }
00176 
00177 static void nodes_remove_callback(link_t *item)
00178 {
00179         tmpfs_node_t *nodep = hash_table_get_instance(item, tmpfs_node_t,
00180             nh_link);
00181 
00182         while (!list_empty(&nodep->cs_head)) {
00183                 tmpfs_dentry_t *dentryp = list_get_instance(nodep->cs_head.next,
00184                     tmpfs_dentry_t, link);
00185 
00186                 assert(nodep->type == TMPFS_DIRECTORY);
00187                 list_remove(&dentryp->link);
00188                 free(dentryp);
00189         }
00190 
00191         if (nodep->data) {
00192                 assert(nodep->type == TMPFS_FILE);
00193                 free(nodep->data);
00194         }
00195         free(nodep->bp);
00196         free(nodep);
00197 }
00198 
00200 hash_table_operations_t nodes_ops = {
00201         .hash = nodes_hash,
00202         .compare = nodes_compare,
00203         .remove_callback = nodes_remove_callback
00204 };
00205 
00206 static void tmpfs_node_initialize(tmpfs_node_t *nodep)
00207 {
00208         nodep->bp = NULL;
00209         nodep->index = 0;
00210         nodep->devmap_handle = 0;
00211         nodep->type = TMPFS_NONE;
00212         nodep->lnkcnt = 0;
00213         nodep->size = 0;
00214         nodep->data = NULL;
00215         link_initialize(&nodep->nh_link);
00216         list_initialize(&nodep->cs_head);
00217 }
00218 
00219 static void tmpfs_dentry_initialize(tmpfs_dentry_t *dentryp)
00220 {
00221         link_initialize(&dentryp->link);
00222         dentryp->name = NULL;
00223         dentryp->node = NULL;
00224 }
00225 
00226 bool tmpfs_init(void)
00227 {
00228         if (!hash_table_create(&nodes, NODES_BUCKETS, 2, &nodes_ops))
00229                 return false;
00230         
00231         return true;
00232 }
00233 
00234 static bool tmpfs_instance_init(devmap_handle_t devmap_handle)
00235 {
00236         fs_node_t *rfn;
00237         int rc;
00238         
00239         rc = tmpfs_create_node(&rfn, devmap_handle, L_DIRECTORY);
00240         if (rc != EOK || !rfn)
00241                 return false;
00242         TMPFS_NODE(rfn)->lnkcnt = 0;    /* FS root is not linked */
00243         return true;
00244 }
00245 
00246 static void tmpfs_instance_done(devmap_handle_t devmap_handle)
00247 {
00248         unsigned long key[] = {
00249                 [NODES_KEY_DEV] = devmap_handle
00250         };
00251         /*
00252          * Here we are making use of one special feature of our hash table
00253          * implementation, which allows to remove more items based on a partial
00254          * key match. In the following, we are going to remove all nodes
00255          * matching our device handle. The nodes_remove_callback() function will
00256          * take care of resource deallocation.
00257          */
00258         hash_table_remove(&nodes, key, 1);
00259 }
00260 
00261 int tmpfs_match(fs_node_t **rfn, fs_node_t *pfn, const char *component)
00262 {
00263         tmpfs_node_t *parentp = TMPFS_NODE(pfn);
00264         link_t *lnk;
00265 
00266         for (lnk = parentp->cs_head.next; lnk != &parentp->cs_head;
00267             lnk = lnk->next) {
00268                 tmpfs_dentry_t *dentryp;
00269                 dentryp = list_get_instance(lnk, tmpfs_dentry_t, link);
00270                 if (!str_cmp(dentryp->name, component)) {
00271                         *rfn = FS_NODE(dentryp->node);
00272                         return EOK;
00273                 }
00274         }
00275 
00276         *rfn = NULL;
00277         return EOK;
00278 }
00279 
00280 int tmpfs_node_get(fs_node_t **rfn, devmap_handle_t devmap_handle, fs_index_t index)
00281 {
00282         unsigned long key[] = {
00283                 [NODES_KEY_DEV] = devmap_handle,
00284                 [NODES_KEY_INDEX] = index
00285         };
00286         link_t *lnk = hash_table_find(&nodes, key);
00287         if (lnk) {
00288                 tmpfs_node_t *nodep;
00289                 nodep = hash_table_get_instance(lnk, tmpfs_node_t, nh_link);
00290                 *rfn = FS_NODE(nodep);
00291         } else {
00292                 *rfn = NULL;
00293         }
00294         return EOK;     
00295 }
00296 
00297 int tmpfs_node_open(fs_node_t *fn)
00298 {
00299         /* nothing to do */
00300         return EOK;
00301 }
00302 
00303 int tmpfs_node_put(fs_node_t *fn)
00304 {
00305         /* nothing to do */
00306         return EOK;
00307 }
00308 
00309 int tmpfs_create_node(fs_node_t **rfn, devmap_handle_t devmap_handle, int lflag)
00310 {
00311         fs_node_t *rootfn;
00312         int rc;
00313 
00314         assert((lflag & L_FILE) ^ (lflag & L_DIRECTORY));
00315 
00316         tmpfs_node_t *nodep = malloc(sizeof(tmpfs_node_t));
00317         if (!nodep)
00318                 return ENOMEM;
00319         tmpfs_node_initialize(nodep);
00320         nodep->bp = malloc(sizeof(fs_node_t));
00321         if (!nodep->bp) {
00322                 free(nodep);
00323                 return ENOMEM;
00324         }
00325         fs_node_initialize(nodep->bp);
00326         nodep->bp->data = nodep;        /* link the FS and TMPFS nodes */
00327 
00328         rc = tmpfs_root_get(&rootfn, devmap_handle);
00329         assert(rc == EOK);
00330         if (!rootfn)
00331                 nodep->index = TMPFS_SOME_ROOT;
00332         else
00333                 nodep->index = tmpfs_next_index++;
00334         nodep->devmap_handle = devmap_handle;
00335         if (lflag & L_DIRECTORY) 
00336                 nodep->type = TMPFS_DIRECTORY;
00337         else 
00338                 nodep->type = TMPFS_FILE;
00339 
00340         /* Insert the new node into the nodes hash table. */
00341         unsigned long key[] = {
00342                 [NODES_KEY_DEV] = nodep->devmap_handle,
00343                 [NODES_KEY_INDEX] = nodep->index
00344         };
00345         hash_table_insert(&nodes, key, &nodep->nh_link);
00346         *rfn = FS_NODE(nodep);
00347         return EOK;
00348 }
00349 
00350 int tmpfs_destroy_node(fs_node_t *fn)
00351 {
00352         tmpfs_node_t *nodep = TMPFS_NODE(fn);
00353         
00354         assert(!nodep->lnkcnt);
00355         assert(list_empty(&nodep->cs_head));
00356 
00357         unsigned long key[] = {
00358                 [NODES_KEY_DEV] = nodep->devmap_handle,
00359                 [NODES_KEY_INDEX] = nodep->index
00360         };
00361         hash_table_remove(&nodes, key, 2);
00362 
00363         /*
00364          * The nodes_remove_callback() function takes care of the actual
00365          * resource deallocation.
00366          */
00367         return EOK;
00368 }
00369 
00370 int tmpfs_link_node(fs_node_t *pfn, fs_node_t *cfn, const char *nm)
00371 {
00372         tmpfs_node_t *parentp = TMPFS_NODE(pfn);
00373         tmpfs_node_t *childp = TMPFS_NODE(cfn);
00374         tmpfs_dentry_t *dentryp;
00375         link_t *lnk;
00376 
00377         assert(parentp->type == TMPFS_DIRECTORY);
00378 
00379         /* Check for duplicit entries. */
00380         for (lnk = parentp->cs_head.next; lnk != &parentp->cs_head;
00381             lnk = lnk->next) {
00382                 dentryp = list_get_instance(lnk, tmpfs_dentry_t, link); 
00383                 if (!str_cmp(dentryp->name, nm))
00384                         return EEXIST;
00385         }
00386 
00387         /* Allocate and initialize the dentry. */
00388         dentryp = malloc(sizeof(tmpfs_dentry_t));
00389         if (!dentryp)
00390                 return ENOMEM;
00391         tmpfs_dentry_initialize(dentryp);
00392 
00393         /* Populate and link the new dentry. */
00394         size_t size = str_size(nm);
00395         dentryp->name = malloc(size + 1);
00396         if (!dentryp->name) {
00397                 free(dentryp);
00398                 return ENOMEM;
00399         }
00400         str_cpy(dentryp->name, size + 1, nm);
00401         dentryp->node = childp;
00402         childp->lnkcnt++;
00403         list_append(&dentryp->link, &parentp->cs_head);
00404 
00405         return EOK;
00406 }
00407 
00408 int tmpfs_unlink_node(fs_node_t *pfn, fs_node_t *cfn, const char *nm)
00409 {
00410         tmpfs_node_t *parentp = TMPFS_NODE(pfn);
00411         tmpfs_node_t *childp = NULL;
00412         tmpfs_dentry_t *dentryp;
00413         link_t *lnk;
00414 
00415         if (!parentp)
00416                 return EBUSY;
00417         
00418         for (lnk = parentp->cs_head.next; lnk != &parentp->cs_head;
00419             lnk = lnk->next) {
00420                 dentryp = list_get_instance(lnk, tmpfs_dentry_t, link);
00421                 if (!str_cmp(dentryp->name, nm)) {
00422                         childp = dentryp->node;
00423                         assert(FS_NODE(childp) == cfn);
00424                         break;
00425                 }       
00426         }
00427 
00428         if (!childp)
00429                 return ENOENT;
00430                 
00431         if ((childp->lnkcnt == 1) && !list_empty(&childp->cs_head))
00432                 return ENOTEMPTY;
00433 
00434         list_remove(&dentryp->link);
00435         free(dentryp);
00436         childp->lnkcnt--;
00437 
00438         return EOK;
00439 }
00440 
00441 void tmpfs_mounted(ipc_callid_t rid, ipc_call_t *request)
00442 {
00443         devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
00444         fs_node_t *rootfn;
00445         int rc;
00446         
00447         /* Accept the mount options. */
00448         char *opts;
00449         rc = async_data_write_accept((void **) &opts, true, 0, 0, 0, NULL);
00450         if (rc != EOK) {
00451                 async_answer_0(rid, rc);
00452                 return;
00453         }
00454 
00455         /* Check if this device is not already mounted. */
00456         rc = tmpfs_root_get(&rootfn, devmap_handle);
00457         if ((rc == EOK) && (rootfn)) {
00458                 (void) tmpfs_node_put(rootfn);
00459                 free(opts);
00460                 async_answer_0(rid, EEXIST);
00461                 return;
00462         }
00463 
00464         /* Initialize TMPFS instance. */
00465         if (!tmpfs_instance_init(devmap_handle)) {
00466                 free(opts);
00467                 async_answer_0(rid, ENOMEM);
00468                 return;
00469         }
00470 
00471         rc = tmpfs_root_get(&rootfn, devmap_handle);
00472         assert(rc == EOK);
00473         tmpfs_node_t *rootp = TMPFS_NODE(rootfn);
00474         if (str_cmp(opts, "restore") == 0) {
00475                 if (tmpfs_restore(devmap_handle))
00476                         async_answer_3(rid, EOK, rootp->index, rootp->size,
00477                             rootp->lnkcnt);
00478                 else
00479                         async_answer_0(rid, ELIMIT);
00480         } else {
00481                 async_answer_3(rid, EOK, rootp->index, rootp->size,
00482                     rootp->lnkcnt);
00483         }
00484         free(opts);
00485 }
00486 
00487 void tmpfs_mount(ipc_callid_t rid, ipc_call_t *request)
00488 {
00489         libfs_mount(&tmpfs_libfs_ops, tmpfs_reg.fs_handle, rid, request);
00490 }
00491 
00492 void tmpfs_unmounted(ipc_callid_t rid, ipc_call_t *request)
00493 {
00494         devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
00495 
00496         tmpfs_instance_done(devmap_handle);
00497         async_answer_0(rid, EOK);
00498 }
00499 
00500 void tmpfs_unmount(ipc_callid_t rid, ipc_call_t *request)
00501 {
00502         libfs_unmount(&tmpfs_libfs_ops, rid, request);
00503 }
00504 
00505 void tmpfs_lookup(ipc_callid_t rid, ipc_call_t *request)
00506 {
00507         libfs_lookup(&tmpfs_libfs_ops, tmpfs_reg.fs_handle, rid, request);
00508 }
00509 
00510 void tmpfs_read(ipc_callid_t rid, ipc_call_t *request)
00511 {
00512         devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
00513         fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
00514         aoff64_t pos =
00515             (aoff64_t) MERGE_LOUP32(IPC_GET_ARG3(*request), IPC_GET_ARG4(*request));
00516         
00517         /*
00518          * Lookup the respective TMPFS node.
00519          */
00520         link_t *hlp;
00521         unsigned long key[] = {
00522                 [NODES_KEY_DEV] = devmap_handle,
00523                 [NODES_KEY_INDEX] = index
00524         };
00525         hlp = hash_table_find(&nodes, key);
00526         if (!hlp) {
00527                 async_answer_0(rid, ENOENT);
00528                 return;
00529         }
00530         tmpfs_node_t *nodep = hash_table_get_instance(hlp, tmpfs_node_t,
00531             nh_link);
00532         
00533         /*
00534          * Receive the read request.
00535          */
00536         ipc_callid_t callid;
00537         size_t size;
00538         if (!async_data_read_receive(&callid, &size)) {
00539                 async_answer_0(callid, EINVAL);
00540                 async_answer_0(rid, EINVAL);
00541                 return;
00542         }
00543 
00544         size_t bytes;
00545         if (nodep->type == TMPFS_FILE) {
00546                 bytes = min(nodep->size - pos, size);
00547                 (void) async_data_read_finalize(callid, nodep->data + pos,
00548                     bytes);
00549         } else {
00550                 tmpfs_dentry_t *dentryp;
00551                 link_t *lnk;
00552                 aoff64_t i;
00553                 
00554                 assert(nodep->type == TMPFS_DIRECTORY);
00555                 
00556                 /*
00557                  * Yes, we really use O(n) algorithm here.
00558                  * If it bothers someone, it could be fixed by introducing a
00559                  * hash table.
00560                  */
00561                 for (i = 0, lnk = nodep->cs_head.next;
00562                     (i < pos) && (lnk != &nodep->cs_head);
00563                     i++, lnk = lnk->next)
00564                         ;
00565 
00566                 if (lnk == &nodep->cs_head) {
00567                         async_answer_0(callid, ENOENT);
00568                         async_answer_1(rid, ENOENT, 0);
00569                         return;
00570                 }
00571 
00572                 dentryp = list_get_instance(lnk, tmpfs_dentry_t, link);
00573 
00574                 (void) async_data_read_finalize(callid, dentryp->name,
00575                     str_size(dentryp->name) + 1);
00576                 bytes = 1;
00577         }
00578 
00579         /*
00580          * Answer the VFS_READ call.
00581          */
00582         async_answer_1(rid, EOK, bytes);
00583 }
00584 
00585 void tmpfs_write(ipc_callid_t rid, ipc_call_t *request)
00586 {
00587         devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
00588         fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
00589         aoff64_t pos =
00590             (aoff64_t) MERGE_LOUP32(IPC_GET_ARG3(*request), IPC_GET_ARG4(*request));
00591         
00592         /*
00593          * Lookup the respective TMPFS node.
00594          */
00595         link_t *hlp;
00596         unsigned long key[] = {
00597                 [NODES_KEY_DEV] = devmap_handle,
00598                 [NODES_KEY_INDEX] = index
00599         };
00600         hlp = hash_table_find(&nodes, key);
00601         if (!hlp) {
00602                 async_answer_0(rid, ENOENT);
00603                 return;
00604         }
00605         tmpfs_node_t *nodep = hash_table_get_instance(hlp, tmpfs_node_t,
00606             nh_link);
00607 
00608         /*
00609          * Receive the write request.
00610          */
00611         ipc_callid_t callid;
00612         size_t size;
00613         if (!async_data_write_receive(&callid, &size)) {
00614                 async_answer_0(callid, EINVAL); 
00615                 async_answer_0(rid, EINVAL);
00616                 return;
00617         }
00618 
00619         /*
00620          * Check whether the file needs to grow.
00621          */
00622         if (pos + size <= nodep->size) {
00623                 /* The file size is not changing. */
00624                 (void) async_data_write_finalize(callid, nodep->data + pos, size);
00625                 async_answer_2(rid, EOK, size, nodep->size);
00626                 return;
00627         }
00628         size_t delta = (pos + size) - nodep->size;
00629         /*
00630          * At this point, we are deliberately extremely straightforward and
00631          * simply realloc the contents of the file on every write that grows the
00632          * file. In the end, the situation might not be as bad as it may look:
00633          * our heap allocator can save us and just grow the block whenever
00634          * possible.
00635          */
00636         void *newdata = realloc(nodep->data, nodep->size + delta);
00637         if (!newdata) {
00638                 async_answer_0(callid, ENOMEM);
00639                 async_answer_2(rid, EOK, 0, nodep->size);
00640                 return;
00641         }
00642         /* Clear any newly allocated memory in order to emulate gaps. */
00643         memset(newdata + nodep->size, 0, delta);
00644         nodep->size += delta;
00645         nodep->data = newdata;
00646         (void) async_data_write_finalize(callid, nodep->data + pos, size);
00647         async_answer_2(rid, EOK, size, nodep->size);
00648 }
00649 
00650 void tmpfs_truncate(ipc_callid_t rid, ipc_call_t *request)
00651 {
00652         devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
00653         fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
00654         aoff64_t size =
00655             (aoff64_t) MERGE_LOUP32(IPC_GET_ARG3(*request), IPC_GET_ARG4(*request));
00656         
00657         /*
00658          * Lookup the respective TMPFS node.
00659          */
00660         unsigned long key[] = {
00661                 [NODES_KEY_DEV] = devmap_handle,
00662                 [NODES_KEY_INDEX] = index
00663         };
00664         link_t *hlp = hash_table_find(&nodes, key);
00665         if (!hlp) {
00666                 async_answer_0(rid, ENOENT);
00667                 return;
00668         }
00669         tmpfs_node_t *nodep = hash_table_get_instance(hlp, tmpfs_node_t,
00670             nh_link);
00671         
00672         if (size == nodep->size) {
00673                 async_answer_0(rid, EOK);
00674                 return;
00675         }
00676         
00677         if (size > SIZE_MAX) {
00678                 async_answer_0(rid, ENOMEM);
00679                 return;
00680         }
00681         
00682         void *newdata = realloc(nodep->data, size);
00683         if (!newdata) {
00684                 async_answer_0(rid, ENOMEM);
00685                 return;
00686         }
00687         
00688         if (size > nodep->size) {
00689                 size_t delta = size - nodep->size;
00690                 memset(newdata + nodep->size, 0, delta);
00691         }
00692         
00693         nodep->size = size;
00694         nodep->data = newdata;
00695         async_answer_0(rid, EOK);
00696 }
00697 
00698 void tmpfs_close(ipc_callid_t rid, ipc_call_t *request)
00699 {
00700         async_answer_0(rid, EOK);
00701 }
00702 
00703 void tmpfs_destroy(ipc_callid_t rid, ipc_call_t *request)
00704 {
00705         devmap_handle_t devmap_handle = (devmap_handle_t)IPC_GET_ARG1(*request);
00706         fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request);
00707         int rc;
00708 
00709         link_t *hlp;
00710         unsigned long key[] = {
00711                 [NODES_KEY_DEV] = devmap_handle,
00712                 [NODES_KEY_INDEX] = index
00713         };
00714         hlp = hash_table_find(&nodes, key);
00715         if (!hlp) {
00716                 async_answer_0(rid, ENOENT);
00717                 return;
00718         }
00719         tmpfs_node_t *nodep = hash_table_get_instance(hlp, tmpfs_node_t,
00720             nh_link);
00721         rc = tmpfs_destroy_node(FS_NODE(nodep));
00722         async_answer_0(rid, rc);
00723 }
00724 
00725 void tmpfs_open_node(ipc_callid_t rid, ipc_call_t *request)
00726 {
00727         libfs_open_node(&tmpfs_libfs_ops, tmpfs_reg.fs_handle, rid, request);
00728 }
00729 
00730 void tmpfs_stat(ipc_callid_t rid, ipc_call_t *request)
00731 {
00732         libfs_stat(&tmpfs_libfs_ops, tmpfs_reg.fs_handle, rid, request);
00733 }
00734 
00735 void tmpfs_sync(ipc_callid_t rid, ipc_call_t *request)
00736 {
00737         /*
00738          * TMPFS keeps its data structures always consistent,
00739          * thus the sync operation is a no-op.
00740          */
00741         async_answer_0(rid, EOK);
00742 }
00743 

Generated on Thu Jun 2 07:45:49 2011 for HelenOS/USB by  doxygen 1.4.7