Subversion Repositories HelenOS

Rev

Rev 2890 | Rev 2893 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  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    fat_ops.c
  35.  * @brief   Implementation of VFS operations for the FAT file system server.
  36.  */
  37.  
  38. #include "fat.h"
  39. #include "../../vfs/vfs.h"
  40. #include <libfs.h>
  41. #include <ipc/ipc.h>
  42. #include <async.h>
  43. #include <errno.h>
  44. #include <string.h>
  45. #include <byteorder.h>
  46. #include <libadt/hash_table.h>
  47. #include <libadt/list.h>
  48. #include <assert.h>
  49. #include <futex.h>
  50.  
  51. #define BS_BLOCK        0
  52.  
  53. #define FIN_KEY_DEV_HANDLE  0
  54. #define FIN_KEY_INDEX       1
  55.  
  56. /** Hash table of FAT in-core nodes. */
  57. hash_table_t fin_hash;
  58.  
  59. /** List of free FAT in-core nodes. */
  60. link_t ffn_head;
  61.  
  62. #define FAT_NAME_LEN        8
  63. #define FAT_EXT_LEN     3
  64.  
  65. #define FAT_PAD         ' '
  66.  
  67. #define FAT_DENTRY_UNUSED   0x00
  68. #define FAT_DENTRY_E5_ESC   0x05
  69. #define FAT_DENTRY_DOT      0x2e
  70. #define FAT_DENTRY_ERASED   0xe5
  71.  
  72. static void dentry_name_canonify(fat_dentry_t *d, char *buf)
  73. {
  74.     int i;
  75.  
  76.     for (i = 0; i < FAT_NAME_LEN; i++) {
  77.         if (d->name[i] == FAT_PAD) {
  78.             buf++;
  79.             break;
  80.         }
  81.         if (d->name[i] == FAT_DENTRY_E5_ESC)
  82.             *buf++ = 0xe5;
  83.         else
  84.             *buf++ = d->name[i];
  85.     }
  86.     if (d->ext[0] != FAT_PAD)
  87.         *buf++ = '.';
  88.     for (i = 0; i < FAT_EXT_LEN; i++) {
  89.         if (d->ext[i] == FAT_PAD) {
  90.             *buf = '\0';
  91.             return;
  92.         }
  93.         if (d->ext[i] == FAT_DENTRY_E5_ESC)
  94.             *buf++ = 0xe5;
  95.         else
  96.             *buf++ = d->ext[i];
  97.     }
  98. }
  99.  
  100. /* TODO and also move somewhere else */
  101. typedef struct {
  102.     void *data;
  103. } block_t;
  104.  
  105. static block_t *block_get(dev_handle_t dev_handle, off_t offset)
  106. {
  107.     return NULL;    /* TODO */
  108. }
  109.  
  110. static void block_put(block_t *block)
  111. {
  112.     /* TODO */
  113. }
  114.  
  115. #define FAT_BS(b)       ((fat_bs_t *)((b)->data))
  116.  
  117. #define FAT_CLST_RES0   0x0000
  118. #define FAT_CLST_RES1   0x0001  /* internally used to mark root directory */
  119. #define FAT_CLST_FIRST  0x0002
  120. #define FAT_CLST_BAD    0xfff7
  121. #define FAT_CLST_LAST1  0xfff8
  122. #define FAT_CLST_LAST8  0xffff
  123.  
  124. #define fat_block_get(np, off) \
  125.     _fat_block_get((np)->idx->dev_handle, (np)->firstc, (off))
  126.  
  127. static block_t *
  128. _fat_block_get(dev_handle_t dev_handle, fat_cluster_t fc, off_t offset)
  129. {
  130.     block_t *bb;
  131.     block_t *b;
  132.     unsigned bps;
  133.     unsigned spc;
  134.     unsigned rscnt;     /* block address of the first FAT */
  135.     unsigned fatcnt;
  136.     unsigned rde;
  137.     unsigned rds;       /* root directory size */
  138.     unsigned sf;
  139.     unsigned ssa;       /* size of the system area */
  140.     unsigned clusters;
  141.     fat_cluster_t clst = fc;
  142.     unsigned i;
  143.  
  144.     bb = block_get(dev_handle, BS_BLOCK);
  145.     bps = uint16_t_le2host(FAT_BS(bb)->bps);
  146.     spc = FAT_BS(bb)->spc;
  147.     rscnt = uint16_t_le2host(FAT_BS(bb)->rscnt);
  148.     fatcnt = FAT_BS(bb)->fatcnt;
  149.     rde = uint16_t_le2host(FAT_BS(bb)->root_ent_max);
  150.     sf = uint16_t_le2host(FAT_BS(bb)->sec_per_fat);
  151.     block_put(bb);
  152.  
  153.     rds = (sizeof(fat_dentry_t) * rde) / bps;
  154.     rds += ((sizeof(fat_dentry_t) * rde) % bps != 0);
  155.     ssa = rscnt + fatcnt * sf + rds;
  156.  
  157.     if (fc == FAT_CLST_RES1) {
  158.         /* root directory special case */
  159.         assert(offset < rds);
  160.         b = block_get(dev_handle, rscnt + fatcnt * sf + offset);
  161.         return b;
  162.     }
  163.  
  164.     clusters = offset / spc;
  165.     for (i = 0; i < clusters; i++) {
  166.         unsigned fsec;  /* sector offset relative to FAT1 */
  167.         unsigned fidx;  /* FAT1 entry index */
  168.  
  169.         assert(clst >= FAT_CLST_FIRST && clst < FAT_CLST_BAD);
  170.         fsec = (clst * sizeof(fat_cluster_t)) / bps;
  171.         fidx = clst % (bps / sizeof(fat_cluster_t));
  172.         /* read FAT1 */
  173.         b = block_get(dev_handle, rscnt + fsec);
  174.         clst = uint16_t_le2host(((fat_cluster_t *)b->data)[fidx]);
  175.         assert(clst != FAT_CLST_BAD);
  176.         assert(clst < FAT_CLST_LAST1);
  177.         block_put(b);
  178.     }
  179.  
  180.     b = block_get(dev_handle, ssa + (clst - FAT_CLST_FIRST) * spc +
  181.         offset % spc);
  182.  
  183.     return b;
  184. }
  185.  
  186. static void fat_node_initialize(fat_node_t *node)
  187. {
  188.     node->idx = NULL;
  189.     node->type = 0;
  190.     link_initialize(&node->fin_link);
  191.     link_initialize(&node->ffn_link);
  192.     node->size = 0;
  193.     node->lnkcnt = 0;
  194.     node->refcnt = 0;
  195.     node->dirty = false;
  196. }
  197.  
  198. static uint16_t fat_bps_get(dev_handle_t dev_handle)
  199. {
  200.     block_t *bb;
  201.     uint16_t bps;
  202.    
  203.     bb = block_get(dev_handle, BS_BLOCK);
  204.     assert(bb != NULL);
  205.     bps = uint16_t_le2host(FAT_BS(bb)->bps);
  206.     block_put(bb);
  207.  
  208.     return bps;
  209. }
  210.  
  211. typedef enum {
  212.     FAT_DENTRY_SKIP,
  213.     FAT_DENTRY_LAST,
  214.     FAT_DENTRY_VALID
  215. } fat_dentry_clsf_t;
  216.  
  217. static fat_dentry_clsf_t fat_classify_dentry(fat_dentry_t *d)
  218. {
  219.     if (d->attr & FAT_ATTR_VOLLABEL) {
  220.         /* volume label entry */
  221.         return FAT_DENTRY_SKIP;
  222.     }
  223.     if (d->name[0] == FAT_DENTRY_ERASED) {
  224.         /* not-currently-used entry */
  225.         return FAT_DENTRY_SKIP;
  226.     }
  227.     if (d->name[0] == FAT_DENTRY_UNUSED) {
  228.         /* never used entry */
  229.         return FAT_DENTRY_LAST;
  230.     }
  231.     if (d->name[0] == FAT_DENTRY_DOT) {
  232.         /*
  233.          * Most likely '.' or '..'.
  234.          * It cannot occur in a regular file name.
  235.          */
  236.         return FAT_DENTRY_SKIP;
  237.     }
  238.     return FAT_DENTRY_VALID;
  239. }
  240.  
  241. static void fat_sync_node(fat_node_t *node)
  242. {
  243.     /* TODO */
  244. }
  245.  
  246. /** Instantiate a FAT in-core node. */
  247. static void *fat_node_get(dev_handle_t dev_handle, fs_index_t index)
  248. {
  249.     fat_idx_t *idx;
  250.     block_t *b;
  251.     fat_dentry_t *d;
  252.     fat_node_t *nodep;
  253.     unsigned bps;
  254.     unsigned dps;
  255.  
  256.     idx = fat_idx_get_by_index(dev_handle, index);
  257.     if (!idx)
  258.         return NULL;
  259.  
  260.     if (idx->nodep) {
  261.         /*
  262.          * We are lucky.
  263.          * The node is already instantiated in memory.
  264.          */
  265.         idx->nodep->refcnt++;
  266.         return idx->nodep;
  267.     }
  268.  
  269.     /*
  270.      * We must instantiate the node from the file system.
  271.      */
  272.    
  273.     assert(idx->pfc);
  274.  
  275.     nodep = (fat_node_t *)malloc(sizeof(fat_node_t));
  276.     if (!nodep)
  277.         return NULL;
  278.     fat_node_initialize(nodep);
  279.  
  280.     bps = fat_bps_get(dev_handle);
  281.     dps = bps / sizeof(fat_dentry_t);
  282.  
  283.     b = _fat_block_get(dev_handle, idx->pfc,
  284.         (idx->pdi * sizeof(fat_dentry_t)) / bps);
  285.  
  286.     assert(b);
  287.  
  288.     d = ((fat_dentry_t *)b->data) + (idx->pdi % dps);
  289.     /* XXX */
  290. }
  291.  
  292. static void fat_node_put(void *node)
  293. {
  294.     /* TODO */
  295. }
  296.  
  297. static void *fat_create(int flags)
  298. {
  299.     return NULL;    /* not supported at the moment */
  300. }
  301.  
  302. static int fat_destroy(void *node)
  303. {
  304.     return ENOTSUP; /* not supported at the moment */
  305. }
  306.  
  307. static bool fat_link(void *prnt, void *chld, const char *name)
  308. {
  309.     return false;   /* not supported at the moment */
  310. }
  311.  
  312. static int fat_unlink(void *prnt, void *chld)
  313. {
  314.     return ENOTSUP; /* not supported at the moment */
  315. }
  316.  
  317. static void *fat_match(void *prnt, const char *component)
  318. {
  319.     fat_node_t *parentp = (fat_node_t *)prnt;
  320.     char name[FAT_NAME_LEN + 1 + FAT_EXT_LEN + 1];
  321.     unsigned i, j;
  322.     unsigned bps;       /* bytes per sector */
  323.     unsigned dps;       /* dentries per sector */
  324.     unsigned blocks;
  325.     fat_dentry_t *d;
  326.     block_t *b;
  327.  
  328.     bps = fat_bps_get(parentp->idx->dev_handle);
  329.     dps = bps / sizeof(fat_dentry_t);
  330.     blocks = parentp->size / bps + (parentp->size % bps != 0);
  331.     for (i = 0; i < blocks; i++) {
  332.         unsigned dentries;
  333.        
  334.         b = fat_block_get(parentp, i);
  335.         dentries = (i == blocks - 1) ?
  336.             parentp->size % sizeof(fat_dentry_t) :
  337.             dps;
  338.         for (j = 0; j < dentries; j++) {
  339.             d = ((fat_dentry_t *)b->data) + j;
  340.             switch (fat_classify_dentry(d)) {
  341.             case FAT_DENTRY_SKIP:
  342.                 continue;
  343.             case FAT_DENTRY_LAST:
  344.                 block_put(b);
  345.                 return NULL;
  346.             default:
  347.             case FAT_DENTRY_VALID:
  348.                 dentry_name_canonify(d, name);
  349.                 break;
  350.             }
  351.             if (strcmp(name, component) == 0) {
  352.                 /* hit */
  353.                 fat_idx_t *idx = fat_idx_get_by_pos(
  354.                     parentp->idx->dev_handle, parentp->firstc,
  355.                     i * dps + j);
  356.                 if (!idx) {
  357.                     /*
  358.                      * Can happen if memory is low or if we
  359.                      * run out of 32-bit indices.
  360.                      */
  361.                     block_put(b);
  362.                     return NULL;
  363.                 }
  364.                 void *node = fat_node_get(idx->dev_handle,
  365.                     idx->index);
  366.                 block_put(b);
  367.                 return node;
  368.             }
  369.         }
  370.         block_put(b);
  371.     }
  372.  
  373.     return NULL;
  374. }
  375.  
  376. static fs_index_t fat_index_get(void *node)
  377. {
  378.     fat_node_t *fnodep = (fat_node_t *)node;
  379.     if (!fnodep)
  380.         return 0;
  381.     return fnodep->idx->index;
  382. }
  383.  
  384. static size_t fat_size_get(void *node)
  385. {
  386.     return ((fat_node_t *)node)->size;
  387. }
  388.  
  389. static unsigned fat_lnkcnt_get(void *node)
  390. {
  391.     return ((fat_node_t *)node)->lnkcnt;
  392. }
  393.  
  394. static bool fat_has_children(void *node)
  395. {
  396.     fat_node_t *nodep = (fat_node_t *)node;
  397.     unsigned bps;
  398.     unsigned dps;
  399.     unsigned blocks;
  400.     block_t *b;
  401.     unsigned i, j;
  402.  
  403.     if (nodep->type != FAT_DIRECTORY)
  404.         return false;
  405.  
  406.     bps = fat_bps_get(nodep->idx->dev_handle);
  407.     dps = bps / sizeof(fat_dentry_t);
  408.  
  409.     blocks = nodep->size / bps + (nodep->size % bps != 0);
  410.  
  411.     for (i = 0; i < blocks; i++) {
  412.         unsigned dentries;
  413.         fat_dentry_t *d;
  414.    
  415.         b = fat_block_get(nodep, i);
  416.         dentries = (i == blocks - 1) ?
  417.             nodep->size % sizeof(fat_dentry_t) :
  418.             dps;
  419.         for (j = 0; j < dentries; j++) {
  420.             d = ((fat_dentry_t *)b->data) + j;
  421.             switch (fat_classify_dentry(d)) {
  422.             case FAT_DENTRY_SKIP:
  423.                 continue;
  424.             case FAT_DENTRY_LAST:
  425.                 block_put(b);
  426.                 return false;
  427.             default:
  428.             case FAT_DENTRY_VALID:
  429.                 block_put(b);
  430.                 return true;
  431.             }
  432.             block_put(b);
  433.             return true;
  434.         }
  435.         block_put(b);
  436.     }
  437.  
  438.     return false;
  439. }
  440.  
  441. static void *fat_root_get(dev_handle_t dev_handle)
  442. {
  443.     return fat_node_get(dev_handle, 0); /* TODO */
  444. }
  445.  
  446. static char fat_plb_get_char(unsigned pos)
  447. {
  448.     return fat_reg.plb_ro[pos % PLB_SIZE];
  449. }
  450.  
  451. static bool fat_is_directory(void *node)
  452. {
  453.     return ((fat_node_t *)node)->type == FAT_DIRECTORY;
  454. }
  455.  
  456. static bool fat_is_file(void *node)
  457. {
  458.     return ((fat_node_t *)node)->type == FAT_FILE;
  459. }
  460.  
  461. /** libfs operations */
  462. libfs_ops_t fat_libfs_ops = {
  463.     .match = fat_match,
  464.     .node_get = fat_node_get,
  465.     .node_put = fat_node_put,
  466.     .create = fat_create,
  467.     .destroy = fat_destroy,
  468.     .link = fat_link,
  469.     .unlink = fat_unlink,
  470.     .index_get = fat_index_get,
  471.     .size_get = fat_size_get,
  472.     .lnkcnt_get = fat_lnkcnt_get,
  473.     .has_children = fat_has_children,
  474.     .root_get = fat_root_get,
  475.     .plb_get_char = fat_plb_get_char,
  476.     .is_directory = fat_is_directory,
  477.     .is_file = fat_is_file
  478. };
  479.  
  480. void fat_lookup(ipc_callid_t rid, ipc_call_t *request)
  481. {
  482.     libfs_lookup(&fat_libfs_ops, fat_reg.fs_handle, rid, request);
  483. }
  484.  
  485. /**
  486.  * @}
  487.  */
  488.