Subversion Repositories HelenOS

Rev

Rev 2863 | Rev 2876 | 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. static fat_idx_t *fat_idx_map(fat_cluster_t pfc, unsigned pdi)
  116. {
  117.     return NULL;    /* TODO */
  118. }
  119.  
  120. #define FAT_BS(b)       ((fat_bs_t *)((b)->data))
  121.  
  122. #define FAT_CLST_RES0   0x0000
  123. #define FAT_CLST_RES1   0x0001  /* internally used to mark root directory */
  124. #define FAT_CLST_FIRST  0x0002
  125. #define FAT_CLST_BAD    0xfff7
  126. #define FAT_CLST_LAST1  0xfff8
  127. #define FAT_CLST_LAST8  0xffff
  128.  
  129. static block_t *fat_block_get(fat_node_t *nodep, off_t offset)
  130. {
  131.     block_t *bb;
  132.     block_t *b;
  133.     unsigned bps;
  134.     unsigned spc;
  135.     unsigned rscnt;     /* block address of the first FAT */
  136.     unsigned fatcnt;
  137.     unsigned rde;
  138.     unsigned rds;       /* root directory size */
  139.     unsigned sf;
  140.     unsigned ssa;       /* size of the system area */
  141.     unsigned clusters;
  142.     fat_cluster_t clst = nodep->firstc;
  143.     unsigned i;
  144.  
  145.     bb = block_get(nodep->idx->dev_handle, BS_BLOCK);
  146.     bps = uint16_t_le2host(FAT_BS(bb)->bps);
  147.     spc = FAT_BS(bb)->spc;
  148.     rscnt = uint16_t_le2host(FAT_BS(bb)->rscnt);
  149.     fatcnt = FAT_BS(bb)->fatcnt;
  150.     rde = uint16_t_le2host(FAT_BS(bb)->root_ent_max);
  151.     sf = uint16_t_le2host(FAT_BS(bb)->sec_per_fat);
  152.     block_put(bb);
  153.  
  154.     rds = (sizeof(fat_dentry_t) * rde) / bps;
  155.     rds += ((sizeof(fat_dentry_t) * rde) % bps != 0);
  156.     ssa = rscnt + fatcnt * sf + rds;
  157.  
  158.     if (nodep->idx->index == FAT_CLST_RES1) {
  159.         /* root directory special case */
  160.         assert(offset < rds);
  161.         b = block_get(nodep->idx->dev_handle,
  162.             rscnt + fatcnt * sf + offset);
  163.         return b;
  164.     }
  165.  
  166.     clusters = offset / spc;
  167.     for (i = 0; i < clusters; i++) {
  168.         unsigned fsec;  /* sector offset relative to FAT1 */
  169.         unsigned fidx;  /* FAT1 entry index */
  170.  
  171.         assert(clst >= FAT_CLST_FIRST && clst < FAT_CLST_BAD);
  172.         fsec = (clst * sizeof(fat_cluster_t)) / bps;
  173.         fidx = clst % (bps / sizeof(fat_cluster_t));
  174.         /* read FAT1 */
  175.         b = block_get(nodep->idx->dev_handle, rscnt + fsec);
  176.         clst = uint16_t_le2host(((fat_cluster_t *)b->data)[fidx]);
  177.         assert(clst != FAT_CLST_BAD);
  178.         assert(clst < FAT_CLST_LAST1);
  179.         block_put(b);
  180.     }
  181.  
  182.     b = block_get(nodep->idx->dev_handle, ssa +
  183.         (clst - FAT_CLST_FIRST) * spc + offset % spc);
  184.  
  185.     return b;
  186. }
  187.  
  188. static void fat_node_initialize(fat_node_t *node)
  189. {
  190.     node->idx = NULL;
  191.     node->type = 0;
  192.     link_initialize(&node->fin_link);
  193.     link_initialize(&node->ffn_link);
  194.     node->size = 0;
  195.     node->lnkcnt = 0;
  196.     node->refcnt = 0;
  197.     node->dirty = false;
  198. }
  199.  
  200. static uint16_t fat_bps_get(dev_handle_t dev_handle)
  201. {
  202.     block_t *bb;
  203.     uint16_t bps;
  204.    
  205.     bb = block_get(dev_handle, BS_BLOCK);
  206.     assert(bb != NULL);
  207.     bps = uint16_t_le2host(FAT_BS(bb)->bps);
  208.     block_put(bb);
  209.  
  210.     return bps;
  211. }
  212.  
  213. typedef enum {
  214.     FAT_DENTRY_SKIP,
  215.     FAT_DENTRY_LAST,
  216.     FAT_DENTRY_VALID
  217. } fat_dentry_clsf_t;
  218.  
  219. static fat_dentry_clsf_t fat_classify_dentry(fat_dentry_t *d)
  220. {
  221.     if (d->attr & FAT_ATTR_VOLLABEL) {
  222.         /* volume label entry */
  223.         return FAT_DENTRY_SKIP;
  224.     }
  225.     if (d->name[0] == FAT_DENTRY_ERASED) {
  226.         /* not-currently-used entry */
  227.         return FAT_DENTRY_SKIP;
  228.     }
  229.     if (d->name[0] == FAT_DENTRY_UNUSED) {
  230.         /* never used entry */
  231.         return FAT_DENTRY_LAST;
  232.     }
  233.     if (d->name[0] == FAT_DENTRY_DOT) {
  234.         /*
  235.          * Most likely '.' or '..'.
  236.          * It cannot occur in a regular file name.
  237.          */
  238.         return FAT_DENTRY_SKIP;
  239.     }
  240.     return FAT_DENTRY_VALID;
  241. }
  242.  
  243. static void fat_sync_node(fat_node_t *node)
  244. {
  245.     /* TODO */
  246. }
  247.  
  248. /** Instantiate a FAT in-core node. */
  249. static void *
  250. fat_node_get(dev_handle_t dev_handle, fs_index_t index)
  251. {
  252.     return NULL;    /* TODO */
  253. }
  254.  
  255. static void fat_node_put(void *node)
  256. {
  257.     /* TODO */
  258. }
  259.  
  260. static void *fat_create(int flags)
  261. {
  262.     return NULL;    /* not supported at the moment */
  263. }
  264.  
  265. static int fat_destroy(void *node)
  266. {
  267.     return ENOTSUP; /* not supported at the moment */
  268. }
  269.  
  270. static bool fat_link(void *prnt, void *chld, const char *name)
  271. {
  272.     return false;   /* not supported at the moment */
  273. }
  274.  
  275. static int fat_unlink(void *prnt, void *chld)
  276. {
  277.     return ENOTSUP; /* not supported at the moment */
  278. }
  279.  
  280. static void *fat_match(void *prnt, const char *component)
  281. {
  282.     fat_node_t *parentp = (fat_node_t *)prnt;
  283.     char name[FAT_NAME_LEN + 1 + FAT_EXT_LEN + 1];
  284.     unsigned i, j;
  285.     unsigned bps;       /* bytes per sector */
  286.     unsigned dps;       /* dentries per sector */
  287.     unsigned blocks;
  288.     fat_dentry_t *d;
  289.     block_t *b;
  290.  
  291.     bps = fat_bps_get(parentp->idx->dev_handle);
  292.     dps = bps / sizeof(fat_dentry_t);
  293.     blocks = parentp->size / bps + (parentp->size % bps != 0);
  294.     for (i = 0; i < blocks; i++) {
  295.         unsigned dentries;
  296.        
  297.         b = fat_block_get(parentp, i);
  298.         dentries = (i == blocks - 1) ?
  299.             parentp->size % sizeof(fat_dentry_t) :
  300.             dps;
  301.         for (j = 0; j < dentries; j++) {
  302.             d = ((fat_dentry_t *)b->data) + j;
  303.             switch (fat_classify_dentry(d)) {
  304.             case FAT_DENTRY_SKIP:
  305.                 continue;
  306.             case FAT_DENTRY_LAST:
  307.                 block_put(b);
  308.                 return NULL;
  309.             default:
  310.             case FAT_DENTRY_VALID:
  311.                 dentry_name_canonify(d, name);
  312.                 break;
  313.             }
  314.             if (strcmp(name, component) == 0) {
  315.                 /* hit */
  316.                 fat_idx_t *idx = fat_idx_map(parentp->firstc,
  317.                     i * dps + j);
  318.                 void *node = fat_node_get(idx->dev_handle,
  319.                     idx->index);
  320.                 block_put(b);
  321.                 return node;
  322.             }
  323.         }
  324.         block_put(b);
  325.     }
  326.  
  327.     return NULL;
  328. }
  329.  
  330. static fs_index_t fat_index_get(void *node)
  331. {
  332.     fat_node_t *fnodep = (fat_node_t *)node;
  333.     if (!fnodep)
  334.         return 0;
  335.     return fnodep->idx->index;
  336. }
  337.  
  338. static size_t fat_size_get(void *node)
  339. {
  340.     return ((fat_node_t *)node)->size;
  341. }
  342.  
  343. static unsigned fat_lnkcnt_get(void *node)
  344. {
  345.     return ((fat_node_t *)node)->lnkcnt;
  346. }
  347.  
  348. static bool fat_has_children(void *node)
  349. {
  350.     fat_node_t *nodep = (fat_node_t *)node;
  351.     unsigned bps;
  352.     unsigned dps;
  353.     unsigned blocks;
  354.     block_t *b;
  355.     unsigned i, j;
  356.  
  357.     if (nodep->type != FAT_DIRECTORY)
  358.         return false;
  359.  
  360.     bps = fat_bps_get(nodep->idx->dev_handle);
  361.     dps = bps / sizeof(fat_dentry_t);
  362.  
  363.     blocks = nodep->size / bps + (nodep->size % bps != 0);
  364.  
  365.     for (i = 0; i < blocks; i++) {
  366.         unsigned dentries;
  367.         fat_dentry_t *d;
  368.    
  369.         b = fat_block_get(nodep, i);
  370.         dentries = (i == blocks - 1) ?
  371.             nodep->size % sizeof(fat_dentry_t) :
  372.             dps;
  373.         for (j = 0; j < dentries; j++) {
  374.             d = ((fat_dentry_t *)b->data) + j;
  375.             switch (fat_classify_dentry(d)) {
  376.             case FAT_DENTRY_SKIP:
  377.                 continue;
  378.             case FAT_DENTRY_LAST:
  379.                 block_put(b);
  380.                 return false;
  381.             default:
  382.             case FAT_DENTRY_VALID:
  383.                 block_put(b);
  384.                 return true;
  385.             }
  386.             block_put(b);
  387.             return true;
  388.         }
  389.         block_put(b);
  390.     }
  391.  
  392.     return false;
  393. }
  394.  
  395. static void *fat_root_get(dev_handle_t dev_handle)
  396. {
  397.     return fat_node_get(dev_handle, FAT_CLST_RES1);
  398. }
  399.  
  400. static char fat_plb_get_char(unsigned pos)
  401. {
  402.     return fat_reg.plb_ro[pos % PLB_SIZE];
  403. }
  404.  
  405. static bool fat_is_directory(void *node)
  406. {
  407.     return ((fat_node_t *)node)->type == FAT_DIRECTORY;
  408. }
  409.  
  410. static bool fat_is_file(void *node)
  411. {
  412.     return ((fat_node_t *)node)->type == FAT_FILE;
  413. }
  414.  
  415. /** libfs operations */
  416. libfs_ops_t fat_libfs_ops = {
  417.     .match = fat_match,
  418.     .node_get = fat_node_get,
  419.     .node_put = fat_node_put,
  420.     .create = fat_create,
  421.     .destroy = fat_destroy,
  422.     .link = fat_link,
  423.     .unlink = fat_unlink,
  424.     .index_get = fat_index_get,
  425.     .size_get = fat_size_get,
  426.     .lnkcnt_get = fat_lnkcnt_get,
  427.     .has_children = fat_has_children,
  428.     .root_get = fat_root_get,
  429.     .plb_get_char = fat_plb_get_char,
  430.     .is_directory = fat_is_directory,
  431.     .is_file = fat_is_file
  432. };
  433.  
  434. void fat_lookup(ipc_callid_t rid, ipc_call_t *request)
  435. {
  436.     libfs_lookup(&fat_libfs_ops, fat_reg.fs_handle, rid, request);
  437. }
  438.  
  439. /**
  440.  * @}
  441.  */
  442.