fat_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 
00038 #include "fat.h"
00039 #include "fat_dentry.h"
00040 #include "fat_fat.h"
00041 #include "../../vfs/vfs.h"
00042 #include <libfs.h>
00043 #include <libblock.h>
00044 #include <ipc/services.h>
00045 #include <ipc/devmap.h>
00046 #include <macros.h>
00047 #include <async.h>
00048 #include <errno.h>
00049 #include <str.h>
00050 #include <byteorder.h>
00051 #include <adt/hash_table.h>
00052 #include <adt/list.h>
00053 #include <assert.h>
00054 #include <fibril_synch.h>
00055 #include <sys/mman.h>
00056 #include <align.h>
00057 #include <malloc.h>
00058 
00059 #define FAT_NODE(node)  ((node) ? (fat_node_t *) (node)->data : NULL)
00060 #define FS_NODE(node)   ((node) ? (node)->bp : NULL)
00061 
00062 #define DPS(bs)         (BPS((bs)) / sizeof(fat_dentry_t))
00063 #define BPC(bs)         (BPS((bs)) * SPC((bs)))
00064 
00066 static FIBRIL_MUTEX_INITIALIZE(ffn_mutex);
00067 
00069 static LIST_INITIALIZE(ffn_head);
00070 
00071 /*
00072  * Forward declarations of FAT libfs operations.
00073  */
00074 static int fat_root_get(fs_node_t **, devmap_handle_t);
00075 static int fat_match(fs_node_t **, fs_node_t *, const char *);
00076 static int fat_node_get(fs_node_t **, devmap_handle_t, fs_index_t);
00077 static int fat_node_open(fs_node_t *);
00078 static int fat_node_put(fs_node_t *);
00079 static int fat_create_node(fs_node_t **, devmap_handle_t, int);
00080 static int fat_destroy_node(fs_node_t *);
00081 static int fat_link(fs_node_t *, fs_node_t *, const char *);
00082 static int fat_unlink(fs_node_t *, fs_node_t *, const char *);
00083 static int fat_has_children(bool *, fs_node_t *);
00084 static fs_index_t fat_index_get(fs_node_t *);
00085 static aoff64_t fat_size_get(fs_node_t *);
00086 static unsigned fat_lnkcnt_get(fs_node_t *);
00087 static char fat_plb_get_char(unsigned);
00088 static bool fat_is_directory(fs_node_t *);
00089 static bool fat_is_file(fs_node_t *node);
00090 static devmap_handle_t fat_device_get(fs_node_t *node);
00091 
00092 /*
00093  * Helper functions.
00094  */
00095 static void fat_node_initialize(fat_node_t *node)
00096 {
00097         fibril_mutex_initialize(&node->lock);
00098         node->bp = NULL;
00099         node->idx = NULL;
00100         node->type = 0;
00101         link_initialize(&node->ffn_link);
00102         node->size = 0;
00103         node->lnkcnt = 0;
00104         node->refcnt = 0;
00105         node->dirty = false;
00106         node->lastc_cached_valid = false;
00107         node->lastc_cached_value = FAT_CLST_LAST1;
00108         node->currc_cached_valid = false;
00109         node->currc_cached_bn = 0;
00110         node->currc_cached_value = FAT_CLST_LAST1;
00111 }
00112 
00113 static int fat_node_sync(fat_node_t *node)
00114 {
00115         block_t *b;
00116         fat_bs_t *bs;
00117         fat_dentry_t *d;
00118         int rc;
00119         
00120         assert(node->dirty);
00121 
00122         bs = block_bb_get(node->idx->devmap_handle);
00123         
00124         /* Read the block that contains the dentry of interest. */
00125         rc = _fat_block_get(&b, bs, node->idx->devmap_handle, node->idx->pfc,
00126             NULL, (node->idx->pdi * sizeof(fat_dentry_t)) / BPS(bs),
00127             BLOCK_FLAGS_NONE);
00128         if (rc != EOK)
00129                 return rc;
00130 
00131         d = ((fat_dentry_t *)b->data) + (node->idx->pdi % DPS(bs));
00132 
00133         d->firstc = host2uint16_t_le(node->firstc);
00134         if (node->type == FAT_FILE) {
00135                 d->size = host2uint32_t_le(node->size);
00136         } else if (node->type == FAT_DIRECTORY) {
00137                 d->attr = FAT_ATTR_SUBDIR;
00138         }
00139         
00140         /* TODO: update other fields? (e.g time fields) */
00141         
00142         b->dirty = true;                /* need to sync block */
00143         rc = block_put(b);
00144         return rc;
00145 }
00146 
00147 static int fat_node_fini_by_devmap_handle(devmap_handle_t devmap_handle)
00148 {
00149         link_t *lnk;
00150         fat_node_t *nodep;
00151         int rc;
00152 
00153         /*
00154          * We are called from fat_unmounted() and assume that there are already
00155          * no nodes belonging to this instance with non-zero refcount. Therefore
00156          * it is sufficient to clean up only the FAT free node list.
00157          */
00158 
00159 restart:
00160         fibril_mutex_lock(&ffn_mutex);
00161         for (lnk = ffn_head.next; lnk != &ffn_head; lnk = lnk->next) {
00162                 nodep = list_get_instance(lnk, fat_node_t, ffn_link);
00163                 if (!fibril_mutex_trylock(&nodep->lock)) {
00164                         fibril_mutex_unlock(&ffn_mutex);
00165                         goto restart;
00166                 }
00167                 if (!fibril_mutex_trylock(&nodep->idx->lock)) {
00168                         fibril_mutex_unlock(&nodep->lock);
00169                         fibril_mutex_unlock(&ffn_mutex);
00170                         goto restart;
00171                 }
00172                 if (nodep->idx->devmap_handle != devmap_handle) {
00173                         fibril_mutex_unlock(&nodep->idx->lock);
00174                         fibril_mutex_unlock(&nodep->lock);
00175                         continue;
00176                 }
00177 
00178                 list_remove(&nodep->ffn_link);
00179                 fibril_mutex_unlock(&ffn_mutex);
00180 
00181                 /*
00182                  * We can unlock the node and its index structure because we are
00183                  * the last player on this playground and VFS is preventing new
00184                  * players from entering.
00185                  */
00186                 fibril_mutex_unlock(&nodep->idx->lock);
00187                 fibril_mutex_unlock(&nodep->lock);
00188 
00189                 if (nodep->dirty) {
00190                         rc = fat_node_sync(nodep);
00191                         if (rc != EOK)
00192                                 return rc;
00193                 }
00194                 nodep->idx->nodep = NULL;
00195                 free(nodep->bp);
00196                 free(nodep);
00197 
00198                 /* Need to restart because we changed the ffn_head list. */
00199                 goto restart;
00200         }
00201         fibril_mutex_unlock(&ffn_mutex);
00202 
00203         return EOK;
00204 }
00205 
00206 static int fat_node_get_new(fat_node_t **nodepp)
00207 {
00208         fs_node_t *fn;
00209         fat_node_t *nodep;
00210         int rc;
00211 
00212         fibril_mutex_lock(&ffn_mutex);
00213         if (!list_empty(&ffn_head)) {
00214                 /* Try to use a cached free node structure. */
00215                 fat_idx_t *idxp_tmp;
00216                 nodep = list_get_instance(ffn_head.next, fat_node_t, ffn_link);
00217                 if (!fibril_mutex_trylock(&nodep->lock))
00218                         goto skip_cache;
00219                 idxp_tmp = nodep->idx;
00220                 if (!fibril_mutex_trylock(&idxp_tmp->lock)) {
00221                         fibril_mutex_unlock(&nodep->lock);
00222                         goto skip_cache;
00223                 }
00224                 list_remove(&nodep->ffn_link);
00225                 fibril_mutex_unlock(&ffn_mutex);
00226                 if (nodep->dirty) {
00227                         rc = fat_node_sync(nodep);
00228                         if (rc != EOK) {
00229                                 idxp_tmp->nodep = NULL;
00230                                 fibril_mutex_unlock(&nodep->lock);
00231                                 fibril_mutex_unlock(&idxp_tmp->lock);
00232                                 free(nodep->bp);
00233                                 free(nodep);
00234                                 return rc;
00235                         }
00236                 }
00237                 idxp_tmp->nodep = NULL;
00238                 fibril_mutex_unlock(&nodep->lock);
00239                 fibril_mutex_unlock(&idxp_tmp->lock);
00240                 fn = FS_NODE(nodep);
00241         } else {
00242 skip_cache:
00243                 /* Try to allocate a new node structure. */
00244                 fibril_mutex_unlock(&ffn_mutex);
00245                 fn = (fs_node_t *)malloc(sizeof(fs_node_t));
00246                 if (!fn)
00247                         return ENOMEM;
00248                 nodep = (fat_node_t *)malloc(sizeof(fat_node_t));
00249                 if (!nodep) {
00250                         free(fn);
00251                         return ENOMEM;
00252                 }
00253         }
00254         fat_node_initialize(nodep);
00255         fs_node_initialize(fn);
00256         fn->data = nodep;
00257         nodep->bp = fn;
00258         
00259         *nodepp = nodep;
00260         return EOK;
00261 }
00262 
00267 static int fat_node_get_core(fat_node_t **nodepp, fat_idx_t *idxp)
00268 {
00269         block_t *b;
00270         fat_bs_t *bs;
00271         fat_dentry_t *d;
00272         fat_node_t *nodep = NULL;
00273         int rc;
00274 
00275         if (idxp->nodep) {
00276                 /*
00277                  * We are lucky.
00278                  * The node is already instantiated in memory.
00279                  */
00280                 fibril_mutex_lock(&idxp->nodep->lock);
00281                 if (!idxp->nodep->refcnt++) {
00282                         fibril_mutex_lock(&ffn_mutex);
00283                         list_remove(&idxp->nodep->ffn_link);
00284                         fibril_mutex_unlock(&ffn_mutex);
00285                 }
00286                 fibril_mutex_unlock(&idxp->nodep->lock);
00287                 *nodepp = idxp->nodep;
00288                 return EOK;
00289         }
00290 
00291         /*
00292          * We must instantiate the node from the file system.
00293          */
00294         
00295         assert(idxp->pfc);
00296 
00297         rc = fat_node_get_new(&nodep);
00298         if (rc != EOK)
00299                 return rc;
00300 
00301         bs = block_bb_get(idxp->devmap_handle);
00302 
00303         /* Read the block that contains the dentry of interest. */
00304         rc = _fat_block_get(&b, bs, idxp->devmap_handle, idxp->pfc, NULL,
00305             (idxp->pdi * sizeof(fat_dentry_t)) / BPS(bs), BLOCK_FLAGS_NONE);
00306         if (rc != EOK) {
00307                 (void) fat_node_put(FS_NODE(nodep));
00308                 return rc;
00309         }
00310 
00311         d = ((fat_dentry_t *)b->data) + (idxp->pdi % DPS(bs));
00312         if (d->attr & FAT_ATTR_SUBDIR) {
00313                 /* 
00314                  * The only directory which does not have this bit set is the
00315                  * root directory itself. The root directory node is handled
00316                  * and initialized elsewhere.
00317                  */
00318                 nodep->type = FAT_DIRECTORY;
00319                 /*
00320                  * Unfortunately, the 'size' field of the FAT dentry is not
00321                  * defined for the directory entry type. We must determine the
00322                  * size of the directory by walking the FAT.
00323                  */
00324                 uint16_t clusters;
00325                 rc = fat_clusters_get(&clusters, bs, idxp->devmap_handle,
00326                     uint16_t_le2host(d->firstc));
00327                 if (rc != EOK) {
00328                         (void) block_put(b);
00329                         (void) fat_node_put(FS_NODE(nodep));
00330                         return rc;
00331                 }
00332                 nodep->size = BPS(bs) * SPC(bs) * clusters;
00333         } else {
00334                 nodep->type = FAT_FILE;
00335                 nodep->size = uint32_t_le2host(d->size);
00336         }
00337         nodep->firstc = uint16_t_le2host(d->firstc);
00338         nodep->lnkcnt = 1;
00339         nodep->refcnt = 1;
00340 
00341         rc = block_put(b);
00342         if (rc != EOK) {
00343                 (void) fat_node_put(FS_NODE(nodep));
00344                 return rc;
00345         }
00346 
00347         /* Link the idx structure with the node structure. */
00348         nodep->idx = idxp;
00349         idxp->nodep = nodep;
00350 
00351         *nodepp = nodep;
00352         return EOK;
00353 }
00354 
00355 /*
00356  * FAT libfs operations.
00357  */
00358 
00359 int fat_root_get(fs_node_t **rfn, devmap_handle_t devmap_handle)
00360 {
00361         return fat_node_get(rfn, devmap_handle, 0);
00362 }
00363 
00364 int fat_match(fs_node_t **rfn, fs_node_t *pfn, const char *component)
00365 {
00366         fat_bs_t *bs;
00367         fat_node_t *parentp = FAT_NODE(pfn);
00368         char name[FAT_NAME_LEN + 1 + FAT_EXT_LEN + 1];
00369         unsigned i, j;
00370         unsigned blocks;
00371         fat_dentry_t *d;
00372         devmap_handle_t devmap_handle;
00373         block_t *b;
00374         int rc;
00375 
00376         fibril_mutex_lock(&parentp->idx->lock);
00377         devmap_handle = parentp->idx->devmap_handle;
00378         fibril_mutex_unlock(&parentp->idx->lock);
00379 
00380         bs = block_bb_get(devmap_handle);
00381         blocks = parentp->size / BPS(bs);
00382         for (i = 0; i < blocks; i++) {
00383                 rc = fat_block_get(&b, bs, parentp, i, BLOCK_FLAGS_NONE);
00384                 if (rc != EOK)
00385                         return rc;
00386                 for (j = 0; j < DPS(bs); j++) { 
00387                         d = ((fat_dentry_t *)b->data) + j;
00388                         switch (fat_classify_dentry(d)) {
00389                         case FAT_DENTRY_SKIP:
00390                         case FAT_DENTRY_FREE:
00391                                 continue;
00392                         case FAT_DENTRY_LAST:
00393                                 /* miss */
00394                                 rc = block_put(b);
00395                                 *rfn = NULL;
00396                                 return rc;
00397                         default:
00398                         case FAT_DENTRY_VALID:
00399                                 fat_dentry_name_get(d, name);
00400                                 break;
00401                         }
00402                         if (fat_dentry_namecmp(name, component) == 0) {
00403                                 /* hit */
00404                                 fat_node_t *nodep;
00405                                 fat_idx_t *idx = fat_idx_get_by_pos(devmap_handle,
00406                                     parentp->firstc, i * DPS(bs) + j);
00407                                 if (!idx) {
00408                                         /*
00409                                          * Can happen if memory is low or if we
00410                                          * run out of 32-bit indices.
00411                                          */
00412                                         rc = block_put(b);
00413                                         return (rc == EOK) ? ENOMEM : rc;
00414                                 }
00415                                 rc = fat_node_get_core(&nodep, idx);
00416                                 fibril_mutex_unlock(&idx->lock);
00417                                 if (rc != EOK) {
00418                                         (void) block_put(b);
00419                                         return rc;
00420                                 }
00421                                 *rfn = FS_NODE(nodep);
00422                                 rc = block_put(b);
00423                                 if (rc != EOK)
00424                                         (void) fat_node_put(*rfn);
00425                                 return rc;
00426                         }
00427                 }
00428                 rc = block_put(b);
00429                 if (rc != EOK)
00430                         return rc;
00431         }
00432 
00433         *rfn = NULL;
00434         return EOK;
00435 }
00436 
00438 int fat_node_get(fs_node_t **rfn, devmap_handle_t devmap_handle, fs_index_t index)
00439 {
00440         fat_node_t *nodep;
00441         fat_idx_t *idxp;
00442         int rc;
00443 
00444         idxp = fat_idx_get_by_index(devmap_handle, index);
00445         if (!idxp) {
00446                 *rfn = NULL;
00447                 return EOK;
00448         }
00449         /* idxp->lock held */
00450         rc = fat_node_get_core(&nodep, idxp);
00451         fibril_mutex_unlock(&idxp->lock);
00452         if (rc == EOK)
00453                 *rfn = FS_NODE(nodep);
00454         return rc;
00455 }
00456 
00457 int fat_node_open(fs_node_t *fn)
00458 {
00459         /*
00460          * Opening a file is stateless, nothing
00461          * to be done here.
00462          */
00463         return EOK;
00464 }
00465 
00466 int fat_node_put(fs_node_t *fn)
00467 {
00468         fat_node_t *nodep = FAT_NODE(fn);
00469         bool destroy = false;
00470 
00471         fibril_mutex_lock(&nodep->lock);
00472         if (!--nodep->refcnt) {
00473                 if (nodep->idx) {
00474                         fibril_mutex_lock(&ffn_mutex);
00475                         list_append(&nodep->ffn_link, &ffn_head);
00476                         fibril_mutex_unlock(&ffn_mutex);
00477                 } else {
00478                         /*
00479                          * The node does not have any index structure associated
00480                          * with itself. This can only mean that we are releasing
00481                          * the node after a failed attempt to allocate the index
00482                          * structure for it.
00483                          */
00484                         destroy = true;
00485                 }
00486         }
00487         fibril_mutex_unlock(&nodep->lock);
00488         if (destroy) {
00489                 free(nodep->bp);
00490                 free(nodep);
00491         }
00492         return EOK;
00493 }
00494 
00495 int fat_create_node(fs_node_t **rfn, devmap_handle_t devmap_handle, int flags)
00496 {
00497         fat_idx_t *idxp;
00498         fat_node_t *nodep;
00499         fat_bs_t *bs;
00500         fat_cluster_t mcl, lcl;
00501         int rc;
00502 
00503         bs = block_bb_get(devmap_handle);
00504         if (flags & L_DIRECTORY) {
00505                 /* allocate a cluster */
00506                 rc = fat_alloc_clusters(bs, devmap_handle, 1, &mcl, &lcl);
00507                 if (rc != EOK)
00508                         return rc;
00509                 /* populate the new cluster with unused dentries */
00510                 rc = fat_zero_cluster(bs, devmap_handle, mcl);
00511                 if (rc != EOK) {
00512                         (void) fat_free_clusters(bs, devmap_handle, mcl);
00513                         return rc;
00514                 }
00515         }
00516 
00517         rc = fat_node_get_new(&nodep);
00518         if (rc != EOK) {
00519                 (void) fat_free_clusters(bs, devmap_handle, mcl);
00520                 return rc;
00521         }
00522         rc = fat_idx_get_new(&idxp, devmap_handle);
00523         if (rc != EOK) {
00524                 (void) fat_free_clusters(bs, devmap_handle, mcl);       
00525                 (void) fat_node_put(FS_NODE(nodep));
00526                 return rc;
00527         }
00528         /* idxp->lock held */
00529         if (flags & L_DIRECTORY) {
00530                 nodep->type = FAT_DIRECTORY;
00531                 nodep->firstc = mcl;
00532                 nodep->size = BPS(bs) * SPC(bs);
00533         } else {
00534                 nodep->type = FAT_FILE;
00535                 nodep->firstc = FAT_CLST_RES0;
00536                 nodep->size = 0;
00537         }
00538         nodep->lnkcnt = 0;      /* not linked anywhere */
00539         nodep->refcnt = 1;
00540         nodep->dirty = true;
00541 
00542         nodep->idx = idxp;
00543         idxp->nodep = nodep;
00544 
00545         fibril_mutex_unlock(&idxp->lock);
00546         *rfn = FS_NODE(nodep);
00547         return EOK;
00548 }
00549 
00550 int fat_destroy_node(fs_node_t *fn)
00551 {
00552         fat_node_t *nodep = FAT_NODE(fn);
00553         fat_bs_t *bs;
00554         bool has_children;
00555         int rc;
00556 
00557         /*
00558          * The node is not reachable from the file system. This means that the
00559          * link count should be zero and that the index structure cannot be
00560          * found in the position hash. Obviously, we don't need to lock the node
00561          * nor its index structure.
00562          */
00563         assert(nodep->lnkcnt == 0);
00564 
00565         /*
00566          * The node may not have any children.
00567          */
00568         rc = fat_has_children(&has_children, fn);
00569         if (rc != EOK)
00570                 return rc;
00571         assert(!has_children);
00572 
00573         bs = block_bb_get(nodep->idx->devmap_handle);
00574         if (nodep->firstc != FAT_CLST_RES0) {
00575                 assert(nodep->size);
00576                 /* Free all clusters allocated to the node. */
00577                 rc = fat_free_clusters(bs, nodep->idx->devmap_handle,
00578                     nodep->firstc);
00579         }
00580 
00581         fat_idx_destroy(nodep->idx);
00582         free(nodep->bp);
00583         free(nodep);
00584         return rc;
00585 }
00586 
00587 int fat_link(fs_node_t *pfn, fs_node_t *cfn, const char *name)
00588 {
00589         fat_node_t *parentp = FAT_NODE(pfn);
00590         fat_node_t *childp = FAT_NODE(cfn);
00591         fat_dentry_t *d;
00592         fat_bs_t *bs;
00593         block_t *b;
00594         unsigned i, j;
00595         unsigned blocks;
00596         fat_cluster_t mcl, lcl;
00597         int rc;
00598 
00599         fibril_mutex_lock(&childp->lock);
00600         if (childp->lnkcnt == 1) {
00601                 /*
00602                  * On FAT, we don't support multiple hard links.
00603                  */
00604                 fibril_mutex_unlock(&childp->lock);
00605                 return EMLINK;
00606         }
00607         assert(childp->lnkcnt == 0);
00608         fibril_mutex_unlock(&childp->lock);
00609 
00610         if (!fat_dentry_name_verify(name)) {
00611                 /*
00612                  * Attempt to create unsupported name.
00613                  */
00614                 return ENOTSUP;
00615         }
00616 
00617         /*
00618          * Get us an unused parent node's dentry or grow the parent and allocate
00619          * a new one.
00620          */
00621         
00622         fibril_mutex_lock(&parentp->idx->lock);
00623         bs = block_bb_get(parentp->idx->devmap_handle);
00624 
00625         blocks = parentp->size / BPS(bs);
00626 
00627         for (i = 0; i < blocks; i++) {
00628                 rc = fat_block_get(&b, bs, parentp, i, BLOCK_FLAGS_NONE);
00629                 if (rc != EOK) {
00630                         fibril_mutex_unlock(&parentp->idx->lock);
00631                         return rc;
00632                 }
00633                 for (j = 0; j < DPS(bs); j++) {
00634                         d = ((fat_dentry_t *)b->data) + j;
00635                         switch (fat_classify_dentry(d)) {
00636                         case FAT_DENTRY_SKIP:
00637                         case FAT_DENTRY_VALID:
00638                                 /* skipping used and meta entries */
00639                                 continue;
00640                         case FAT_DENTRY_FREE:
00641                         case FAT_DENTRY_LAST:
00642                                 /* found an empty slot */
00643                                 goto hit;
00644                         }
00645                 }
00646                 rc = block_put(b);
00647                 if (rc != EOK) {
00648                         fibril_mutex_unlock(&parentp->idx->lock);
00649                         return rc;
00650                 }
00651         }
00652         j = 0;
00653         
00654         /*
00655          * We need to grow the parent in order to create a new unused dentry.
00656          */
00657         if (parentp->firstc == FAT_CLST_ROOT) {
00658                 /* Can't grow the root directory. */
00659                 fibril_mutex_unlock(&parentp->idx->lock);
00660                 return ENOSPC;
00661         }
00662         rc = fat_alloc_clusters(bs, parentp->idx->devmap_handle, 1, &mcl, &lcl);
00663         if (rc != EOK) {
00664                 fibril_mutex_unlock(&parentp->idx->lock);
00665                 return rc;
00666         }
00667         rc = fat_zero_cluster(bs, parentp->idx->devmap_handle, mcl);
00668         if (rc != EOK) {
00669                 (void) fat_free_clusters(bs, parentp->idx->devmap_handle, mcl);
00670                 fibril_mutex_unlock(&parentp->idx->lock);
00671                 return rc;
00672         }
00673         rc = fat_append_clusters(bs, parentp, mcl, lcl);
00674         if (rc != EOK) {
00675                 (void) fat_free_clusters(bs, parentp->idx->devmap_handle, mcl);
00676                 fibril_mutex_unlock(&parentp->idx->lock);
00677                 return rc;
00678         }
00679         parentp->size += BPS(bs) * SPC(bs);
00680         parentp->dirty = true;          /* need to sync node */
00681         rc = fat_block_get(&b, bs, parentp, i, BLOCK_FLAGS_NONE);
00682         if (rc != EOK) {
00683                 fibril_mutex_unlock(&parentp->idx->lock);
00684                 return rc;
00685         }
00686         d = (fat_dentry_t *)b->data;
00687 
00688 hit:
00689         /*
00690          * At this point we only establish the link between the parent and the
00691          * child.  The dentry, except of the name and the extension, will remain
00692          * uninitialized until the corresponding node is synced. Thus the valid
00693          * dentry data is kept in the child node structure.
00694          */
00695         memset(d, 0, sizeof(fat_dentry_t));
00696         fat_dentry_name_set(d, name);
00697         b->dirty = true;                /* need to sync block */
00698         rc = block_put(b);
00699         fibril_mutex_unlock(&parentp->idx->lock);
00700         if (rc != EOK) 
00701                 return rc;
00702 
00703         fibril_mutex_lock(&childp->idx->lock);
00704         
00705         if (childp->type == FAT_DIRECTORY) {
00706                 /*
00707                  * If possible, create the Sub-directory Identifier Entry and
00708                  * the Sub-directory Parent Pointer Entry (i.e. "." and "..").
00709                  * These entries are not mandatory according to Standard
00710                  * ECMA-107 and HelenOS VFS does not use them anyway, so this is
00711                  * rather a sign of our good will.
00712                  */
00713                 rc = fat_block_get(&b, bs, childp, 0, BLOCK_FLAGS_NONE);
00714                 if (rc != EOK) {
00715                         /*
00716                          * Rather than returning an error, simply skip the
00717                          * creation of these two entries.
00718                          */
00719                         goto skip_dots;
00720                 }
00721                 d = (fat_dentry_t *) b->data;
00722                 if ((fat_classify_dentry(d) == FAT_DENTRY_LAST) ||
00723                     (str_cmp((char *) d->name, FAT_NAME_DOT)) == 0) {
00724                         memset(d, 0, sizeof(fat_dentry_t));
00725                         memcpy(d->name, FAT_NAME_DOT, FAT_NAME_LEN);
00726                         memcpy(d->ext, FAT_EXT_PAD, FAT_EXT_LEN);
00727                         d->attr = FAT_ATTR_SUBDIR;
00728                         d->firstc = host2uint16_t_le(childp->firstc);
00729                         /* TODO: initialize also the date/time members. */
00730                 }
00731                 d++;
00732                 if ((fat_classify_dentry(d) == FAT_DENTRY_LAST) ||
00733                     (str_cmp((char *) d->name, FAT_NAME_DOT_DOT) == 0)) {
00734                         memset(d, 0, sizeof(fat_dentry_t));
00735                         memcpy(d->name, FAT_NAME_DOT_DOT, FAT_NAME_LEN);
00736                         memcpy(d->ext, FAT_EXT_PAD, FAT_EXT_LEN);
00737                         d->attr = FAT_ATTR_SUBDIR;
00738                         d->firstc = (parentp->firstc == FAT_CLST_ROOT) ?
00739                             host2uint16_t_le(FAT_CLST_RES0) :
00740                             host2uint16_t_le(parentp->firstc);
00741                         /* TODO: initialize also the date/time members. */
00742                 }
00743                 b->dirty = true;                /* need to sync block */
00744                 /*
00745                  * Ignore the return value as we would have fallen through on error
00746                  * anyway.
00747                  */
00748                 (void) block_put(b);
00749         }
00750 skip_dots:
00751 
00752         childp->idx->pfc = parentp->firstc;
00753         childp->idx->pdi = i * DPS(bs) + j;
00754         fibril_mutex_unlock(&childp->idx->lock);
00755 
00756         fibril_mutex_lock(&childp->lock);
00757         childp->lnkcnt = 1;
00758         childp->dirty = true;           /* need to sync node */
00759         fibril_mutex_unlock(&childp->lock);
00760 
00761         /*
00762          * Hash in the index structure into the position hash.
00763          */
00764         fat_idx_hashin(childp->idx);
00765 
00766         return EOK;
00767 }
00768 
00769 int fat_unlink(fs_node_t *pfn, fs_node_t *cfn, const char *nm)
00770 {
00771         fat_node_t *parentp = FAT_NODE(pfn);
00772         fat_node_t *childp = FAT_NODE(cfn);
00773         fat_bs_t *bs;
00774         fat_dentry_t *d;
00775         block_t *b;
00776         bool has_children;
00777         int rc;
00778 
00779         if (!parentp)
00780                 return EBUSY;
00781         
00782         rc = fat_has_children(&has_children, cfn);
00783         if (rc != EOK)
00784                 return rc;
00785         if (has_children)
00786                 return ENOTEMPTY;
00787 
00788         fibril_mutex_lock(&parentp->lock);
00789         fibril_mutex_lock(&childp->lock);
00790         assert(childp->lnkcnt == 1);
00791         fibril_mutex_lock(&childp->idx->lock);
00792         bs = block_bb_get(childp->idx->devmap_handle);
00793 
00794         rc = _fat_block_get(&b, bs, childp->idx->devmap_handle, childp->idx->pfc,
00795             NULL, (childp->idx->pdi * sizeof(fat_dentry_t)) / BPS(bs),
00796             BLOCK_FLAGS_NONE);
00797         if (rc != EOK) 
00798                 goto error;
00799         d = (fat_dentry_t *)b->data +
00800             (childp->idx->pdi % (BPS(bs) / sizeof(fat_dentry_t)));
00801         /* mark the dentry as not-currently-used */
00802         d->name[0] = FAT_DENTRY_ERASED;
00803         b->dirty = true;                /* need to sync block */
00804         rc = block_put(b);
00805         if (rc != EOK)
00806                 goto error;
00807 
00808         /* remove the index structure from the position hash */
00809         fat_idx_hashout(childp->idx);
00810         /* clear position information */
00811         childp->idx->pfc = FAT_CLST_RES0;
00812         childp->idx->pdi = 0;
00813         fibril_mutex_unlock(&childp->idx->lock);
00814         childp->lnkcnt = 0;
00815         childp->refcnt++;       /* keep the node in memory until destroyed */
00816         childp->dirty = true;
00817         fibril_mutex_unlock(&childp->lock);
00818         fibril_mutex_unlock(&parentp->lock);
00819 
00820         return EOK;
00821 
00822 error:
00823         fibril_mutex_unlock(&parentp->idx->lock);
00824         fibril_mutex_unlock(&childp->lock);
00825         fibril_mutex_unlock(&childp->idx->lock);
00826         return rc;
00827 }
00828 
00829 int fat_has_children(bool *has_children, fs_node_t *fn)
00830 {
00831         fat_bs_t *bs;
00832         fat_node_t *nodep = FAT_NODE(fn);
00833         unsigned blocks;
00834         block_t *b;
00835         unsigned i, j;
00836         int rc;
00837 
00838         if (nodep->type != FAT_DIRECTORY) {
00839                 *has_children = false;
00840                 return EOK;
00841         }
00842         
00843         fibril_mutex_lock(&nodep->idx->lock);
00844         bs = block_bb_get(nodep->idx->devmap_handle);
00845 
00846         blocks = nodep->size / BPS(bs);
00847 
00848         for (i = 0; i < blocks; i++) {
00849                 fat_dentry_t *d;
00850         
00851                 rc = fat_block_get(&b, bs, nodep, i, BLOCK_FLAGS_NONE);
00852                 if (rc != EOK) {
00853                         fibril_mutex_unlock(&nodep->idx->lock);
00854                         return rc;
00855                 }
00856                 for (j = 0; j < DPS(bs); j++) {
00857                         d = ((fat_dentry_t *)b->data) + j;
00858                         switch (fat_classify_dentry(d)) {
00859                         case FAT_DENTRY_SKIP:
00860                         case FAT_DENTRY_FREE:
00861                                 continue;
00862                         case FAT_DENTRY_LAST:
00863                                 rc = block_put(b);
00864                                 fibril_mutex_unlock(&nodep->idx->lock);
00865                                 *has_children = false;
00866                                 return rc;
00867                         default:
00868                         case FAT_DENTRY_VALID:
00869                                 rc = block_put(b);
00870                                 fibril_mutex_unlock(&nodep->idx->lock);
00871                                 *has_children = true;
00872                                 return rc;
00873                         }
00874                 }
00875                 rc = block_put(b);
00876                 if (rc != EOK) {
00877                         fibril_mutex_unlock(&nodep->idx->lock);
00878                         return rc;      
00879                 }
00880         }
00881 
00882         fibril_mutex_unlock(&nodep->idx->lock);
00883         *has_children = false;
00884         return EOK;
00885 }
00886 
00887 
00888 fs_index_t fat_index_get(fs_node_t *fn)
00889 {
00890         return FAT_NODE(fn)->idx->index;
00891 }
00892 
00893 aoff64_t fat_size_get(fs_node_t *fn)
00894 {
00895         return FAT_NODE(fn)->size;
00896 }
00897 
00898 unsigned fat_lnkcnt_get(fs_node_t *fn)
00899 {
00900         return FAT_NODE(fn)->lnkcnt;
00901 }
00902 
00903 char fat_plb_get_char(unsigned pos)
00904 {
00905         return fat_reg.plb_ro[pos % PLB_SIZE];
00906 }
00907 
00908 bool fat_is_directory(fs_node_t *fn)
00909 {
00910         return FAT_NODE(fn)->type == FAT_DIRECTORY;
00911 }
00912 
00913 bool fat_is_file(fs_node_t *fn)
00914 {
00915         return FAT_NODE(fn)->type == FAT_FILE;
00916 }
00917 
00918 devmap_handle_t fat_device_get(fs_node_t *node)
00919 {
00920         return 0;
00921 }
00922 
00924 libfs_ops_t fat_libfs_ops = {
00925         .root_get = fat_root_get,
00926         .match = fat_match,
00927         .node_get = fat_node_get,
00928         .node_open = fat_node_open,
00929         .node_put = fat_node_put,
00930         .create = fat_create_node,
00931         .destroy = fat_destroy_node,
00932         .link = fat_link,
00933         .unlink = fat_unlink,
00934         .has_children = fat_has_children,
00935         .index_get = fat_index_get,
00936         .size_get = fat_size_get,
00937         .lnkcnt_get = fat_lnkcnt_get,
00938         .plb_get_char = fat_plb_get_char,
00939         .is_directory = fat_is_directory,
00940         .is_file = fat_is_file,
00941         .device_get = fat_device_get
00942 };
00943 
00944 /*
00945  * VFS operations.
00946  */
00947 
00948 void fat_mounted(ipc_callid_t rid, ipc_call_t *request)
00949 {
00950         devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
00951         enum cache_mode cmode;
00952         fat_bs_t *bs;
00953         
00954         /* Accept the mount options */
00955         char *opts;
00956         int rc = async_data_write_accept((void **) &opts, true, 0, 0, 0, NULL);
00957         
00958         if (rc != EOK) {
00959                 async_answer_0(rid, rc);
00960                 return;
00961         }
00962 
00963         /* Check for option enabling write through. */
00964         if (str_cmp(opts, "wtcache") == 0)
00965                 cmode = CACHE_MODE_WT;
00966         else
00967                 cmode = CACHE_MODE_WB;
00968 
00969         free(opts);
00970 
00971         /* initialize libblock */
00972         rc = block_init(devmap_handle, BS_SIZE);
00973         if (rc != EOK) {
00974                 async_answer_0(rid, rc);
00975                 return;
00976         }
00977 
00978         /* prepare the boot block */
00979         rc = block_bb_read(devmap_handle, BS_BLOCK);
00980         if (rc != EOK) {
00981                 block_fini(devmap_handle);
00982                 async_answer_0(rid, rc);
00983                 return;
00984         }
00985 
00986         /* get the buffer with the boot sector */
00987         bs = block_bb_get(devmap_handle);
00988         
00989         if (BPS(bs) != BS_SIZE) {
00990                 block_fini(devmap_handle);
00991                 async_answer_0(rid, ENOTSUP);
00992                 return;
00993         }
00994 
00995         /* Initialize the block cache */
00996         rc = block_cache_init(devmap_handle, BPS(bs), 0 /* XXX */, cmode);
00997         if (rc != EOK) {
00998                 block_fini(devmap_handle);
00999                 async_answer_0(rid, rc);
01000                 return;
01001         }
01002 
01003         /* Do some simple sanity checks on the file system. */
01004         rc = fat_sanity_check(bs, devmap_handle);
01005         if (rc != EOK) {
01006                 (void) block_cache_fini(devmap_handle);
01007                 block_fini(devmap_handle);
01008                 async_answer_0(rid, rc);
01009                 return;
01010         }
01011 
01012         rc = fat_idx_init_by_devmap_handle(devmap_handle);
01013         if (rc != EOK) {
01014                 (void) block_cache_fini(devmap_handle);
01015                 block_fini(devmap_handle);
01016                 async_answer_0(rid, rc);
01017                 return;
01018         }
01019 
01020         /* Initialize the root node. */
01021         fs_node_t *rfn = (fs_node_t *)malloc(sizeof(fs_node_t));
01022         if (!rfn) {
01023                 (void) block_cache_fini(devmap_handle);
01024                 block_fini(devmap_handle);
01025                 fat_idx_fini_by_devmap_handle(devmap_handle);
01026                 async_answer_0(rid, ENOMEM);
01027                 return;
01028         }
01029         fs_node_initialize(rfn);
01030         fat_node_t *rootp = (fat_node_t *)malloc(sizeof(fat_node_t));
01031         if (!rootp) {
01032                 free(rfn);
01033                 (void) block_cache_fini(devmap_handle);
01034                 block_fini(devmap_handle);
01035                 fat_idx_fini_by_devmap_handle(devmap_handle);
01036                 async_answer_0(rid, ENOMEM);
01037                 return;
01038         }
01039         fat_node_initialize(rootp);
01040 
01041         fat_idx_t *ridxp = fat_idx_get_by_pos(devmap_handle, FAT_CLST_ROOTPAR, 0);
01042         if (!ridxp) {
01043                 free(rfn);
01044                 free(rootp);
01045                 (void) block_cache_fini(devmap_handle);
01046                 block_fini(devmap_handle);
01047                 fat_idx_fini_by_devmap_handle(devmap_handle);
01048                 async_answer_0(rid, ENOMEM);
01049                 return;
01050         }
01051         assert(ridxp->index == 0);
01052         /* ridxp->lock held */
01053 
01054         rootp->type = FAT_DIRECTORY;
01055         rootp->firstc = FAT_CLST_ROOT;
01056         rootp->refcnt = 1;
01057         rootp->lnkcnt = 0;      /* FS root is not linked */
01058         rootp->size = RDE(bs) * sizeof(fat_dentry_t);
01059         rootp->idx = ridxp;
01060         ridxp->nodep = rootp;
01061         rootp->bp = rfn;
01062         rfn->data = rootp;
01063         
01064         fibril_mutex_unlock(&ridxp->lock);
01065 
01066         async_answer_3(rid, EOK, ridxp->index, rootp->size, rootp->lnkcnt);
01067 }
01068 
01069 void fat_mount(ipc_callid_t rid, ipc_call_t *request)
01070 {
01071         libfs_mount(&fat_libfs_ops, fat_reg.fs_handle, rid, request);
01072 }
01073 
01074 void fat_unmounted(ipc_callid_t rid, ipc_call_t *request)
01075 {
01076         devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
01077         fs_node_t *fn;
01078         fat_node_t *nodep;
01079         int rc;
01080 
01081         rc = fat_root_get(&fn, devmap_handle);
01082         if (rc != EOK) {
01083                 async_answer_0(rid, rc);
01084                 return;
01085         }
01086         nodep = FAT_NODE(fn);
01087 
01088         /*
01089          * We expect exactly two references on the root node. One for the
01090          * fat_root_get() above and one created in fat_mounted().
01091          */
01092         if (nodep->refcnt != 2) {
01093                 (void) fat_node_put(fn);
01094                 async_answer_0(rid, EBUSY);
01095                 return;
01096         }
01097         
01098         /*
01099          * Put the root node and force it to the FAT free node list.
01100          */
01101         (void) fat_node_put(fn);
01102         (void) fat_node_put(fn);
01103 
01104         /*
01105          * Perform cleanup of the node structures, index structures and
01106          * associated data. Write back this file system's dirty blocks and
01107          * stop using libblock for this instance.
01108          */
01109         (void) fat_node_fini_by_devmap_handle(devmap_handle);
01110         fat_idx_fini_by_devmap_handle(devmap_handle);
01111         (void) block_cache_fini(devmap_handle);
01112         block_fini(devmap_handle);
01113 
01114         async_answer_0(rid, EOK);
01115 }
01116 
01117 void fat_unmount(ipc_callid_t rid, ipc_call_t *request)
01118 {
01119         libfs_unmount(&fat_libfs_ops, rid, request);
01120 }
01121 
01122 void fat_lookup(ipc_callid_t rid, ipc_call_t *request)
01123 {
01124         libfs_lookup(&fat_libfs_ops, fat_reg.fs_handle, rid, request);
01125 }
01126 
01127 void fat_read(ipc_callid_t rid, ipc_call_t *request)
01128 {
01129         devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
01130         fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
01131         aoff64_t pos =
01132             (aoff64_t) MERGE_LOUP32(IPC_GET_ARG3(*request), IPC_GET_ARG4(*request));
01133         fs_node_t *fn;
01134         fat_node_t *nodep;
01135         fat_bs_t *bs;
01136         size_t bytes;
01137         block_t *b;
01138         int rc;
01139 
01140         rc = fat_node_get(&fn, devmap_handle, index);
01141         if (rc != EOK) {
01142                 async_answer_0(rid, rc);
01143                 return;
01144         }
01145         if (!fn) {
01146                 async_answer_0(rid, ENOENT);
01147                 return;
01148         }
01149         nodep = FAT_NODE(fn);
01150 
01151         ipc_callid_t callid;
01152         size_t len;
01153         if (!async_data_read_receive(&callid, &len)) {
01154                 fat_node_put(fn);
01155                 async_answer_0(callid, EINVAL);
01156                 async_answer_0(rid, EINVAL);
01157                 return;
01158         }
01159 
01160         bs = block_bb_get(devmap_handle);
01161 
01162         if (nodep->type == FAT_FILE) {
01163                 /*
01164                  * Our strategy for regular file reads is to read one block at
01165                  * most and make use of the possibility to return less data than
01166                  * requested. This keeps the code very simple.
01167                  */
01168                 if (pos >= nodep->size) {
01169                         /* reading beyond the EOF */
01170                         bytes = 0;
01171                         (void) async_data_read_finalize(callid, NULL, 0);
01172                 } else {
01173                         bytes = min(len, BPS(bs) - pos % BPS(bs));
01174                         bytes = min(bytes, nodep->size - pos);
01175                         rc = fat_block_get(&b, bs, nodep, pos / BPS(bs),
01176                             BLOCK_FLAGS_NONE);
01177                         if (rc != EOK) {
01178                                 fat_node_put(fn);
01179                                 async_answer_0(callid, rc);
01180                                 async_answer_0(rid, rc);
01181                                 return;
01182                         }
01183                         (void) async_data_read_finalize(callid,
01184                             b->data + pos % BPS(bs), bytes);
01185                         rc = block_put(b);
01186                         if (rc != EOK) {
01187                                 fat_node_put(fn);
01188                                 async_answer_0(rid, rc);
01189                                 return;
01190                         }
01191                 }
01192         } else {
01193                 unsigned bnum;
01194                 aoff64_t spos = pos;
01195                 char name[FAT_NAME_LEN + 1 + FAT_EXT_LEN + 1];
01196                 fat_dentry_t *d;
01197 
01198                 assert(nodep->type == FAT_DIRECTORY);
01199                 assert(nodep->size % BPS(bs) == 0);
01200                 assert(BPS(bs) % sizeof(fat_dentry_t) == 0);
01201 
01202                 /*
01203                  * Our strategy for readdir() is to use the position pointer as
01204                  * an index into the array of all dentries. On entry, it points
01205                  * to the first unread dentry. If we skip any dentries, we bump
01206                  * the position pointer accordingly.
01207                  */
01208                 bnum = (pos * sizeof(fat_dentry_t)) / BPS(bs);
01209                 while (bnum < nodep->size / BPS(bs)) {
01210                         aoff64_t o;
01211 
01212                         rc = fat_block_get(&b, bs, nodep, bnum,
01213                             BLOCK_FLAGS_NONE);
01214                         if (rc != EOK)
01215                                 goto err;
01216                         for (o = pos % (BPS(bs) / sizeof(fat_dentry_t));
01217                             o < BPS(bs) / sizeof(fat_dentry_t);
01218                             o++, pos++) {
01219                                 d = ((fat_dentry_t *)b->data) + o;
01220                                 switch (fat_classify_dentry(d)) {
01221                                 case FAT_DENTRY_SKIP:
01222                                 case FAT_DENTRY_FREE:
01223                                         continue;
01224                                 case FAT_DENTRY_LAST:
01225                                         rc = block_put(b);
01226                                         if (rc != EOK)
01227                                                 goto err;
01228                                         goto miss;
01229                                 default:
01230                                 case FAT_DENTRY_VALID:
01231                                         fat_dentry_name_get(d, name);
01232                                         rc = block_put(b);
01233                                         if (rc != EOK)
01234                                                 goto err;
01235                                         goto hit;
01236                                 }
01237                         }
01238                         rc = block_put(b);
01239                         if (rc != EOK)
01240                                 goto err;
01241                         bnum++;
01242                 }
01243 miss:
01244                 rc = fat_node_put(fn);
01245                 async_answer_0(callid, rc != EOK ? rc : ENOENT);
01246                 async_answer_1(rid, rc != EOK ? rc : ENOENT, 0);
01247                 return;
01248 
01249 err:
01250                 (void) fat_node_put(fn);
01251                 async_answer_0(callid, rc);
01252                 async_answer_0(rid, rc);
01253                 return;
01254 
01255 hit:
01256                 (void) async_data_read_finalize(callid, name, str_size(name) + 1);
01257                 bytes = (pos - spos) + 1;
01258         }
01259 
01260         rc = fat_node_put(fn);
01261         async_answer_1(rid, rc, (sysarg_t)bytes);
01262 }
01263 
01264 void fat_write(ipc_callid_t rid, ipc_call_t *request)
01265 {
01266         devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
01267         fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
01268         aoff64_t pos =
01269             (aoff64_t) MERGE_LOUP32(IPC_GET_ARG3(*request), IPC_GET_ARG4(*request));
01270         fs_node_t *fn;
01271         fat_node_t *nodep;
01272         fat_bs_t *bs;
01273         size_t bytes, size;
01274         block_t *b;
01275         aoff64_t boundary;
01276         int flags = BLOCK_FLAGS_NONE;
01277         int rc;
01278         
01279         rc = fat_node_get(&fn, devmap_handle, index);
01280         if (rc != EOK) {
01281                 async_answer_0(rid, rc);
01282                 return;
01283         }
01284         if (!fn) {
01285                 async_answer_0(rid, ENOENT);
01286                 return;
01287         }
01288         nodep = FAT_NODE(fn);
01289         
01290         ipc_callid_t callid;
01291         size_t len;
01292         if (!async_data_write_receive(&callid, &len)) {
01293                 (void) fat_node_put(fn);
01294                 async_answer_0(callid, EINVAL);
01295                 async_answer_0(rid, EINVAL);
01296                 return;
01297         }
01298 
01299         bs = block_bb_get(devmap_handle);
01300 
01301         /*
01302          * In all scenarios, we will attempt to write out only one block worth
01303          * of data at maximum. There might be some more efficient approaches,
01304          * but this one greatly simplifies fat_write(). Note that we can afford
01305          * to do this because the client must be ready to handle the return
01306          * value signalizing a smaller number of bytes written. 
01307          */ 
01308         bytes = min(len, BPS(bs) - pos % BPS(bs));
01309         if (bytes == BPS(bs))
01310                 flags |= BLOCK_FLAGS_NOREAD;
01311         
01312         boundary = ROUND_UP(nodep->size, BPC(bs));
01313         if (pos < boundary) {
01314                 /*
01315                  * This is the easier case - we are either overwriting already
01316                  * existing contents or writing behind the EOF, but still within
01317                  * the limits of the last cluster. The node size may grow to the
01318                  * next block size boundary.
01319                  */
01320                 rc = fat_fill_gap(bs, nodep, FAT_CLST_RES0, pos);
01321                 if (rc != EOK) {
01322                         (void) fat_node_put(fn);
01323                         async_answer_0(callid, rc);
01324                         async_answer_0(rid, rc);
01325                         return;
01326                 }
01327                 rc = fat_block_get(&b, bs, nodep, pos / BPS(bs), flags);
01328                 if (rc != EOK) {
01329                         (void) fat_node_put(fn);
01330                         async_answer_0(callid, rc);
01331                         async_answer_0(rid, rc);
01332                         return;
01333                 }
01334                 (void) async_data_write_finalize(callid,
01335                     b->data + pos % BPS(bs), bytes);
01336                 b->dirty = true;                /* need to sync block */
01337                 rc = block_put(b);
01338                 if (rc != EOK) {
01339                         (void) fat_node_put(fn);
01340                         async_answer_0(rid, rc);
01341                         return;
01342                 }
01343                 if (pos + bytes > nodep->size) {
01344                         nodep->size = pos + bytes;
01345                         nodep->dirty = true;    /* need to sync node */
01346                 }
01347                 size = nodep->size;
01348                 rc = fat_node_put(fn);
01349                 async_answer_2(rid, rc, bytes, nodep->size);
01350                 return;
01351         } else {
01352                 /*
01353                  * This is the more difficult case. We must allocate new
01354                  * clusters for the node and zero them out.
01355                  */
01356                 unsigned nclsts;
01357                 fat_cluster_t mcl, lcl; 
01358  
01359                 nclsts = (ROUND_UP(pos + bytes, BPC(bs)) - boundary) / BPC(bs);
01360                 /* create an independent chain of nclsts clusters in all FATs */
01361                 rc = fat_alloc_clusters(bs, devmap_handle, nclsts, &mcl, &lcl);
01362                 if (rc != EOK) {
01363                         /* could not allocate a chain of nclsts clusters */
01364                         (void) fat_node_put(fn);
01365                         async_answer_0(callid, rc);
01366                         async_answer_0(rid, rc);
01367                         return;
01368                 }
01369                 /* zero fill any gaps */
01370                 rc = fat_fill_gap(bs, nodep, mcl, pos);
01371                 if (rc != EOK) {
01372                         (void) fat_free_clusters(bs, devmap_handle, mcl);
01373                         (void) fat_node_put(fn);
01374                         async_answer_0(callid, rc);
01375                         async_answer_0(rid, rc);
01376                         return;
01377                 }
01378                 rc = _fat_block_get(&b, bs, devmap_handle, lcl, NULL,
01379                     (pos / BPS(bs)) % SPC(bs), flags);
01380                 if (rc != EOK) {
01381                         (void) fat_free_clusters(bs, devmap_handle, mcl);
01382                         (void) fat_node_put(fn);
01383                         async_answer_0(callid, rc);
01384                         async_answer_0(rid, rc);
01385                         return;
01386                 }
01387                 (void) async_data_write_finalize(callid,
01388                     b->data + pos % BPS(bs), bytes);
01389                 b->dirty = true;                /* need to sync block */
01390                 rc = block_put(b);
01391                 if (rc != EOK) {
01392                         (void) fat_free_clusters(bs, devmap_handle, mcl);
01393                         (void) fat_node_put(fn);
01394                         async_answer_0(rid, rc);
01395                         return;
01396                 }
01397                 /*
01398                  * Append the cluster chain starting in mcl to the end of the
01399                  * node's cluster chain.
01400                  */
01401                 rc = fat_append_clusters(bs, nodep, mcl, lcl);
01402                 if (rc != EOK) {
01403                         (void) fat_free_clusters(bs, devmap_handle, mcl);
01404                         (void) fat_node_put(fn);
01405                         async_answer_0(rid, rc);
01406                         return;
01407                 }
01408                 nodep->size = size = pos + bytes;
01409                 nodep->dirty = true;            /* need to sync node */
01410                 rc = fat_node_put(fn);
01411                 async_answer_2(rid, rc, bytes, size);
01412                 return;
01413         }
01414 }
01415 
01416 void fat_truncate(ipc_callid_t rid, ipc_call_t *request)
01417 {
01418         devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
01419         fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
01420         aoff64_t size =
01421             (aoff64_t) MERGE_LOUP32(IPC_GET_ARG3(*request), IPC_GET_ARG4(*request));
01422         fs_node_t *fn;
01423         fat_node_t *nodep;
01424         fat_bs_t *bs;
01425         int rc;
01426 
01427         rc = fat_node_get(&fn, devmap_handle, index);
01428         if (rc != EOK) {
01429                 async_answer_0(rid, rc);
01430                 return;
01431         }
01432         if (!fn) {
01433                 async_answer_0(rid, ENOENT);
01434                 return;
01435         }
01436         nodep = FAT_NODE(fn);
01437 
01438         bs = block_bb_get(devmap_handle);
01439 
01440         if (nodep->size == size) {
01441                 rc = EOK;
01442         } else if (nodep->size < size) {
01443                 /*
01444                  * The standard says we have the freedom to grow the node.
01445                  * For now, we simply return an error.
01446                  */
01447                 rc = EINVAL;
01448         } else if (ROUND_UP(nodep->size, BPC(bs)) == ROUND_UP(size, BPC(bs))) {
01449                 /*
01450                  * The node will be shrunk, but no clusters will be deallocated.
01451                  */
01452                 nodep->size = size;
01453                 nodep->dirty = true;            /* need to sync node */
01454                 rc = EOK;       
01455         } else {
01456                 /*
01457                  * The node will be shrunk, clusters will be deallocated.
01458                  */
01459                 if (size == 0) {
01460                         rc = fat_chop_clusters(bs, nodep, FAT_CLST_RES0);
01461                         if (rc != EOK)
01462                                 goto out;
01463                 } else {
01464                         fat_cluster_t lastc;
01465                         rc = fat_cluster_walk(bs, devmap_handle, nodep->firstc,
01466                             &lastc, NULL, (size - 1) / BPC(bs));
01467                         if (rc != EOK)
01468                                 goto out;
01469                         rc = fat_chop_clusters(bs, nodep, lastc);
01470                         if (rc != EOK)
01471                                 goto out;
01472                 }
01473                 nodep->size = size;
01474                 nodep->dirty = true;            /* need to sync node */
01475                 rc = EOK;       
01476         }
01477 out:
01478         fat_node_put(fn);
01479         async_answer_0(rid, rc);
01480         return;
01481 }
01482 
01483 void fat_close(ipc_callid_t rid, ipc_call_t *request)
01484 {
01485         async_answer_0(rid, EOK);
01486 }
01487 
01488 void fat_destroy(ipc_callid_t rid, ipc_call_t *request)
01489 {
01490         devmap_handle_t devmap_handle = (devmap_handle_t)IPC_GET_ARG1(*request);
01491         fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request);
01492         fs_node_t *fn;
01493         fat_node_t *nodep;
01494         int rc;
01495 
01496         rc = fat_node_get(&fn, devmap_handle, index);
01497         if (rc != EOK) {
01498                 async_answer_0(rid, rc);
01499                 return;
01500         }
01501         if (!fn) {
01502                 async_answer_0(rid, ENOENT);
01503                 return;
01504         }
01505 
01506         nodep = FAT_NODE(fn);
01507         /*
01508          * We should have exactly two references. One for the above
01509          * call to fat_node_get() and one from fat_unlink().
01510          */
01511         assert(nodep->refcnt == 2);
01512 
01513         rc = fat_destroy_node(fn);
01514         async_answer_0(rid, rc);
01515 }
01516 
01517 void fat_open_node(ipc_callid_t rid, ipc_call_t *request)
01518 {
01519         libfs_open_node(&fat_libfs_ops, fat_reg.fs_handle, rid, request);
01520 }
01521 
01522 void fat_stat(ipc_callid_t rid, ipc_call_t *request)
01523 {
01524         libfs_stat(&fat_libfs_ops, fat_reg.fs_handle, rid, request);
01525 }
01526 
01527 void fat_sync(ipc_callid_t rid, ipc_call_t *request)
01528 {
01529         devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
01530         fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
01531         
01532         fs_node_t *fn;
01533         int rc = fat_node_get(&fn, devmap_handle, index);
01534         if (rc != EOK) {
01535                 async_answer_0(rid, rc);
01536                 return;
01537         }
01538         if (!fn) {
01539                 async_answer_0(rid, ENOENT);
01540                 return;
01541         }
01542         
01543         fat_node_t *nodep = FAT_NODE(fn);
01544         
01545         nodep->dirty = true;
01546         rc = fat_node_sync(nodep);
01547         
01548         fat_node_put(fn);
01549         async_answer_0(rid, rc);
01550 }
01551 

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