daily pastebin goal
63%
SHARE
TWEET

Broken ext2 driver

a guest Feb 1st, 2015 180 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  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. }
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top