Advertisement
Guest User

Broken ext2 driver

a guest
Feb 1st, 2015
269
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 33.73 KB | None | 0 0
  1. /**
  2.  * fs/ext2.c
  3.  *
  4.  * Part of P-OS kernel.
  5.  *
  6.  * Written by Peter Bosch <peterbosc@gmail.com>
  7.  *
  8.  * Changelog:
  9.  * 09-07-2014 - Created
  10.  */
  11.  
  12. #include <stdint.h>
  13. #include <string.h>
  14. #include <assert.h>
  15.  
  16. #include <sys/errno.h>
  17. #include <sys/types.h>
  18.  
  19. #include "fs/ext2.h"
  20. #include "kernel/heapmm.h"
  21. #include "kernel/device.h"
  22. #include "kernel/vfs.h"
  23. #include "kernel/earlycon.h"
  24.    
  25.  
  26. void *ext2_zero_buffer = NULL;
  27.  
  28. uint32_t ext2_divup(uint32_t a, uint32_t b)
  29. {
  30.     uint32_t result = a / b;
  31.     if ( a % b ) { result++; }
  32.     return result;
  33. }
  34.  
  35. uint32_t ext2_roundup(uint32_t a, uint32_t b)
  36. {//XXX: Works only with power-of-two values for B
  37.     b--;
  38.     return (a+b) & ~b;
  39. }
  40.  
  41.  
  42. void ext2_handle_error(ext2_device_t *device)
  43. {
  44.     assert(0/* EXT2 ERROR */);
  45.  
  46. }
  47.  
  48. int ext2_read_block(ext2_device_t *dev, uint32_t block_ptr, uint32_t in_block, void *buffer, aoff_t count, aoff_t *read_size)
  49. {
  50.     int status;
  51.     aoff_t  block_addr;
  52.     aoff_t  _read_size;
  53.     size_t *rs = read_size ? read_size : (&_read_size);
  54.     if (!dev)
  55.         return EFAULT;
  56.     block_addr = (block_ptr << (10 + dev->superblock.block_size_enc)) + in_block;
  57.     status = device_block_read(dev->dev_id, block_addr, buffer, count, rs);
  58.     if ((!status) && ((*rs) != count))
  59.         return EIO;
  60.     return status;
  61. }
  62.  
  63. int ext2_write_block(ext2_device_t *dev, uint32_t block_ptr, uint32_t in_block, void *buffer, aoff_t count, aoff_t *write_size)
  64. {
  65.     int status;
  66.     aoff_t  block_addr;
  67.     aoff_t  _write_size;
  68.     aoff_t *ws = write_size ? write_size : (&_write_size);
  69.     if (!dev)
  70.         return EFAULT;
  71.     block_addr = (block_ptr << (10 + dev->superblock.block_size_enc)) + in_block;
  72.     status = device_block_write(dev->dev_id, block_addr, buffer, count, ws);   
  73.     if ((!status) && ((*ws) != count))
  74.         return EIO;
  75.     return status;
  76. }
  77.  
  78. ext2_block_group_desc_t *ext2_load_bgd(ext2_device_t *device, uint32_t bg_id)
  79. {
  80.     //TODO: Cache BGDs
  81.     ext2_block_group_desc_t *bgd;
  82.     off_t bgd_addr;
  83.     size_t read_size;
  84.     int status;
  85.  
  86.     if (!device)
  87.         return NULL;
  88.  
  89.     bgd = heapmm_alloc(sizeof(ext2_block_group_desc_t));
  90.     if (!bgd)
  91.         return NULL;
  92.  
  93.     bgd_addr = (device->bgdt_block << (10 + device->superblock.block_size_enc)) +
  94.             bg_id * sizeof(ext2_block_group_desc_t);
  95.    
  96.     status = device_block_read(device->dev_id, bgd_addr, bgd, sizeof(ext2_block_group_desc_t), &read_size);
  97.    
  98.     if (status || (read_size != sizeof(ext2_block_group_desc_t))) {
  99.         heapmm_free(bgd, sizeof(ext2_block_group_desc_t));
  100.         return NULL;
  101.     }
  102.  
  103.     return bgd;
  104. }
  105.  
  106. int ext2_store_bgd(ext2_device_t *device, uint32_t bg_id, ext2_block_group_desc_t *bgd)
  107. {
  108.     //TODO: Cache BGDs
  109.     off_t bgd_addr;
  110.     size_t read_size;
  111.     int status;
  112.  
  113.     if (!device)
  114.         return 0;
  115.  
  116.     bgd_addr = (device->bgdt_block << (10 + device->superblock.block_size_enc)) +
  117.             bg_id * sizeof(ext2_block_group_desc_t);
  118.    
  119.     status = device_block_write(device->dev_id, bgd_addr, bgd, sizeof(ext2_block_group_desc_t), &read_size);
  120.    
  121.     if (status || (read_size != sizeof(ext2_block_group_desc_t))) {
  122.         return 1;
  123.     }
  124.  
  125.     return 0;
  126. }
  127.  
  128. void ext2_free_bgd(__attribute__((__unused__)) ext2_device_t *device, ext2_block_group_desc_t *bgd)
  129. {
  130.     heapmm_free(bgd, sizeof(ext2_block_group_desc_t));
  131. }
  132.  
  133. inline uint32_t ext2_free_block(ext2_device_t *device, uint32_t block_id)
  134. {
  135.     uint32_t b_count = device->superblock.block_count;
  136.     uint32_t bgrp_id = 0;
  137.     uint32_t bgrp_bcnt = device->superblock.blocks_per_group;
  138.     uint32_t bm_block_size = 256 << device->superblock.block_size_enc;
  139.     uint32_t bm_block_bcnt = bm_block_size * 32;
  140.     uint32_t bm_id;
  141.     uint32_t block_map[bm_block_size];
  142.     uint32_t first_b = device->superblock.block_size_enc ? 0 : 1;
  143.     uint32_t idx ,nb;
  144.  
  145.     int status;
  146.  
  147.     ext2_block_group_desc_t *bgd;
  148.  
  149.     assert (block_id < b_count);
  150.     assert (block_id > first_b);
  151.  
  152.     bgrp_id = (block_id - first_b) / bgrp_bcnt;
  153.     idx = block_id - first_b - bgrp_id * bgrp_bcnt;
  154.     bm_id = idx / bm_block_bcnt;
  155.     idx -= bm_id * bm_block_bcnt;
  156.     nb = idx % 32;
  157.     idx -= nb;
  158.    
  159.     bgd = ext2_load_bgd(device, bgrp_id);
  160.  
  161.     status = ext2_read_block(device, bgd->block_bitmap + bm_id, 0, block_map, bm_block_size * 4, NULL);
  162.     if (status)
  163.         return status;
  164.  
  165.     EXT2_BITMAP_CLR(block_map[idx], nb);
  166.  
  167.     status = ext2_write_block(device, bgd->block_bitmap + bm_id, 0, block_map, bm_block_size * 4, NULL);
  168.     if (status) {
  169.         debugcon_printf("ext2: MAYDAY MAYDAY MAYDAY: write error (block bitmap), FILESYSTEM IS PROBABLY CORRUPTED NOW!");
  170.         ext2_handle_error(device);
  171.     }
  172.  
  173.     bgd->free_block_count++;
  174.  
  175.     status = ext2_store_bgd(device, bgrp_id, bgd);
  176.     if (status) {
  177.         debugcon_printf("ext2: MAYDAY MAYDAY MAYDAY: write error (BGD), FILESYSTEM IS PROBABLY CORRUPTED NOW!");
  178.         ext2_handle_error(device);
  179.     }
  180.     ext2_free_bgd(device, bgd);
  181.  
  182.     device->superblock.free_block_count++;
  183.  
  184.     return 0;
  185. }
  186.  
  187. inline uint32_t ext2_alloc_block(ext2_device_t *device, uint32_t start)
  188. {
  189.     uint32_t b_count = device->superblock.block_count;
  190.     uint32_t block_id = start;
  191.     uint32_t bgrp_id = 0;
  192.     uint32_t bgrp_bcnt = device->superblock.blocks_per_group;
  193.     uint32_t bgrp_count = ext2_divup(b_count,bgrp_bcnt);//DIVUP
  194.     uint32_t bm_block_size = 256 << device->superblock.block_size_enc;
  195.     uint32_t bm_block_bcnt = bm_block_size * 32;
  196.     uint32_t bgrp_bmcnt = ext2_divup(bgrp_bcnt,bm_block_bcnt);//DIVUP
  197.     uint32_t bm_id;
  198.     uint32_t block_map[bm_block_size];
  199.     uint32_t first_b = device->superblock.block_size_enc ? 0 : 1;
  200.     uint32_t idx ,nb;
  201.  
  202.     int status;
  203.  
  204.     ext2_block_group_desc_t *bgd;
  205.  
  206.     assert (start < b_count);
  207.  
  208.     if (start == 0)
  209.         block_id = first_b;
  210.  
  211.     bgrp_id = (block_id - first_b) / bgrp_bcnt;
  212.     idx = block_id - first_b - bgrp_id * bgrp_bcnt;
  213.     bm_id = idx / bm_block_bcnt;
  214.     idx -= bm_id * bm_block_bcnt;
  215.     nb = idx % 32;
  216.     idx -= nb;
  217.     for (; bgrp_id < bgrp_count; bgrp_id++) {
  218.         bgd = ext2_load_bgd(device, bgrp_id);
  219.  
  220.         if (bgd->free_block_count) {
  221.             for (; bm_id < bgrp_bmcnt; bm_id++) {
  222.                 status = ext2_read_block(device, bgd->block_bitmap + bm_id, 0, block_map, bm_block_size * 4, NULL);
  223.                 if (status)
  224.                     return 0;
  225.                 for (; idx < bm_block_size; idx++) {
  226.                     if (block_map[idx] != 0xFFFFFFFF) {                
  227.                         for (; nb < 32; nb++)
  228.                             if (!EXT2_BITMAP_GET(block_map[idx], nb))
  229.                                 goto found_it;
  230.                     }
  231.                     nb = 0;
  232.                 }
  233.                 idx = 0;
  234.             }
  235.         }
  236.         bm_id = 0;     
  237.         ext2_free_bgd(device, bgd);
  238.     }
  239.     bgrp_id = 0;
  240.     for (; bgrp_id < bgrp_count; bgrp_id++) {
  241.         bgd = ext2_load_bgd(device, bgrp_id);
  242.  
  243.         if (bgd->free_block_count) {
  244.             for (; bm_id < bgrp_bmcnt; bm_id++) {
  245.                 status = ext2_read_block(device, bgd->block_bitmap + bm_id, 0, block_map, bm_block_size * 4, NULL);
  246.                 if (status)
  247.                     return 0;
  248.                 for (; idx < bm_block_size; idx++) {
  249.                     if (block_map[idx] != 0xFFFFFFFF) {                
  250.                         for (; nb < 32; nb++)
  251.                             if (!EXT2_BITMAP_GET(block_map[idx], nb))
  252.                                 goto found_it;
  253.                     }
  254.                     nb = 0;
  255.                 }
  256.                 idx = 0;
  257.             }
  258.         }
  259.         bm_id = 0;     
  260.         ext2_free_bgd(device, bgd);
  261.     }
  262.     return EXT2_ENOSPC;
  263. found_it:
  264.  
  265.     block_id = nb + idx * 32 + bm_id * bm_block_bcnt + bgrp_id * bgrp_bcnt + first_b;
  266.  
  267.     EXT2_BITMAP_SET(block_map[idx], nb);
  268.     status = ext2_write_block(device, bgd->block_bitmap + bm_id, 0, block_map, bm_block_size * 4, NULL);
  269.     if (status) {
  270.         debugcon_printf("ext2: MAYDAY MAYDAY MAYDAY: write error (block bitmap), FILESYSTEM IS PROBABLY CORRUPTED NOW!");
  271.         ext2_handle_error(device);
  272.     }
  273.  
  274.     bgd->free_block_count--;
  275.  
  276.     status = ext2_store_bgd(device, bgrp_id, bgd);
  277.     if (status) {
  278.         debugcon_printf("ext2: MAYDAY MAYDAY MAYDAY: write error (BGD), FILESYSTEM IS PROBABLY CORRUPTED NOW!");
  279.         ext2_handle_error(device);
  280.     }
  281.     ext2_free_bgd(device, bgd);
  282.  
  283.     device->superblock.free_block_count--;
  284.    
  285.     memset(block_map, 0, bm_block_size * 4);
  286.  
  287.     status = ext2_write_block(device, block_id, 0, block_map, bm_block_size * 4, NULL);
  288.     if (status) {
  289.         debugcon_printf("ext2: MAYDAY MAYDAY MAYDAY: write error (block clear)!");
  290.         ext2_handle_error(device);
  291.     }
  292.  
  293.     return block_id;
  294. }
  295.  
  296. inline uint32_t ext2_alloc_inode(ext2_device_t *device)
  297. {
  298.     uint32_t i_count = device->superblock.inode_count;
  299.     uint32_t inode_id = 11;
  300.     uint32_t bgrp_id = 0;
  301.     uint32_t bgrp_icnt = device->superblock.inodes_per_group;
  302.     uint32_t bgrp_count = ext2_divup(i_count,bgrp_icnt);//DIVUP
  303.     uint32_t bm_block_size = 256 << device->superblock.block_size_enc;
  304.     uint32_t bm_block_icnt = bm_block_size * 32;
  305.     uint32_t bgrp_bmcnt = ext2_divup(bgrp_icnt,bm_block_icnt);//DIVUP
  306.     uint32_t bm_id;
  307.     uint32_t inode_map[bm_block_size];
  308.     uint32_t first_i = 1;
  309.     uint32_t idx ,nb;
  310.  
  311.     int status;
  312.  
  313.     ext2_block_group_desc_t *bgd;
  314.  
  315.     bgrp_id = (inode_id - first_i) / bgrp_icnt;
  316.     idx = inode_id - first_i - bgrp_id * bgrp_icnt;
  317.     bm_id = idx / bm_block_icnt;
  318.     idx -= bm_id * bm_block_icnt;
  319.     nb = idx % 32;
  320.     idx -= nb;
  321.  
  322.     for (; bgrp_id < bgrp_count; bgrp_id++) {
  323.         bgd = ext2_load_bgd(device, bgrp_id);
  324.  
  325.         if (bgd->free_inode_count) {
  326.             for (; bm_id < bgrp_bmcnt; bm_id++) {
  327.                 status = ext2_read_block(device, bgd->inode_bitmap + bm_id, 0, inode_map, bm_block_size * 4, NULL);
  328.                 if (status)
  329.                     return 0;
  330.                 for (; idx < bm_block_size; idx++) {
  331.                     if (inode_map[idx] != 0xFFFFFFFF) {                
  332.                         for (; nb < 32; nb++)
  333.                             if (!EXT2_BITMAP_GET(inode_map[idx], nb))
  334.                                 goto found_it;
  335.                     }
  336.                     nb = 0;
  337.                 }
  338.                 idx = 0;
  339.             }
  340.         }
  341.         bm_id = 0;     
  342.         ext2_free_bgd(device, bgd);
  343.     }
  344.     bgrp_id = 0;
  345.  
  346.     return EXT2_ENOSPC;
  347. found_it:
  348.  
  349.     inode_id = nb + idx * 32 + bm_id * bm_block_icnt + bgrp_id * bgrp_icnt + first_i;
  350.  
  351.     EXT2_BITMAP_SET(inode_map[idx], nb);
  352.     status = ext2_write_block(device, bgd->inode_bitmap + bm_id, 0, inode_map, bm_block_size * 4, NULL);
  353.     if (status) {
  354.         debugcon_printf("ext2: MAYDAY MAYDAY MAYDAY: write error (inode bitmap), FILESYSTEM IS PROBABLY CORRUPTED NOW!");
  355.         ext2_handle_error(device);
  356.     }
  357.  
  358.     bgd->free_inode_count--;
  359.  
  360.     status = ext2_store_bgd(device, bgrp_id, bgd);
  361.     if (status) {
  362.         debugcon_printf("ext2: MAYDAY MAYDAY MAYDAY: write error (BGD), FILESYSTEM IS PROBABLY CORRUPTED NOW!");
  363.         ext2_handle_error(device);
  364.     }
  365.     ext2_free_bgd(device, bgd);
  366.  
  367.     device->superblock.free_inode_count--;
  368.  
  369.     return inode_id;
  370. }
  371.  
  372. inline uint32_t ext2_free_inode(ext2_device_t *device, uint32_t inode_id)
  373. {
  374.     uint32_t i_count = device->superblock.inode_count;
  375.     uint32_t bgrp_id = 0;
  376.     uint32_t bgrp_icnt = device->superblock.inodes_per_group;
  377.     uint32_t bm_block_size = 256 << device->superblock.block_size_enc;
  378.     uint32_t bm_block_icnt = bm_block_size * 32;
  379.     uint32_t bm_id;
  380.     uint32_t inode_map[bm_block_size];
  381.     uint32_t first_i = 1;
  382.     uint32_t idx ,nb;
  383.  
  384.     int status;
  385.  
  386.     ext2_block_group_desc_t *bgd;
  387.  
  388.     assert (inode_id < i_count);
  389.     assert (inode_id > first_i);
  390.  
  391.     bgrp_id = (inode_id - first_i) / bgrp_icnt;
  392.     idx = inode_id - first_i - bgrp_id * bgrp_icnt;
  393.     bm_id = idx / bm_block_icnt;
  394.     idx -= bm_id * bm_block_icnt;
  395.     nb = idx % 32;
  396.     idx -= nb;
  397.    
  398.     bgd = ext2_load_bgd(device, bgrp_id);
  399.  
  400.     status = ext2_read_block(device, bgd->inode_bitmap + bm_id, 0, inode_map, bm_block_size * 4, NULL);
  401.     if (status)
  402.         return status;
  403.  
  404.     EXT2_BITMAP_CLR(inode_map[idx], nb);
  405.  
  406.     status = ext2_write_block(device, bgd->inode_bitmap + bm_id, 0, inode_map, bm_block_size * 4, NULL);
  407.     if (status) {
  408.         debugcon_printf("ext2: MAYDAY MAYDAY MAYDAY: write error (inode bitmap), FILESYSTEM IS PROBABLY CORRUPTED NOW!");
  409.         ext2_handle_error(device);
  410.     }
  411.  
  412.     bgd->free_inode_count++;
  413.  
  414.     status = ext2_store_bgd(device, bgrp_id, bgd);
  415.     if (status) {
  416.         debugcon_printf("ext2: MAYDAY MAYDAY MAYDAY: write error (BGD), FILESYSTEM IS PROBABLY CORRUPTED NOW!");
  417.         ext2_handle_error(device);
  418.     }
  419.     ext2_free_bgd(device, bgd);
  420.  
  421.     device->superblock.free_inode_count++;
  422.  
  423.     return 0;
  424. }
  425.  
  426. uint32_t ext2_allocate_indirect_block(ext2_device_t *device, ext2_inode_t *inode)
  427. {
  428.     int status;
  429.     size_t block_size = 1024 << device->superblock.block_size_enc;
  430.     uint32_t id = ext2_alloc_block(device, 0);//TODO: Prevent fragmentation, swap 0 for previous block in inode
  431.     if (id != EXT2_ENOSPC) {
  432.         inode->blocks += 2 << device->superblock.block_size_enc;
  433.         if (!ext2_zero_buffer) {
  434.             ext2_zero_buffer = heapmm_alloc(block_size);
  435.             memset(ext2_zero_buffer, 0, block_size);
  436.         }
  437.         status = ext2_write_block(device, id, 0, ext2_zero_buffer, block_size, NULL);
  438.         assert(status == 0);
  439.     }
  440.     return id;
  441. }
  442.  
  443. uint32_t ext2_decode_block_id(ext2_device_t *device, ext2_inode_t *inode, uint32_t block_id)
  444. {
  445.     uint32_t indirect_count = 256 << device->superblock.block_size_enc;
  446.     uint32_t indirect_id, indirect_off, indirect_rd;
  447.     uint32_t s_indir_l = indirect_count;
  448.     uint32_t d_indir_l = indirect_count * indirect_count;
  449.     uint32_t s_indir_s = 12;
  450.     uint32_t d_indir_s = s_indir_s + s_indir_l;
  451.     uint32_t t_indir_s = d_indir_s + d_indir_l;
  452.     int status;
  453.  
  454.     if (block_id >= t_indir_s) { //Triply indirect
  455.         indirect_id = inode->block[14];
  456.         indirect_off = (block_id - t_indir_s) / d_indir_l;
  457.  
  458.         if (!indirect_id)
  459.             return 0;
  460.  
  461.         status = ext2_read_block(device, indirect_id, indirect_off * 4, &indirect_rd, 4, NULL);
  462.         if (status || !indirect_rd) {
  463.             assert ( status == 0 );
  464.             return 0;
  465.         }
  466.  
  467.         indirect_id = indirect_rd;
  468.  
  469.         block_id -= indirect_off * d_indir_l + d_indir_l;
  470.        
  471.     } else if (block_id >= d_indir_s) {
  472.  
  473.         indirect_id = inode->block[13];
  474.  
  475.         if (!indirect_id)
  476.             return 0;
  477.     }
  478.  
  479.     if (block_id >= d_indir_s) { //Doubly indirect
  480.         indirect_off = (block_id - d_indir_s) / s_indir_l;
  481.  
  482.         status = ext2_read_block(device, indirect_id, indirect_off * 4, &indirect_rd, 4, NULL);
  483.         if (status || !indirect_rd) {
  484.             assert ( status == 0 );
  485.             return 0;
  486.         }
  487.  
  488.         indirect_id = indirect_rd;
  489.  
  490.         block_id -= s_indir_l + indirect_off * s_indir_l;
  491.  
  492.     } else if (block_id >= s_indir_s) {
  493.  
  494.         indirect_id = inode->block[12];
  495.  
  496.         if (!indirect_id)
  497.             return 0;
  498.  
  499.     }
  500.  
  501.     if (block_id >= s_indir_s) { //Singly Indirect
  502.  
  503.         indirect_off = block_id - s_indir_s;
  504.  
  505.         status = ext2_read_block(device, indirect_id, indirect_off * 4, &indirect_rd, 4, NULL);
  506.         if (status || !indirect_rd) {
  507.             assert ( status == 0 );
  508.             return 0;
  509.         }
  510.  
  511.         return indirect_rd;
  512.     }
  513.  
  514.     return inode->block[block_id];
  515. }
  516.  
  517. int ext2_set_block_id(ext2_device_t *device, ext2_inode_t *inode, uint32_t block_id, uint32_t block_v)
  518. {
  519.     uint32_t indirect_count = 256 << device->superblock.block_size_enc;
  520.     uint32_t indirect_id, indirect_off, indirect_rd;
  521.     uint32_t s_indir_l = indirect_count;
  522.     uint32_t d_indir_l = indirect_count * indirect_count;
  523.     uint32_t s_indir_s = 12;
  524.     uint32_t d_indir_s = s_indir_s + s_indir_l;
  525.     uint32_t t_indir_s = d_indir_s + d_indir_l;
  526.     int status;
  527.  
  528.     if (block_id >= t_indir_s) { //Triply indirect
  529.         indirect_id = inode->block[14];
  530.         indirect_off = (block_id - t_indir_s) / d_indir_l;
  531.  
  532.         if (!indirect_id) {
  533.  
  534.             indirect_id = ext2_allocate_indirect_block(device, inode);
  535.  
  536.             if (indirect_id == EXT2_ENOSPC)
  537.                 return ENOSPC;         
  538.  
  539.             inode->block[14] = indirect_id;
  540.         }
  541.  
  542.         status = ext2_read_block(device, indirect_id, indirect_off * 4, &indirect_rd, 4, NULL);
  543.         if (status)
  544.             return status;
  545.  
  546.         if (!indirect_rd) {
  547.  
  548.             indirect_rd = ext2_allocate_indirect_block(device, inode);
  549.  
  550.             if (indirect_rd == EXT2_ENOSPC)
  551.                 return ENOSPC; 
  552.  
  553.             status = ext2_write_block(device, indirect_id, indirect_off * 4, &indirect_rd, 4, NULL);
  554.             if (status)
  555.                 return status;         
  556.         }
  557.  
  558.         indirect_id = indirect_rd;
  559.  
  560.         block_id -= indirect_off * d_indir_l + d_indir_l;
  561.        
  562.     } else if (block_id >= d_indir_s) {
  563.  
  564.         indirect_id = inode->block[13];
  565.  
  566.         if (!indirect_id) {
  567.  
  568.             indirect_id = ext2_allocate_indirect_block(device, inode);
  569.  
  570.             if (indirect_id == EXT2_ENOSPC)
  571.                 return ENOSPC; 
  572.  
  573.             inode->block[13] = indirect_id;
  574.         }
  575.     }
  576.  
  577.     if (block_id >= d_indir_s) { //Doubly indirect
  578.         indirect_off = (block_id - d_indir_s) / s_indir_l;
  579.  
  580.         status = ext2_read_block(device, indirect_id, indirect_off * 4, &indirect_rd, 4, NULL);
  581.         if (status)
  582.             return status;
  583.  
  584.         if (!indirect_rd) {
  585.  
  586.             indirect_rd = ext2_allocate_indirect_block(device, inode);
  587.  
  588.             if (indirect_rd == EXT2_ENOSPC)
  589.                 return ENOSPC; 
  590.  
  591.             status = ext2_write_block(device, indirect_id, indirect_off * 4, &indirect_rd, 4, NULL);
  592.             if (status)
  593.                 return status;         
  594.         }
  595.  
  596.         indirect_id = indirect_rd;
  597.  
  598.         block_id -= s_indir_l + indirect_off * s_indir_l;
  599.  
  600.     } else if (block_id >= s_indir_s){
  601.  
  602.         indirect_id = inode->block[12];
  603.  
  604.         if (!indirect_id) {
  605.  
  606.             indirect_id = ext2_allocate_indirect_block(device, inode);
  607.  
  608.             if (indirect_id == EXT2_ENOSPC)
  609.                 return ENOSPC; 
  610.  
  611.             inode->block[12] = indirect_id;
  612.         }
  613.  
  614.     }
  615.  
  616.     if (block_id >= s_indir_s) { //Singly Indirect
  617.  
  618.         indirect_off = block_id - s_indir_s;
  619.  
  620.         status = ext2_write_block(device, indirect_id, indirect_off * 4, &block_v, 4, NULL);
  621.         if (status)
  622.             return status; 
  623.  
  624.         return 0;
  625.     }
  626.  
  627.     inode->block[block_id] = block_v;
  628.  
  629.     return 0;
  630. }
  631.  
  632. int ext2_shrink_inode(ext2_device_t *device, ext2_inode_t *inode, aoff_t old_size, aoff_t new_size)
  633. {
  634.     aoff_t count;
  635.     aoff_t length = old_size - new_size;
  636.     aoff_t block_size;
  637.     aoff_t in_blk;
  638.     aoff_t in_blk_size;
  639.     aoff_t in_file;
  640.     uint32_t block_addr;   
  641.     int status;
  642.  
  643.     block_size = 1024 << device->superblock.block_size_enc;
  644.  
  645.     for (count = 0; count < length; count += in_blk_size) {
  646.         in_file = count + new_size;
  647.         in_blk = in_file % block_size;             
  648.         in_blk_size = length - count;
  649.  
  650.         if (in_blk_size > block_size)
  651.             in_blk_size = block_size;
  652.    
  653.         if ((in_blk || (in_blk_size != block_size)))
  654.             continue;
  655.    
  656.         block_addr = ext2_decode_block_id (device, inode, in_file / block_size);
  657.  
  658.         if (block_addr) {
  659.             debugcon_printf("ext2: shrinking file!\n");
  660.             status = ext2_free_block(device, block_addr);
  661.             if (status)
  662.                 return status;
  663.             if (block_addr == EXT2_ENOSPC)
  664.                 return ENOSPC;
  665.  
  666.             status = ext2_set_block_id(device, inode, in_file / block_size, 0);
  667.             if (status)
  668.                 return status;
  669.  
  670.             inode->blocks -= 2 << device->superblock.block_size_enc;;
  671.         }
  672.  
  673.         if (status)
  674.             return status;
  675.     }
  676.  
  677.     //TODO: Dealloc indirect blocks
  678.  
  679.     return 0;
  680. }
  681.  
  682. int ext2_trunc_inode(inode_t *_inode, aoff_t size)//buffer, f_offset, length -> numbytes
  683. {
  684.     ext2_device_t *device;
  685.     ext2_vinode_t *inode;
  686.  
  687.     if (!_inode) { 
  688.         return EFAULT;
  689.     }
  690.  
  691.     device = (ext2_device_t *) _inode->device;
  692.     inode = (ext2_vinode_t *) _inode;
  693.  
  694.     if (size > _inode->size) {
  695.         //TODO: Implement explicit file growth
  696.     } else if (size < _inode->size) {
  697.         return ext2_shrink_inode(device, &(inode->inode), _inode->size, size);
  698.     }
  699.     return 0;  
  700. }
  701.  
  702. int ext2_write_inode(inode_t *_inode, void *_buffer, aoff_t f_offset, aoff_t length, aoff_t *nwritten)
  703. {
  704.     ext2_device_t *device;
  705.     ext2_vinode_t *inode;
  706.     aoff_t count;
  707.     aoff_t block_size;
  708.     aoff_t in_blk_size;
  709.     aoff_t in_blk;
  710.     aoff_t in_file;
  711.     uint32_t block_addr, p_block_addr; 
  712.     uint8_t *buffer = _buffer;
  713.     int status;
  714.  
  715.     if (!_inode) { 
  716.         *nwritten = 0;
  717.         return EFAULT;
  718.     }
  719.  
  720.     device = (ext2_device_t *) _inode->device;
  721.     inode = (ext2_vinode_t *) _inode;
  722.  
  723.     block_size = 1024 << device->superblock.block_size_enc;
  724.    
  725.     p_block_addr = 0;
  726.  
  727.     for (count = 0; count < length; count += in_blk_size) {
  728.         in_file = count + f_offset;
  729.         in_blk = in_file % block_size;             
  730.         in_blk_size = length - count;
  731.  
  732.         *nwritten = count;
  733.  
  734.         if (in_blk_size > block_size)
  735.             in_blk_size = block_size;
  736.  
  737.         block_addr = ext2_decode_block_id (device, &(inode->inode), in_file / block_size);
  738.  
  739.         if (!block_addr) {
  740.             debugcon_printf("ext2: growing file!\n");
  741.             block_addr = ext2_alloc_block(device, p_block_addr);
  742.             if (!block_addr)
  743.                 return EIO;
  744.             if (block_addr == EXT2_ENOSPC)
  745.                 return ENOSPC;
  746.  
  747.             status = ext2_set_block_id(device, &(inode->inode), in_file / block_size, block_addr);
  748.             if (status)
  749.                 return status;
  750.  
  751.             inode->inode.blocks += 2 << device->superblock.block_size_enc;
  752.         }
  753.  
  754.         status = ext2_write_block(device, block_addr, in_blk, &(buffer[count]), in_blk_size, NULL);
  755.  
  756.         if (status)
  757.             return status;
  758.  
  759.         p_block_addr = block_addr;
  760.     }
  761.    
  762.     *nwritten = count;
  763.  
  764.     return 0;
  765. }
  766.  
  767. int ext2_read_inode(inode_t *_inode, void *_buffer, aoff_t f_offset, aoff_t length, aoff_t *nread)
  768. {
  769.     ext2_device_t *device;
  770.     ext2_vinode_t *inode;
  771.     aoff_t count;
  772.     aoff_t block_size;
  773.     aoff_t in_blk_size;
  774.     aoff_t in_blk;
  775.     aoff_t in_file;
  776.     uint32_t block_addr;   
  777.     uint8_t *buffer = _buffer;
  778.     int status;
  779.  
  780.     if (!_inode) { 
  781.         *nread = 0;
  782.         return EFAULT;
  783.     }
  784.  
  785.     device = (ext2_device_t *) _inode->device;
  786.     inode = (ext2_vinode_t *) _inode;
  787.  
  788.     block_size = 1024 << device->superblock.block_size_enc;
  789.  
  790.     for (count = 0; count < length; count += in_blk_size) {
  791.         in_file = count + f_offset;
  792.         in_blk = in_file % block_size;             
  793.         in_blk_size = length - count;
  794.  
  795.         *nread = count;
  796.  
  797.         if (in_blk_size > block_size)
  798.             in_blk_size = block_size;
  799.  
  800.         block_addr = ext2_decode_block_id (device, &(inode->inode), in_file / block_size);
  801.  
  802.         if (!block_addr)
  803.             return EIO;
  804.  
  805.         status = ext2_read_block(device, block_addr, in_blk, &(buffer[count]), in_blk_size, NULL);
  806.  
  807.         if (status)
  808.             return status;
  809.     }
  810.    
  811.     *nread = count;
  812.  
  813.     return 0;
  814. }
  815.  
  816. int ext2_link(inode_t *_inode, char *name, ino_t ino_id)
  817. {
  818.     ext2_device_t *device;
  819.     ext2_vinode_t *inode;
  820.  
  821.     size_t reclen,namelen, f_reclen;
  822.     ext2_dirent_t dirent;  
  823.     ext2_dirent_t f_dirent;
  824.    
  825.     int status, m = 0;
  826.  
  827.     aoff_t split_offset, hole_offset, nread, pos, dsize, hole_size;
  828.  
  829.     if (!_inode)
  830.         return EFAULT;
  831.  
  832.     device = (ext2_device_t *) _inode->device;
  833.     inode = (ext2_vinode_t *) _inode;
  834.  
  835.     dsize = _inode->size;
  836.  
  837.     namelen = strlen(name);
  838.     reclen = ext2_roundup(sizeof(ext2_dirent_t) + namelen, 4);
  839.  
  840.     split_offset = 0;
  841.  
  842.     for (pos = 0; pos < dsize; pos += f_dirent.rec_len) {
  843.         status = ext2_read_inode(_inode, &f_dirent, pos, sizeof(ext2_dirent_t), &nread);
  844.         if (status || (nread != sizeof(ext2_dirent_t)))
  845.             return status ? status : EIO;
  846.        
  847.         f_reclen = ext2_roundup (sizeof(ext2_dirent_t) + f_dirent.name_len, 4);
  848.        
  849.         if ((((!f_dirent.inode) || (!f_dirent.name_len))) && (f_dirent.rec_len >= reclen)) {
  850.             hole_offset = pos;
  851.             hole_size = f_dirent.rec_len;
  852.             m = 1;
  853.             break;
  854.         } else if ((f_dirent.rec_len - f_reclen) >= reclen) {
  855.             split_offset = pos;
  856.             hole_offset = pos + f_reclen;
  857.             hole_size = f_dirent.rec_len - f_reclen;
  858.             m = 2;
  859.             break;
  860.         }
  861.         split_offset = pos;
  862.     }
  863.  
  864.     if (m == 0) {
  865.         //Append new block to the end of the file, split_offset contains the offset of the last dirent
  866.         hole_size = 1024 << device->superblock.block_size_enc;
  867.         hole_offset = split_offset;
  868.         _inode->size += hole_size;
  869.     }
  870.  
  871.     dirent.rec_len = hole_size;
  872.     dirent.name_len = namelen;
  873.     dirent.inode = ino_id;
  874.     //TODO: Set file type
  875.     dirent.file_type = EXT2_FT_UNKNOWN;
  876.    
  877.     status = ext2_write_inode(_inode, name, hole_offset + sizeof(ext2_dirent_t), namelen, &nread);
  878.     if (status || (nread != namelen))
  879.         return status ? status : EIO;
  880.    
  881.     status = ext2_write_inode(_inode, &dirent, hole_offset, sizeof(ext2_dirent_t), &nread);
  882.     if (status || (nread != sizeof(ext2_dirent_t)))
  883.         return status ? status : EIO;
  884.    
  885.     if (m == 2){
  886.         f_dirent.rec_len = hole_offset - split_offset;
  887.  
  888.         status = ext2_write_inode(_inode, &f_dirent, split_offset, sizeof(ext2_dirent_t), &nread);
  889.         if (status || (nread != sizeof(ext2_dirent_t)))
  890.             return status ? status : EIO;
  891.     }
  892.  
  893.     return 0;
  894.    
  895. }
  896.  
  897. int ext2_readdir(inode_t *_inode, void *_buffer, aoff_t f_offset, aoff_t length, aoff_t *nread)
  898. {///XXX: Dependent on : sizeof(vfs_dirent_t) == sizeof(ext2_dirent_t)
  899.     int status;
  900.  
  901.     ext2_dirent_t *dirent;
  902.     uint8_t *name;
  903.     uint8_t *buffer= _buffer;
  904.  
  905.     dirent_t *vfs_dir;
  906.     aoff_t pos, inode_nread;
  907.  
  908.     *nread = 0;
  909.  
  910.     if (!_inode)
  911.         return EFAULT;
  912.  
  913.     if (f_offset >= _inode->size)
  914.         return EINVAL;
  915.  
  916.     if ((f_offset + length) > _inode->size)
  917.         length = _inode->size - f_offset;
  918.  
  919.     dirent = heapmm_alloc(sizeof(ext2_dirent_t));
  920.    
  921.     if (!dirent)
  922.         return ENOMEM;
  923.  
  924.     for (pos = 0; pos < length; pos += dirent->rec_len) {
  925.  
  926.         *nread = pos;
  927.  
  928.         status = ext2_read_inode(_inode, dirent, pos + f_offset, sizeof(ext2_dirent_t), &inode_nread);
  929.         if (status || (inode_nread != sizeof(ext2_dirent_t))) {
  930.             heapmm_free(dirent, sizeof(ext2_dirent_t));
  931.             return status ? status : EIO;
  932.         }
  933.  
  934.         if ((dirent->rec_len + pos) > length){
  935.             heapmm_free(dirent, sizeof(ext2_dirent_t));
  936.             return 0;
  937.         }
  938.    
  939.         vfs_dir = (dirent_t *)&buffer[pos];
  940.  
  941.         name = (uint8_t *) vfs_dir->name;
  942.        
  943.         status = ext2_read_inode(_inode, name, pos + f_offset + sizeof(ext2_dirent_t), dirent->name_len, &inode_nread);
  944.  
  945.         if (status || (inode_nread != dirent->name_len)) {
  946.             heapmm_free(dirent, sizeof(ext2_dirent_t));
  947.             return status ? status : EIO;
  948.         }
  949.  
  950.         name[dirent->name_len] = 0;
  951.         vfs_dir->inode_id = dirent->inode;
  952.         vfs_dir->device_id = _inode->device_id;
  953.         vfs_dir->d_reclen = dirent->rec_len;
  954.        
  955.     }
  956.  
  957.     heapmm_free(dirent, sizeof(ext2_dirent_t));
  958.  
  959.     *nread = pos;
  960.  
  961.     return 0;
  962. }
  963.  
  964. dirent_t *ext2_finddir(inode_t *_inode, char * name)
  965. {
  966.     uint8_t *buffer = heapmm_alloc(1024);
  967.     int status;
  968.     aoff_t nread = 1;
  969.     aoff_t fpos = 0;
  970.     aoff_t pos;
  971.     dirent_t *dirent;
  972.     dirent_t *pp;
  973.     if (!buffer)
  974.         return NULL;
  975.     for (fpos = 0; nread != 0; fpos += nread) {
  976.         status = ext2_readdir(_inode, buffer, fpos, 1024, &nread);
  977.         if (status) {
  978.             heapmm_free(buffer, 1024);
  979.             return NULL;
  980.         }
  981.         for (pos = 0; pos < nread; pos += dirent->d_reclen) {
  982.             dirent = (dirent_t *) &(buffer[pos]);
  983.             if (strcmp(name, dirent->name) == 0){
  984.                 pp = heapmm_alloc(sizeof(dirent_t));   
  985.                 dirent->d_reclen = (dirent->d_reclen > sizeof(dirent_t)) ? sizeof(dirent_t) : dirent->d_reclen;
  986.                 memcpy(pp, dirent,dirent->d_reclen);
  987.                 heapmm_free(buffer, 1024);
  988.                 return pp;
  989.             }
  990.         }
  991.     }
  992.     heapmm_free(buffer, 1024);
  993.     return NULL;
  994. }
  995.  
  996. int ext2_load_e2inode(ext2_device_t *device, ext2_inode_t *ino, uint32_t ino_id)
  997. {
  998.     ext2_block_group_desc_t *bgd;
  999.     off_t           index, ino_offset;
  1000.     size_t read_size;
  1001.     int status;
  1002.  
  1003.     if (!device)
  1004.         return 0;
  1005.  
  1006.     bgd = ext2_load_bgd(device, (ino_id - 1) / device->superblock.inodes_per_group);
  1007.     if (!bgd) {
  1008.         return 0;
  1009.     }  
  1010.  
  1011.     index = (ino_id - 1) % device->superblock.inodes_per_group;
  1012.     ino_offset = (bgd->inode_table << (10 + device->superblock.block_size_enc)) +
  1013.             index * device->superblock.inode_size;
  1014.  
  1015.     status = device_block_read(device->dev_id,
  1016.                    ino_offset,
  1017.                    ino,
  1018.                    device->inode_load_size,
  1019.                    &read_size);
  1020.    
  1021.     if (status || (read_size != device->inode_load_size)) {
  1022.         ext2_free_bgd(device, bgd);
  1023.         return 0;
  1024.     }
  1025.    
  1026.     ext2_free_bgd(device, bgd);
  1027.     return 1;
  1028. }
  1029.  
  1030. int ext2_store_e2inode(ext2_device_t *device, ext2_inode_t *ino, uint32_t ino_id)
  1031. {
  1032.     ext2_block_group_desc_t *bgd;
  1033.     off_t           index, ino_offset;
  1034.     size_t read_size;
  1035.     int status;
  1036.  
  1037.     if (!device)
  1038.         return EFAULT;
  1039.  
  1040.     bgd = ext2_load_bgd(device, (ino_id - 1) / device->superblock.inodes_per_group);
  1041.     if (!bgd) {
  1042.         return EIO;
  1043.     }  
  1044.  
  1045.     index = (ino_id - 1) % device->superblock.inodes_per_group;
  1046.     ino_offset = (bgd->inode_table << (10 + device->superblock.block_size_enc)) +
  1047.             index * device->superblock.inode_size;
  1048.  
  1049.     status = device_block_write(device->dev_id,
  1050.                    ino_offset,
  1051.                    ino,
  1052.                    device->inode_load_size,
  1053.                    &read_size);
  1054.    
  1055.     if (status || (read_size != device->inode_load_size)) {
  1056.         ext2_free_bgd(device, bgd);
  1057.         return status;
  1058.     }
  1059.    
  1060.     ext2_free_bgd(device, bgd);
  1061.     return 0;
  1062. }
  1063.  
  1064. void ext2_e2tovfs_inode(ext2_device_t *device, ext2_vinode_t *_ino, ino_t ino_id)
  1065. {
  1066.     ext2_inode_t *ino;
  1067.     inode_t *vfs_ino;
  1068.  
  1069.     ino = &(_ino->inode);
  1070.     vfs_ino = &(_ino->vfs_ino);
  1071.     vfs_ino->node.next = NULL;
  1072.     vfs_ino->node.prev = NULL;
  1073.     vfs_ino->device_id = device->device.id;
  1074.     vfs_ino->id = ino_id;
  1075.     vfs_ino->device = (fs_device_t *) device;
  1076.     vfs_ino->mount = NULL;
  1077.     vfs_ino->lock = semaphore_alloc();
  1078.     semaphore_up(vfs_ino->lock);
  1079.    
  1080.     vfs_ino->hard_link_count = (nlink_t) ino->link_count;
  1081.     vfs_ino->uid = (uid_t) ino->uid;
  1082.     vfs_ino->gid = (gid_t) ino->gid;
  1083.  
  1084.     vfs_ino->mode = (umode_t) (ino->mode & 0xFFF);
  1085.  
  1086.     switch (EXT2_MODE_FMT(ino->mode)) {
  1087.         case EXT2_IFBLK:
  1088.             vfs_ino->mode |= S_IFBLK;
  1089.             vfs_ino->if_dev = EXT2_DEV_DECODE(ino->block[0]);
  1090.             break;
  1091.         case EXT2_IFCHR:
  1092.             vfs_ino->mode |= S_IFCHR;
  1093.             vfs_ino->if_dev = EXT2_DEV_DECODE(ino->block[0]);
  1094.             break;
  1095.         case EXT2_IFDIR:
  1096.             vfs_ino->mode |= S_IFDIR;
  1097.             break;
  1098.         case EXT2_IFSOCK:
  1099.             vfs_ino->mode |= S_IFSOCK;
  1100.             break;
  1101.         case EXT2_IFIFO:
  1102.             vfs_ino->mode |= S_IFIFO;
  1103.             break;
  1104.         case EXT2_IFREG:
  1105.             vfs_ino->mode |= S_IFREG;
  1106.             break;
  1107.         case EXT2_IFLNK:
  1108.             vfs_ino->mode |= S_IFLNK;
  1109.             break;
  1110.         default:
  1111.             vfs_ino->mode |= S_IFREG;
  1112.             debugcon_printf("ext2: inode %i has invalid mode: %i", (uint32_t)ino_id, (uint32_t)ino->mode);
  1113.             break;
  1114.     }
  1115.     vfs_ino->usage_count = 0;
  1116.     vfs_ino->size = ino->size;
  1117.     vfs_ino->atime = (ktime_t) ino->atime;
  1118.     vfs_ino->ctime = (ktime_t) ino->ctime;
  1119.     vfs_ino->mtime = (ktime_t) ino->mtime;
  1120. }
  1121.  
  1122.  
  1123. void ext2_vfstoe2_inode(ext2_vinode_t *_ino, ino_t ino_id)
  1124. {
  1125.     ext2_inode_t *ino;
  1126.     inode_t *vfs_ino;
  1127.  
  1128.     ino = &(_ino->inode);
  1129.     vfs_ino = &(_ino->vfs_ino);
  1130.     //semaphore_down(vfs_ino->lock);
  1131.    
  1132.     ino->link_count = vfs_ino->hard_link_count;
  1133.     ino->uid = vfs_ino->uid;
  1134.     ino->gid = vfs_ino->gid;
  1135.  
  1136.     ino->mode = vfs_ino->mode & 0xFFF;
  1137.  
  1138.     switch (vfs_ino->mode & S_IFMT) {
  1139.         case S_IFBLK:
  1140.             ino->mode |= EXT2_IFBLK;
  1141.             ino->block[0] = EXT2_DEV_ENCODE(vfs_ino->if_dev);
  1142.             break;
  1143.         case S_IFCHR:
  1144.             ino->mode |= EXT2_IFCHR;
  1145.             ino->block[0] = EXT2_DEV_ENCODE(vfs_ino->if_dev);
  1146.             break;
  1147.         case S_IFDIR:
  1148.             ino->mode |= EXT2_IFDIR;
  1149.             break;
  1150.         case S_IFSOCK:
  1151.             ino->mode |= EXT2_IFSOCK;
  1152.             break;
  1153.         case S_IFIFO:
  1154.             ino->mode |= EXT2_IFIFO;
  1155.             break;
  1156.         case S_IFREG:
  1157.             ino->mode |= EXT2_IFREG;
  1158.             break;
  1159.         case S_IFLNK:
  1160.             ino->mode |= EXT2_IFLNK;
  1161.             break;
  1162.         default:
  1163.             ino->mode |= S_IFREG;
  1164.             debugcon_printf("ext2: vfs inode %i has invalid mode: %i", (uint32_t)ino_id, (uint32_t)ino->mode);
  1165.             break;
  1166.     }
  1167.  
  1168.     ino->size = vfs_ino->size;
  1169.     ino->atime = vfs_ino->atime;
  1170.     ino->ctime = vfs_ino->ctime;
  1171.     ino->mtime = vfs_ino->mtime;
  1172.  
  1173.     //semaphore_up(vfs_ino->lock);
  1174. }
  1175.  
  1176. inode_t *ext2_load_inode(fs_device_t *device, ino_t id) {
  1177.     ext2_vinode_t *ino;
  1178.     ext2_device_t *_dev = (ext2_device_t *) device;
  1179.  
  1180.     if (!_dev)
  1181.         return NULL;
  1182.  
  1183.     ino = heapmm_alloc(sizeof(ext2_vinode_t));
  1184.     if (!ino)
  1185.         return NULL;
  1186.  
  1187.     if(!ext2_load_e2inode(_dev, &(ino->inode), id))
  1188.         return NULL;
  1189.  
  1190.     ext2_e2tovfs_inode(_dev, ino, id);
  1191.  
  1192.     return (inode_t *) ino;
  1193. }
  1194.  
  1195. int ext2_store_inode(inode_t *_inode) {
  1196.     ext2_device_t *device;
  1197.     ext2_vinode_t *inode;
  1198.  
  1199.     if (!_inode) { 
  1200.         return EFAULT;
  1201.     }
  1202.  
  1203.     device = (ext2_device_t *) _inode->device;
  1204.     inode = (ext2_vinode_t *) _inode;
  1205.  
  1206.     ext2_vfstoe2_inode(inode, _inode->id);
  1207.  
  1208.     debugcon_printf("ext2: storing inode %i\n", _inode->id);
  1209.  
  1210.     return ext2_store_e2inode(device, &(inode->inode), _inode->id);
  1211. }
  1212.  
  1213. int ext2_mknod(inode_t *_inode) {
  1214.     ext2_device_t *device;
  1215.     ext2_vinode_t *inode;
  1216.  
  1217.     if (!_inode) { 
  1218.         return EFAULT;
  1219.     }
  1220.  
  1221.     device = (ext2_device_t *) _inode->device;
  1222.     inode = (ext2_vinode_t *) _inode;
  1223.  
  1224.     _inode->id = (ino_t) ext2_alloc_inode(device);
  1225.     if (_inode->id == EXT2_ENOSPC)
  1226.         return ENOSPC;
  1227.  
  1228.     memset(&(inode->inode), 0, sizeof(ext2_inode_t));
  1229.  
  1230.     ext2_vfstoe2_inode(inode, _inode->id);
  1231.  
  1232.     return ext2_store_e2inode(device, &(inode->inode), _inode->id);
  1233. }
  1234.  
  1235. int ext2_mkdir(inode_t *_inode) {
  1236.     ext2_block_group_desc_t *bgd;
  1237.     ext2_device_t *device;
  1238.     int st;
  1239.     if (!_inode) { 
  1240.         return EFAULT;
  1241.     }
  1242.  
  1243.     device = (ext2_device_t *) _inode->device;
  1244.  
  1245.     bgd = ext2_load_bgd(device, (_inode->id - 1) / device->superblock.inodes_per_group);
  1246.  
  1247.     assert(bgd != NULL);
  1248.  
  1249.     bgd->used_dir_count++;
  1250.    
  1251.     st = ext2_store_bgd(device, (_inode->id - 1) / device->superblock.inodes_per_group, bgd);
  1252.    
  1253.     ext2_free_bgd(device, bgd);
  1254.  
  1255.     return st;//TODO: Is this an error ?
  1256. }
  1257.  
  1258. fs_device_operations_t ext2_ops = {
  1259.     &ext2_load_inode,//Load inode
  1260.     &ext2_store_inode,//Store inode
  1261.     &ext2_mknod,//Make inode
  1262.     NULL,//Remove inode
  1263.     &ext2_read_inode,//Read from file
  1264.     &ext2_write_inode,//Write to file
  1265.     &ext2_readdir,//Read from directory
  1266.     &ext2_finddir,//Find directory entry
  1267.     &ext2_mkdir,//Make directory
  1268.     &ext2_link,//Make directory entry
  1269.     NULL,//Remove directory entry
  1270.     &ext2_trunc_inode //Change file length
  1271. };
  1272.  
  1273. fs_device_t *ext2_mount(dev_t device, uint32_t flags)
  1274. {
  1275.     int status;
  1276.     aoff_t  _read_size;
  1277.  
  1278.     ext2_device_t *dev = heapmm_alloc(sizeof(ext2_device_t));
  1279.    
  1280.     if (!dev)
  1281.         return NULL;
  1282.  
  1283.     dev->dev_id = device;  
  1284.     dev->device.id = device;
  1285.     dev->device.root_inode_id = EXT2_ROOT_INODE;
  1286.     dev->device.ops = &ext2_ops;
  1287.     dev->device.lock = semaphore_alloc();
  1288.     if(!dev->device.lock) {
  1289.         heapmm_free(dev, sizeof(ext2_device_t));
  1290.         return 0;
  1291.     }
  1292.     semaphore_up(dev->device.lock);
  1293.     dev->device.inode_size = sizeof(ext2_vinode_t);
  1294.  
  1295.     status = device_block_read(dev->dev_id, 1024, &(dev->superblock), 1024, &_read_size);
  1296.  
  1297.     //TODO: Implement fallback to alternative superblock
  1298.  
  1299.     if (_read_size != 1024) {
  1300.         debugcon_printf("ext2: could not read superblock, error:%i, read:%i!\n", status, _read_size);
  1301.         heapmm_free(dev, sizeof(ext2_device_t));
  1302.         return 0;
  1303.     }
  1304.  
  1305.     if (dev->superblock.signature != 0xEF53) {
  1306.         debugcon_printf("ext2: superblock signature incorrect: %i!\n", dev->superblock.signature);
  1307.         heapmm_free(dev, sizeof(ext2_device_t));
  1308.         return 0;
  1309.     }  
  1310.  
  1311.     if (dev->superblock.version_major == EXT2_VERSION_MAJOR_DYNAMIC) {
  1312.  
  1313.         if (dev->superblock.required_features & ~(EXT2_SUPPORTED_REQ_FEATURES)) {
  1314.             debugcon_printf("ext2: filesystem requires unsupported features, refusing to mount!\n");
  1315.             heapmm_free(dev, sizeof(ext2_device_t));
  1316.             return 0;
  1317.         }
  1318.  
  1319.         if (dev->superblock.ro_force_features & ~(EXT2_SUPPORTED_ROF_FEATURES)) {
  1320.             debugcon_printf("ext2: filesystem requires unsupported features, mounting read-only!\n");
  1321.             flags |= EXT2_MOUNT_FLAG_RO;
  1322.         }
  1323.  
  1324.         debugcon_printf("ext2: mounting %s\n", dev->superblock.volume_name);
  1325.  
  1326.     } else {
  1327.         dev->superblock.first_inode = EXT2_NO_EXT_FIRST_INO;
  1328.         dev->superblock.inode_size = EXT2_NO_EXT_INODE_SIZE;       
  1329.     }
  1330.  
  1331.     dev->inode_load_size = (sizeof(ext2_inode_t) > dev->superblock.inode_size) ?
  1332.                 dev->superblock.inode_size : sizeof(ext2_inode_t);
  1333.  
  1334.     dev->bgdt_block = dev->superblock.block_size_enc ? 1 : 2;
  1335.  
  1336.     return (fs_device_t *) dev;
  1337. }
  1338.  
  1339. int ext2_register()
  1340. {
  1341.     return vfs_register_fs("ext2", &ext2_mount);
  1342. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement