Subversion Repositories Kolibri OS

Rev

Rev 4429 | Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2. ;;                                                              ;;
  3. ;; Contains ext2 inode handling code.                           ;;
  4. ;;                                                              ;;
  5. ;; Copyright (C) KolibriOS team 2013-2014. All rights reserved. ;;
  6. ;; Distributed under terms of the GNU General Public License    ;;
  7. ;;                                                              ;;
  8. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  9.  
  10. $Revision: 4891 $
  11.  
  12.  
  13. ;---------------------------------------------------------------------
  14. ; Receives block number from extent-based inode.
  15. ; Input:        ecx = number of block in inode
  16. ;               esi = address of extent header
  17. ;               ebp = pointer to EXTFS
  18. ; Output:       ecx = address of next block, if successful
  19. ;               eax = error code (0 implies no error)
  20. ;---------------------------------------------------------------------
  21. ext4_block_recursive_search:
  22.         cmp     word [esi + EXT4_EXTENT_HEADER.eh_magic], 0xF30A ;EXT4_EXT_MAGIC
  23.         jne     .fail
  24.        
  25.         movzx   ebx, [esi + EXT4_EXTENT_HEADER.eh_entries]
  26.         add     esi, sizeof.EXT4_EXTENT_HEADER
  27.         cmp     word [esi - sizeof.EXT4_EXTENT_HEADER + EXT4_EXTENT_HEADER.eh_depth], 0
  28.         je      .leaf_block     ;листовой ли это блок?
  29.        
  30.         ;не листовой блок, а индексный ; eax - ext4_extent_idx
  31.         test    ebx, ebx
  32.         jz      .fail               ;пустой индексный блок -> ошибка
  33.  
  34.         ;цикл по индексам экстентов
  35.     @@:
  36.         cmp     ebx, 1              ;у индексов не хранится длина,
  37.         je      .end_search_index   ;поэтому, если остался последний - то это нужный
  38.        
  39.         cmp     ecx, [esi + EXT4_EXTENT_IDX.ei_block]
  40.         jb      .fail
  41.        
  42.         cmp     ecx, [esi + sizeof.EXT4_EXTENT_IDX + EXT4_EXTENT_IDX.ei_block] ;блок слeдующего индекса
  43.         jb      .end_search_index ;следующий дальше - значит текущий, то что нам нужен
  44.        
  45.         add     esi, sizeof.EXT4_EXTENT_IDX
  46.         dec     ebx
  47.         jmp     @B
  48.  
  49.     .end_search_index:
  50.         ;ebp указывает на нужный extent_idx, считываем следующий блок
  51.         mov     ebx, [ebp + EXTFS.ext2_temp_block]
  52.         mov     eax, [esi + EXT4_EXTENT_IDX.ei_leaf_lo]
  53.         call    ext2_block_read
  54.         test    eax, eax
  55.         jnz     .fail
  56.         mov     esi, ebx
  57.         jmp     ext4_block_recursive_search ;рекурсивно прыгаем в начало
  58.        
  59.     .leaf_block:    ;листовой блок esi - ext4_extent
  60.         ;цикл по экстентам
  61.     @@:
  62.         test    ebx, ebx
  63.         jz      .fail       ;ни один узел не подошел - ошибка
  64.  
  65.         mov     edx, [esi + EXT4_EXTENT.ee_block]
  66.         cmp     ecx, edx
  67.         jb      .fail       ;если меньше, значит он был в предыдущих блоках -> ошибка
  68.  
  69.         movzx   edi, [esi + EXT4_EXTENT.ee_len]
  70.         add     edx, edi
  71.         cmp     ecx, edx
  72.         jb      .end_search_extent     ;нашли нужный блок
  73.        
  74.         add     esi, sizeof.EXT4_EXTENT
  75.         dec     ebx
  76.         jmp     @B
  77.        
  78.     .end_search_extent:
  79.         mov     edx, [esi + EXT4_EXTENT.ee_start_lo]
  80.         sub     ecx, [esi + EXT4_EXTENT.ee_block] ;разница в ext4 блоках
  81.         add     ecx, edx
  82.         xor     eax, eax
  83.         ret
  84.  
  85.     .fail:
  86.         mov     eax, ERROR_FS_FAIL
  87.         ret
  88.  
  89. ;---------------------------------------------------------------------
  90. ; Frees triply indirect block.
  91. ; Input:        eax = triply indirect block.
  92. ;               [ebp + EXTFS.ext2_save_inode] = the inode.
  93. ; Output:       eax = error code.
  94. ;---------------------------------------------------------------------
  95. ext2_inode_free_triply_indirect:
  96.         push    ebx edx
  97.  
  98.         test    eax, eax
  99.         jz      .success
  100.         push    eax
  101.         ; Read the triple indirect block.
  102.         mov     ebx, [ebp + EXTFS.ext2_temp_block]
  103.         call    ext2_block_read
  104.         test    eax, eax
  105.         pop     eax
  106.         jnz     .fail
  107.  
  108.         ; Free the triple indirect block.
  109.         call    ext2_block_free
  110.         test    eax, eax
  111.         jnz     .fail
  112.  
  113.         mov     edx, ebx
  114.         add     edx, [ebp + EXTFS.block_size]
  115.  
  116.     @@:
  117.         mov     eax, [ebx]
  118.         test    eax, eax
  119.         jz      .success
  120.  
  121.         call    ext2_inode_free_doubly_indirect
  122.         cmp     eax, 1
  123.         je      .success
  124.         cmp     eax, 0xFFFFFFFF
  125.         je      .fail
  126.  
  127.         add     ebx, 4
  128.         cmp     ebx, edx
  129.         jb      @B
  130.  
  131.     .success:
  132.         xor     eax, eax
  133.     .ret:
  134.         pop     edx ebx
  135.         ret
  136.  
  137.     .fail:
  138.         xor     eax, eax
  139.         not     eax
  140.         jmp     .ret
  141.  
  142. ;---------------------------------------------------------------------
  143. ; Frees double indirect block.
  144. ; Input:        eax = double indirect block.
  145. ;               [ebp + EXTFS.ext2_save_inode] = the inode.
  146. ; Output:       eax = error code, 1 implies finished, ~0 implies error
  147. ;---------------------------------------------------------------------
  148. ext2_inode_free_doubly_indirect:
  149.         push    ebx edx
  150.  
  151.         test    eax, eax
  152.         jz      .complete
  153.         push    eax
  154.         ; Read the double indirect block.
  155.         mov     ebx, [ebp + EXTFS.ext2_temp_block]
  156.         call    ext2_block_read
  157.         test    eax, eax
  158.         pop     eax
  159.         jnz     .fail
  160.  
  161.         call    ext2_block_free
  162.         test    eax, eax
  163.         jnz     .fail
  164.  
  165.         mov     edx, ebx
  166.         add     edx, [ebp + EXTFS.block_size]
  167.  
  168.     @@:
  169.         mov     eax, [ebx]
  170.         test    eax, eax
  171.         jz      .complete
  172.  
  173.         call    ext2_block_free
  174.         test    eax, eax
  175.         jnz     .fail
  176.  
  177.         add     ebx, 4
  178.         cmp     ebx, edx
  179.         jb      @B
  180.  
  181.     .success:
  182.         xor     eax, eax
  183.     .ret:
  184.         pop     edx ebx
  185.         ret
  186.  
  187.     .complete:
  188.         xor     eax, eax
  189.         inc     eax
  190.         jmp     .ret
  191.  
  192.     .fail:
  193.         xor     eax, eax
  194.         not     eax
  195.         jmp     .ret
  196.  
  197. ;---------------------------------------------------------------------
  198. ; Frees all indirect blocks.
  199. ; Input:        ebp = pointer to EXTFS.
  200. ;               [ebp + EXTFS.ext2_save_inode] = the inode.
  201. ; Output:       eax = error code (0 implies no error)
  202. ;---------------------------------------------------------------------
  203. ext2_inode_free_indirect_blocks:
  204.         push    edi
  205.  
  206.         mov     edi, [ebp + EXTFS.ext2_save_inode]
  207.  
  208.         ; Free indirect block.
  209.         mov     eax, [edi + EXT2_INODE_STRUC.i_block + 12*4]
  210.         test    eax, eax
  211.         jz      .success
  212.  
  213.         call    ext2_block_free
  214.         test    eax, eax
  215.         jnz     .fail
  216.  
  217.         mov     eax, [edi + EXT2_INODE_STRUC.i_block + 13*4]
  218.         call    ext2_inode_free_doubly_indirect
  219.         cmp     eax, 1
  220.         je      .success
  221.         cmp     eax, 0xFFFFFFFF
  222.         je      .fail
  223.  
  224.         mov     eax, [edi + EXT2_INODE_STRUC.i_block + 14*4]
  225.         call    ext2_inode_free_triply_indirect
  226.         test    eax, eax
  227.         jnz     .fail
  228.  
  229.     .success:
  230.         xor     eax, eax
  231.     .ret:
  232.         pop     edi
  233.         ret
  234.  
  235.     .fail:
  236.         xor     eax, eax
  237.         not     eax
  238.         jmp     .ret
  239.  
  240. ;---------------------------------------------------------------------
  241. ; Allocates block for inode.
  242. ; Input:        esi = address of inode
  243. ;               ebp = pointer to EXTFS.
  244. ; Output:       eax = error code (0 implies no error)
  245. ;---------------------------------------------------------------------
  246. ext2_inode_calloc_block:
  247.         push    ecx
  248.  
  249.         ; TODO: fix to have correct preference.
  250.         mov     eax, EXT2_ROOT_INO
  251.         call    ext2_block_calloc
  252.         test    eax, eax
  253.         jnz     .fail
  254.  
  255.         mov     ecx, [ebp + EXTFS.superblock + EXT2_SB_STRUC.log_block_size]
  256.         mov     eax, 2
  257.         shl     eax, cl
  258.         add     [esi + EXT2_INODE_STRUC.i_blocks], eax
  259.  
  260.     .success:
  261.         xor     eax, eax
  262.     .ret:
  263.         pop     ecx
  264.         ret
  265.  
  266.     .fail:
  267.         xor     eax, eax
  268.         not     eax
  269.         jmp     .ret
  270.  
  271. ;---------------------------------------------------------------------
  272. ; Sets block ID for indirect-addressing inode.
  273. ; Input:        ecx = index of block in inode
  274. ;               edi = block ID to set to
  275. ;               esi = address of inode
  276. ;               ebp = pointer to EXTFS.
  277. ; Output:       eax = error code (0 implies no error)
  278. ;---------------------------------------------------------------------
  279. ext2_inode_set_block:
  280.         push    ebx ecx edx
  281.  
  282.         ; 0 to 11: direct blocks.
  283.         cmp     ecx, 12
  284.         jb      .direct_block
  285.  
  286.         ; Indirect blocks
  287.         sub     ecx, 12
  288.         cmp     ecx, [ebp + EXTFS.count_pointer_in_block]
  289.         jb      .indirect_block
  290.  
  291.         ; Double indirect blocks.
  292.         sub     ecx, [ebp + EXTFS.count_pointer_in_block]
  293.         cmp     ecx, [ebp + EXTFS.count_pointer_in_block_square]
  294.         jb      .double_indirect_block
  295.  
  296.         ; Triple indirect blocks.
  297.         sub     ecx, [ebp + EXTFS.count_pointer_in_block_square]
  298.  
  299.         ; Get triply-indirect block in temp_block.
  300.         mov     eax, [esi + EXT2_INODE_STRUC.i_block + 14*4]
  301.         test    eax, eax
  302.         jnz     @F
  303.  
  304.         call    ext2_inode_calloc_block
  305.         test    eax, eax
  306.         jnz     .fail_alloc
  307.  
  308.         mov     [esi + EXT2_INODE_STRUC.i_block + 14*4], ebx
  309.         mov     eax, ebx
  310.  
  311.     @@:
  312.         push    eax
  313.         mov     ebx, [ebp + EXTFS.ext2_temp_block]
  314.         call    ext2_block_read
  315.         test    eax, eax
  316.         jnz     .fail_alloc_4
  317.  
  318.         ; Get index in triply-indirect block.
  319.         xor     edx, edx
  320.         mov     eax, ecx
  321.         div     [ebp + EXTFS.count_pointer_in_block_square]
  322.  
  323.         ; eax: index in triply-indirect block, edx: index in doubly-indirect block.
  324.         lea     ecx, [ebx + eax*4]
  325.         mov     eax, [ebx + eax*4]
  326.         test    eax, eax
  327.         jnz     @F
  328.  
  329.         call    ext2_inode_calloc_block
  330.         test    eax, eax
  331.         jnz     .fail_alloc_4
  332.  
  333.         mov     [ecx], ebx
  334.  
  335.         mov     eax, [esp]
  336.         mov     ebx, [ebp + EXTFS.ext2_temp_block]
  337.         call    ext2_block_write    
  338.         test    eax, eax
  339.         jnz     .fail_alloc_4
  340.  
  341.         mov     eax, [ecx]
  342.     @@:
  343.         mov     [esp], eax
  344.         call    ext2_block_read
  345.         test    eax, eax
  346.         jnz     .fail_alloc_4
  347.  
  348.         mov     eax, edx
  349.         jmp     @F
  350.  
  351.     .double_indirect_block:
  352.         ; Get doubly-indirect block.
  353.         mov     eax, [esi + EXT2_INODE_STRUC.i_block + 13*4]
  354.         test    eax, eax
  355.         jnz     .double_indirect_present
  356.  
  357.         call    ext2_inode_calloc_block
  358.         test    eax, eax
  359.         jnz     .fail_alloc
  360.  
  361.         mov     [esi + EXT2_INODE_STRUC.i_block + 13*4], ebx
  362.         mov     eax, ebx
  363.  
  364.     .double_indirect_present:
  365.         ; Save block we're at.
  366.         push    eax
  367.  
  368.         mov     ebx, [ebp + EXTFS.ext2_temp_block]
  369.         call    ext2_block_read
  370.         test    eax, eax
  371.         jnz     .fail_alloc_4
  372.  
  373.         mov     eax, ecx
  374.     @@:
  375.         xor     edx, edx
  376.         div     [ebp + EXTFS.count_pointer_in_block]
  377.  
  378.         ; eax: index in doubly-indirect block, edx: index in indirect block.
  379.         lea     ecx, [ebx + edx*4]
  380.         push    ecx
  381.  
  382.         lea     ecx, [ebx + eax*4]
  383.         cmp     dword[ecx], 0
  384.         jne     @F
  385.  
  386.         call    ext2_inode_calloc_block
  387.         test    eax, eax
  388.         jnz     .fail_alloc_8
  389.  
  390.         mov     [ecx], ebx
  391.  
  392.         mov     eax, [esp + 4]
  393.         mov     ebx, [ebp + EXTFS.ext2_temp_block]
  394.         call    ext2_block_write    
  395.         test    eax, eax
  396.         jnz     .fail_alloc_8      
  397.  
  398.     @@:
  399.         mov     eax, [ecx]
  400.         push    eax
  401.         call    ext2_block_read
  402.         test    eax, eax
  403.         jnz     .fail_alloc_12
  404.  
  405.         pop     eax
  406.         pop     ecx
  407.         mov     [ecx], edi
  408.         call    ext2_block_write
  409.  
  410.         add     esp, 4
  411.         jmp     .return
  412.  
  413.     .indirect_block:
  414.         ; Get index of indirect block.
  415.         mov     eax, [esi + EXT2_INODE_STRUC.i_block + 12*4]
  416.         test    eax, eax
  417.         jnz     @F
  418.  
  419.         call    ext2_inode_calloc_block
  420.         test    eax, eax
  421.         jnz     .fail_alloc
  422.        
  423.         mov     [esi + EXT2_INODE_STRUC.i_block + 12*4], ebx
  424.         mov     eax, ebx
  425.    
  426.     @@:
  427.         push    eax
  428.         mov     ebx, [ebp + EXTFS.ext2_temp_block]
  429.         call    ext2_block_read
  430.         test    eax, eax
  431.         jnz     .fail_alloc_4
  432.        
  433.         ; Get the block ID.
  434.         mov     [ebx + ecx*4], edi
  435.         pop     eax
  436.         call    ext2_block_write
  437.         jmp     .return
  438.  
  439.     .direct_block:
  440.         mov     [esi + EXT2_INODE_STRUC.i_block + ecx*4], edi
  441.         xor     eax, eax
  442.  
  443.     .return:
  444.         pop     edx ecx ebx
  445.         ret
  446.  
  447.     .fail_alloc:
  448.         xor     eax, eax
  449.         not     eax
  450.         jmp     .return
  451.  
  452.     .fail_alloc_12:
  453.         add     esp, 4
  454.     .fail_alloc_8:
  455.         add     esp, 4
  456.     .fail_alloc_4:
  457.         add     esp, 4
  458.         jmp     .fail_alloc
  459.  
  460. ;---------------------------------------------------------------------
  461. ; Receives block ID from indirect-addressing inode.
  462. ; Input:        ecx = index of block in inode
  463. ;               esi = address of inode
  464. ;               ebp = pointer to EXTFS
  465. ; Output:       ecx = block ID, if successful
  466. ;               eax = error code (0 implies no error)
  467. ;---------------------------------------------------------------------
  468. ext2_inode_get_block:
  469.         ; If inode is extent-based, use ext4_block_recursive_search.
  470.         test    [esi + EXT2_INODE_STRUC.i_flags], EXT2_EXTENTS_FL
  471.         jz      @F
  472.  
  473.         pushad
  474.  
  475.         ; Get extent header in EBP.
  476.         add     esi, EXT2_INODE_STRUC.i_block
  477.         call    ext4_block_recursive_search
  478.         mov     PUSHAD_ECX, ecx
  479.         mov     PUSHAD_EAX, eax
  480.  
  481.         popad
  482.         ret
  483.  
  484.     @@:
  485.         ; 0 to 11: direct blocks.
  486.         cmp     ecx, 12
  487.         jb      .get_direct_block
  488.  
  489.         ; Indirect blocks
  490.         sub     ecx, 12
  491.         cmp     ecx, [ebp + EXTFS.count_pointer_in_block]
  492.         jb      .get_indirect_block
  493.  
  494.         ; Double indirect blocks.
  495.         sub     ecx, [ebp + EXTFS.count_pointer_in_block]
  496.         cmp     ecx, [ebp + EXTFS.count_pointer_in_block_square]
  497.         jb      .get_double_indirect_block
  498.  
  499.         ; Triple indirect blocks.
  500.         sub     ecx, [ebp + EXTFS.count_pointer_in_block_square]
  501.         push    edx ebx
  502.  
  503.         ; Get triply-indirect block in temp_block.
  504.         mov     eax, [esi + EXT2_INODE_STRUC.i_block + 14*4]
  505.         mov     ebx, [ebp + EXTFS.ext2_temp_block]
  506.         call    ext2_block_read
  507.         test    eax, eax
  508.         jnz     .fail
  509.  
  510.         ; Get index in triply-indirect block.
  511.         xor     edx, edx
  512.         mov     eax, ecx
  513.         div     [ebp + EXTFS.count_pointer_in_block_square]
  514.  
  515.         ; eax: index in triply-indirect block, edx: index in doubly-indirect block.
  516.         mov     eax, [ebx + eax*4]
  517.         test    eax, eax
  518.         jz      .fail_triple_indirect_block
  519.  
  520.         call    ext2_block_read
  521.         test    eax, eax
  522.         jnz     .fail
  523.  
  524.         mov     eax, edx
  525.         jmp     @F
  526.  
  527.     .get_double_indirect_block:
  528.         push    edx ebx
  529.  
  530.         ; Get doubly-indirect block.
  531.         mov     eax, [esi + EXT2_INODE_STRUC.i_block + 13*4]
  532.         test    eax, eax
  533.         jz      .fail_double_indirect_block
  534.  
  535.         mov     ebx, [ebp + EXTFS.ext2_temp_block]
  536.         call    ext2_block_read
  537.         test    eax, eax
  538.         jnz     .fail
  539.  
  540.         mov     eax, ecx
  541.     @@:
  542.         xor     edx, edx
  543.         div     [ebp + EXTFS.count_pointer_in_block]
  544.  
  545.         ; eax: index in doubly-indirect block, edx: index in indirect block.
  546.         mov     eax, [ebx + eax*4]
  547.         test    eax, eax
  548.         jz      .fail_double_indirect_block
  549.  
  550.         call    ext2_block_read
  551.         test    eax, eax
  552.         jnz     .fail
  553.  
  554.         mov     ecx, [ebx + edx*4]
  555.     .fail:
  556.         pop     ebx edx
  557.  
  558.         ret
  559.  
  560.     .get_indirect_block:
  561.         push    ebx
  562.  
  563.         ; Get index of indirect block.
  564.         mov     eax, [esi + EXT2_INODE_STRUC.i_block + 12*4]
  565.         test    eax, eax
  566.         jz      .fail_indirect_block
  567.  
  568.         mov     ebx, [ebp + EXTFS.ext2_temp_block]
  569.         call    ext2_block_read
  570.         test    eax, eax
  571.         jnz     @F
  572.        
  573.         mov     ecx, [ebx + ecx*4]
  574.     @@:
  575.         pop     ebx
  576.  
  577.         ret
  578.  
  579.     .get_direct_block:
  580.         mov     ecx, [esi + EXT2_INODE_STRUC.i_block + ecx*4]
  581.         xor     eax, eax
  582.  
  583.         ret
  584.  
  585.     .fail_indirect_block:
  586.         pop     ebx
  587.  
  588.     .fail_triple_indirect_block:
  589.         xor     eax, eax
  590.         xor     ecx, ecx
  591.         ret
  592.  
  593.     .fail_double_indirect_block:
  594.         pop     ebx edx
  595.         jmp     .fail_triple_indirect_block
  596.  
  597. ;---------------------------------------------------------------------
  598. ; Get block containing inode.
  599. ; Input:        eax = inode number.
  600. ;               ebp = pointer to EXTFS.
  601. ; Output:       ebx = block (hard disk) containing inode.
  602. ;               edx = index inside block.
  603. ;               eax = error code (0 implies no error)
  604. ;---------------------------------------------------------------------
  605. ext2_read_block_of_inode:
  606.         pushad
  607.  
  608.         dec     eax
  609.         xor     edx, edx
  610.        
  611.         ; EAX = block group.
  612.         div     [ebp + EXTFS.superblock + EXT2_SB_STRUC.inodes_per_group]
  613.  
  614.         push    edx                             ; Index in group.
  615.  
  616.         mov     edx, 32
  617.         mul     edx                             ; Get index of descriptor in global_desc_table.
  618.  
  619.         ; eax: inode group offset relative to global descriptor table start
  620.         ; Find the block this block descriptor is in.
  621.         div     [ebp + EXTFS.block_size]
  622.         add     eax, [ebp + EXTFS.superblock + EXT2_SB_STRUC.first_data_block]
  623.         inc     eax
  624.         mov     ebx, [ebp + EXTFS.ext2_temp_block]
  625.         call    ext2_block_read
  626.         test    eax, eax
  627.         jnz     .return    
  628.  
  629.         add     ebx, edx                        ; edx: local index of descriptor inside block
  630.         mov     eax, [ebx + EXT2_BLOCK_GROUP_DESC.inode_table]   ; Block number of inode table - in ext2 terms.
  631.         mov     ecx, [ebp + EXTFS.log_block_size]
  632.         shl     eax, cl
  633.  
  634.         ; eax: points to inode table on HDD.
  635.         mov     esi, eax
  636.  
  637.         ; Add local address of inode.
  638.         pop     eax
  639.         mov     ecx, [ebp + EXTFS.inode_size]
  640.         mul     ecx                             ; (index * inode_size)
  641.  
  642.         mov     ebp, 512
  643.         div     ebp                             ; Divide by hard disk block size.
  644.  
  645.         add     eax, esi                        ; Found block to read.
  646.         mov     ebx, eax                        ; Get it inside ebx.
  647.  
  648.         xor     eax, eax
  649.     .return:
  650.         mov     PUSHAD_EAX, eax
  651.         mov     PUSHAD_EBX, ebx
  652.         mov     PUSHAD_EDX, edx
  653.  
  654.         popad
  655.         ret
  656.  
  657. ;---------------------------------------------------------------------
  658. ; Sets content of inode by number.
  659. ; Input:        eax = inode number.
  660. ;               ebx = address from where to write inode content.
  661. ;               ebp = pointer to EXTFS.
  662. ; Output:       eax = error code (0 implies no error)
  663. ;---------------------------------------------------------------------
  664. ext2_inode_write:
  665.         push    edx edi esi ecx ebx
  666.         mov     esi, ebx
  667.  
  668.         ; Ext2 actually stores time of modification of inode in ctime.
  669.         lea     edi, [ebx + EXT2_INODE_STRUC.i_ctime]
  670.         call    current_unix_time
  671.  
  672.         ; Get block where inode is situated.
  673.         call    ext2_read_block_of_inode
  674.         test    eax, eax
  675.         jnz     .error
  676.  
  677.         mov     eax, ebx                        ; Get block into EAX.
  678.         mov     ebx, [ebp + EXTFS.ext2_temp_block]
  679.  
  680.         mov     ecx, eax                        ; Save block.    
  681.         call    fs_read32_sys
  682.         test    eax, eax
  683.         jz      @F
  684.  
  685.     .error:
  686.         mov     eax, ERROR_DEVICE
  687.         jmp     .return
  688.  
  689.     @@:
  690.         mov     eax, ecx
  691.         mov     ecx, [ebp + EXTFS.inode_size]
  692.         mov     edi, edx                        ; The index into the block.
  693.         add     edi, ebx
  694.         rep movsb
  695.  
  696.         ; Write the block.
  697.         call    fs_write32_sys
  698.  
  699.     .return:
  700.         pop     ebx ecx esi edi edx
  701.         ret
  702.  
  703. ;---------------------------------------------------------------------
  704. ; Get content of inode by number.
  705. ; Input:        eax = inode number.
  706. ;               ebx = address where to store inode content.
  707. ;               ebp = pointer to EXTFS.
  708. ; Output:       eax = error code (0 implies no error)
  709. ;---------------------------------------------------------------------
  710. ext2_inode_read:
  711.         push    edx edi esi ecx ebx
  712.         mov     edi, ebx
  713.  
  714.         ; Get block where inode is situated.
  715.         call    ext2_read_block_of_inode
  716.         test    eax, eax
  717.         jnz     .error
  718.  
  719.         mov     eax, ebx                        ; Get block into EAX.
  720.         mov     ebx, [ebp + EXTFS.ext2_temp_block]
  721.         call    fs_read32_sys
  722.         test    eax, eax
  723.         jz      @F
  724.  
  725.     .error:
  726.         mov     eax, ERROR_DEVICE
  727.         jmp     .return
  728.  
  729.     @@:
  730.         mov     ecx, [ebp + EXTFS.inode_size]
  731.         mov     esi, edx                        ; The index into the inode.
  732.         add     esi, ebx
  733.         rep movsb
  734.  
  735.         xor     eax, eax
  736.     .return:
  737.         pop     ebx ecx esi edi edx
  738.         ret
  739.  
  740. ;---------------------------------------------------------------------
  741. ; Seek inode from the path.
  742. ; Input:        esi + [esp + 4] = name.
  743. ;               ebp = pointer to EXTFS.
  744. ; Output:       eax = error code (0 implies no error)
  745. ;               esi = inode number.
  746. ;                dl = first byte of file/folder name.
  747. ;                     [ext2_data.ext2_save_inode] stores the inode.
  748. ;---------------------------------------------------------------------
  749. ext2_inode_find:
  750.         mov     edx, [ebp + EXTFS.root_inode]
  751.  
  752.         ; Check for empty root.
  753.         cmp     [edx + EXT2_INODE_STRUC.i_blocks], 0
  754.         je      .error_empty_root
  755.  
  756.         ; Check for root.
  757.         cmp     byte[esi], 0
  758.         jne     .next_path_part
  759.  
  760.         push    edi ecx
  761.         mov     esi, [ebp + EXTFS.root_inode]
  762.         mov     edi, [ebp + EXTFS.ext2_save_inode]
  763.         mov     ecx, [ebp + EXTFS.inode_size]
  764.         rep movsb
  765.         pop     ecx edi
  766.  
  767.         xor     eax, eax
  768.         xor     dl, dl
  769.         mov     esi, EXT2_ROOT_INO
  770.         ret     4
  771.    
  772.     .next_path_part:
  773.         push    [edx + EXT2_INODE_STRUC.i_blocks]
  774.         xor     ecx, ecx
  775.  
  776.     .folder_block_cycle:
  777.         push    ecx
  778.         xchg    esi, edx
  779.         call    ext2_inode_get_block
  780.         xchg    esi, edx
  781.         test    eax, eax
  782.         jnz     .error_get_inode_block
  783.        
  784.         mov     eax, ecx
  785.         mov     ebx, [ebp + EXTFS.ext2_save_block]              ; Get directory records from directory.
  786.         call    ext2_block_read
  787.         test    eax, eax
  788.         jnz     .error_get_block
  789.        
  790.         push    esi
  791.         push    edx
  792.         call    ext2_block_find_parent
  793.         pop     edx
  794.         pop     edi ecx
  795.  
  796.         cmp     edi, esi                                        ; Did something match?
  797.         je      .next_folder_block                              ; No, move to next block.
  798.        
  799.         cmp     byte [esi], 0                                   ; Reached the "end" of path successfully.
  800.         jnz     @F
  801.         cmp     dword[esp + 8], 0
  802.         je      .get_inode_ret
  803.         mov     esi, [esp + 8]
  804.         mov     dword[esp + 8], 0
  805.  
  806.     @@:
  807.         mov     eax, [ebx + EXT2_DIR_STRUC.inode]
  808.         mov     ebx, [ebp + EXTFS.ext2_save_inode]
  809.         call    ext2_inode_read
  810.         test    eax, eax
  811.         jnz     .error_get_inode
  812.  
  813.         movzx   eax, [ebx + EXT2_INODE_STRUC.i_mode]
  814.         and     eax, EXT2_S_IFMT                                ; Get the mask.
  815.         cmp     eax, EXT2_S_IFDIR
  816.         jne     .not_found                                      ; Matched till part, but directory entry we got doesn't point to folder.
  817.  
  818.         pop     ecx                                             ; Stack top contains number of blocks.
  819.         mov     edx, ebx
  820.         jmp     .next_path_part
  821.        
  822.     .next_folder_block:
  823.         ; Next block in current folder.
  824.         pop     eax                                             ; Get blocks counter.
  825.         sub     eax, [ebp + EXTFS.count_block_in_block]
  826.         jle     .not_found
  827.        
  828.         push    eax
  829.         inc     ecx
  830.         jmp     .folder_block_cycle
  831.  
  832.     .not_found:
  833.         mov     eax, ERROR_FILE_NOT_FOUND
  834.         ret     4
  835.  
  836.     .get_inode_ret:
  837.         pop     ecx                                             ; Stack top contains number of blocks.
  838.  
  839.         mov     dl, [ebx + EXT2_DIR_STRUC.name]                 ; First character of file-name.
  840.         mov     eax, [ebx + EXT2_DIR_STRUC.inode]
  841.         mov     ebx, [ebp + EXTFS.ext2_save_inode]
  842.         mov     esi, eax
  843.  
  844.         ; If we can't get the inode, eax contains the error.        
  845.         call    ext2_inode_read
  846.         ret     4
  847.  
  848.     .error_get_inode_block:
  849.     .error_get_block:
  850.         pop     ecx
  851.     .error_get_inode:
  852.         pop     ebx
  853.     .error_empty_root:
  854.         mov     eax, ERROR_FS_FAIL
  855.         ret     4
  856.  
  857. ;---------------------------------------------------------------------
  858. ; Seeks parent inode from path.
  859. ; Input:        esi = path.
  860. ;               ebp = pointer to EXTFS.
  861. ; Output:       eax = error code.
  862. ;               esi = inode.
  863. ;               edi = pointer to file name.
  864. ;---------------------------------------------------------------------
  865. ext2_inode_find_parent:
  866.         push    esi
  867.         xor     edi, edi  
  868.  
  869.     .loop:
  870.         cmp     byte[esi], '/'
  871.         jne     @F
  872.  
  873.         mov     edi, esi
  874.         inc     esi
  875.         jmp     .loop
  876.  
  877.     @@:
  878.         inc     esi
  879.         cmp     byte[esi - 1], 0
  880.         jne     .loop
  881.  
  882.         ; If it was just a filename (without any additional directories),
  883.         ; use the last byte as "parent path".
  884.         cmp     edi, 0
  885.         jne     @F
  886.  
  887.         pop     edi
  888.         dec     esi
  889.         jmp     .get_inode
  890.  
  891.         ; It had some additional directories, so handle it that way.
  892.     @@:
  893.         mov     byte[edi], 0
  894.         inc     edi
  895.         pop     esi
  896.  
  897.     .get_inode:
  898.         push    ebx edx
  899.         stdcall ext2_inode_find, 0
  900.         pop     edx ebx
  901.  
  902.     .return:
  903.         ret
  904.  
  905. ;---------------------------------------------------------------------
  906. ; Link an inode.
  907. ; Input:        eax = inode on which to link.
  908. ;               ebx = inode to link.
  909. ;                dl = file type.
  910. ;               esi = name.
  911. ;               ebp = pointer to EXTFS.
  912. ; Output:       eax = error code.
  913. ;---------------------------------------------------------------------
  914. ext2_inode_link:
  915.         push    eax
  916.         push    esi edi ebx ecx edx
  917.  
  918.         ; Get string length, and then directory entry structure size.
  919.         call    strlen
  920.         add     ecx, 8
  921.  
  922.         push    esi ebx ecx
  923.  
  924.         xor     ecx, ecx
  925.         mov     esi, [ebp + EXTFS.ext2_temp_inode]
  926.         mov     ebx, esi
  927.  
  928.         call    ext2_inode_read
  929.         test    eax, eax
  930.         jnz     .error_inode_read
  931.  
  932.         ; Get the maximum addressible i_block index by (i_blocks/(2 << s_log_block_size)).
  933.         ; Note that i_blocks contains number of reserved 512B blocks, which is why we've to
  934.         ; find out the ext2 blocks.
  935.         mov     eax, 2
  936.         mov     ecx, [ebp + EXTFS.superblock + EXT2_SB_STRUC.log_block_size]
  937.         shl     eax, cl
  938.         mov     ecx, eax
  939.  
  940.         mov     eax, [esi + EXT2_INODE_STRUC.i_blocks]
  941.         xor     edx, edx
  942.  
  943.         div     ecx
  944.  
  945.         ; EAX is the maximum index inside i_block we can go.
  946.         push    eax
  947.         push    dword 0
  948.  
  949.         ; ECX contains the "block inside i_block" index.
  950.         xor     ecx, ecx
  951.     @@:
  952.         call    ext2_inode_get_block
  953.         test    eax, eax
  954.         jnz     .error_get_inode_block
  955.         test    ecx, ecx
  956.         jz      .alloc_block        ; We've got no block here, so allocate one.
  957.  
  958.         push    ecx                 ; Save block number.
  959.  
  960.         mov     eax, ecx
  961.         mov     ebx, [ebp + EXTFS.ext2_temp_block]
  962.         call    ext2_block_read
  963.         test    eax, eax
  964.         jnz     .error_block_read
  965.  
  966.         ; Try to find free space in current block.
  967.         mov     ecx, [esp + 8]
  968.         call    ext2_block_find_fspace
  969.         test    eax, eax
  970.         jz      .found
  971.  
  972.         cmp     eax, 0x00000001
  973.         jne     .next_iter
  974.  
  975.         ; This block wasn't linking to the next block, so fix that, and use the next one.
  976.         ; Write the block.
  977.         pop     eax
  978.         mov     ebx, [ebp + EXTFS.ext2_temp_block]
  979.         call    ext2_block_write    
  980.         test    eax, eax
  981.         jnz     .error_get_inode_block
  982.  
  983.         inc     dword [esp]
  984.         mov     ecx, [esp]
  985.         call    ext2_inode_get_block
  986.         test    eax, eax
  987.         jnz     .error_get_inode_block
  988.  
  989.         test    ecx, ecx
  990.         jz      .alloc_block
  991.  
  992.         ; If there was a block there, prepare it for our use!
  993.         push    ecx
  994.         jmp     .prepare_block
  995.  
  996.     .next_iter:
  997.         add     esp, 4
  998.  
  999.         inc     dword [esp]
  1000.         mov     ecx, [esp]
  1001.         cmp     ecx, [esp + 4]
  1002.         jbe     @B      
  1003.  
  1004.     .alloc_block:
  1005.         mov     eax, [esp + 12]     ; Get inode ID of what we're linking.
  1006.         call    ext2_block_calloc
  1007.         test    eax, eax
  1008.         jnz     .error_get_inode_block
  1009.  
  1010.         mov     ecx, [esp]          ; Get the index of it inside the inode.
  1011.         mov     edi, ebx            ; And what to set to.
  1012.         call    ext2_inode_set_block
  1013.         test    eax, eax
  1014.         jnz     .error_get_inode_block
  1015.  
  1016.         ; Update i_size.
  1017.         mov     eax, [ebp + EXTFS.block_size]
  1018.         add     [esi + EXT2_INODE_STRUC.i_size], eax
  1019.  
  1020.         ; Update i_blocks.
  1021.         mov     ecx, [ebp + EXTFS.superblock + EXT2_SB_STRUC.log_block_size]
  1022.         mov     eax, 2
  1023.         shl     eax, cl
  1024.         add     [esi + EXT2_INODE_STRUC.i_blocks], eax
  1025.  
  1026.         ; Write the inode.
  1027.         mov     eax, [esp + 40]
  1028.         mov     ebx, esi
  1029.         call    ext2_inode_write
  1030.         test    eax, eax
  1031.         jnz     .error_get_inode_block
  1032.  
  1033.         push    edi                 ; Save the block we just allocated.
  1034.  
  1035.     ; If we've allocated/using-old-block outside of loop, prepare it.
  1036.     .prepare_block:
  1037.         mov     eax, [esp]
  1038.         mov     ebx, [ebp + EXTFS.ext2_temp_block]
  1039.         call    ext2_block_read
  1040.         test    eax, eax
  1041.         jnz     .error_block_read
  1042.  
  1043.         mov     edi, ebx
  1044.         mov     eax, [ebp + EXTFS.block_size]
  1045.         mov     [edi + EXT2_DIR_STRUC.rec_len], ax
  1046.  
  1047.     .found:
  1048.         pop     edx
  1049.         add     esp, 8
  1050.         pop     ecx ebx esi
  1051.  
  1052.         push    ebx
  1053.         mov     [edi], ebx          ; Save inode.
  1054.  
  1055.         mov     eax, [esp + 4]      ; Get EDX off the stack -- contains the file_type.
  1056.         cmp     [ebp + EXTFS.superblock + EXT2_SB_STRUC.rev_level], EXT2_GOOD_OLD_REV
  1057.         je      .name
  1058.  
  1059.         ; Set the file-type.
  1060.         mov     [edi + EXT2_DIR_STRUC.file_type], al
  1061.  
  1062.     .name:
  1063.         ; Save name.
  1064.         sub     ecx, 8
  1065.         mov     [edi + EXT2_DIR_STRUC.name_len], cl
  1066.         add     edi, 8
  1067.         rep movsb
  1068.  
  1069.         ; Write block.
  1070.         mov     eax, edx
  1071.         mov     ebx, [ebp + EXTFS.ext2_temp_block]
  1072.         call    ext2_block_write
  1073.         test    eax, eax
  1074.         jnz     .error_block_write
  1075.  
  1076.         mov     eax, [esp]
  1077.         mov     ebx, [ebp + EXTFS.ext2_temp_inode]
  1078.         call    ext2_inode_read
  1079.         test    eax, eax
  1080.         jnz     .error_block_write
  1081.  
  1082.         pop     eax
  1083.         inc     [ebx + EXT2_INODE_STRUC.i_links_count]
  1084.         call    ext2_inode_write
  1085.         test    eax, eax
  1086.         jnz     .error
  1087.  
  1088.         xor     eax, eax
  1089.     .ret:
  1090.         pop     edx ecx ebx edi esi
  1091.         add     esp, 4
  1092.         ret
  1093.  
  1094.     .error_block_read:
  1095.         add     esp, 4
  1096.     .error_get_inode_block:
  1097.         add     esp, 8
  1098.     .error_inode_read:
  1099.         add     esp, 8
  1100.     .error_block_write:
  1101.         add     esp, 4
  1102.     .error:
  1103.         xor     eax, eax
  1104.         not     eax
  1105.         jmp     .ret
  1106.  
  1107. ;---------------------------------------------------------------------
  1108. ; Unlink an inode.
  1109. ; Input:        eax = inode from which to unlink.
  1110. ;               ebx = inode to unlink.
  1111. ;               ebp = pointer to EXTFS.
  1112. ; Output:       eax = number of links to inode, after unlinking (0xFFFFFFFF implies error)
  1113. ;---------------------------------------------------------------------
  1114. ext2_inode_unlink:
  1115.         push    ebx ecx edx esi edi
  1116.  
  1117.         push    ebx
  1118.         mov     ebx, [ebp + EXTFS.ext2_temp_inode]
  1119.         call    ext2_inode_read
  1120.  
  1121.         test    eax, eax
  1122.         jnz     .fail_get_inode
  1123.  
  1124.         ; The index into the inode block data.
  1125.         push    dword 0
  1126.         mov     esi, [ebp + EXTFS.ext2_temp_inode]
  1127.        
  1128.     .loop:
  1129.         mov     ecx, [esp]
  1130.         call    ext2_inode_get_block
  1131.  
  1132.         test    eax, eax
  1133.         jnz     .fail_loop
  1134.         test    ecx, ecx
  1135.         jz      .fail_loop
  1136.  
  1137.         mov     eax, ecx
  1138.         mov     edi, eax
  1139.         mov     ebx, [ebp + EXTFS.ext2_temp_block]
  1140.         call    ext2_block_read
  1141.         test    eax, eax
  1142.         jnz     .fail_loop
  1143.  
  1144.     ; edi -> block.
  1145.     .first_dir_entry:
  1146.         mov     eax, [esp + 4]
  1147.         cmp     [ebx], eax
  1148.         jne     @F
  1149.  
  1150.         mov     dword[ebx], 0                               ; inode.
  1151.         mov     word[ebx + 6], 0                            ; name_len + file_type.
  1152.         jmp     .write_block
  1153.  
  1154.     @@:
  1155.         mov     edx, ebx
  1156.         add     edx, [ebp + EXTFS.block_size]
  1157.         push    edx
  1158.  
  1159.         mov     edx, ebx
  1160.         movzx   ecx, [ebx + EXT2_DIR_STRUC.rec_len]
  1161.         add     ebx, ecx
  1162.  
  1163.     .dir_entry:
  1164.         cmp     [ebx], eax
  1165.         jne     @F
  1166.  
  1167.         mov     cx, [ebx + EXT2_DIR_STRUC.rec_len]
  1168.         add     [edx + EXT2_DIR_STRUC.rec_len], cx
  1169.         add     esp, 4
  1170.         jmp     .write_block
  1171.  
  1172.     @@:
  1173.         mov     edx, ebx
  1174.         movzx   ecx, [ebx + EXT2_DIR_STRUC.rec_len]
  1175.        
  1176.         ; If it's a zero length entry, error.
  1177.         test    ecx, ecx
  1178.         jz      .fail_inode
  1179.  
  1180.         add     ebx, ecx
  1181.  
  1182.         cmp     ebx, [esp]
  1183.         jb      .dir_entry
  1184.  
  1185.         add     esp, 4
  1186.         inc     dword[esp]
  1187.         jmp     .loop
  1188.  
  1189.     .write_block:
  1190.         mov     eax, edi
  1191.         mov     ebx, [ebp + EXTFS.ext2_temp_block]
  1192.         call    ext2_block_write
  1193.         test    eax, eax
  1194.         jnz     .fail_loop
  1195.  
  1196.         add     esp, 4
  1197.         mov     ebx, [ebp + EXTFS.ext2_temp_inode]
  1198.         mov     eax, [esp]
  1199.         call    ext2_inode_read
  1200.         test    eax, eax
  1201.         jnz     .fail_get_inode
  1202.  
  1203.         dec     word[ebx + EXT2_INODE_STRUC.i_links_count]
  1204.         movzx   eax, word[ebx + EXT2_INODE_STRUC.i_links_count]
  1205.         push    eax
  1206.  
  1207.         mov     eax, [esp + 4]
  1208.         call    ext2_inode_write
  1209.         test    eax, eax
  1210.         jnz     .fail_loop
  1211.  
  1212.         pop     eax
  1213.         add     esp, 4
  1214.     .return:
  1215.         pop     edi esi edx ecx ebx
  1216.         ret
  1217.  
  1218.     .fail_inode:
  1219.         add     esp, 4
  1220.  
  1221.     .fail_loop:
  1222.         add     esp, 4
  1223.  
  1224.     .fail_get_inode:
  1225.         add     esp, 4
  1226.  
  1227.     .fail:
  1228.         xor     eax, eax
  1229.         not     eax
  1230.         jmp     .return
  1231.  
  1232. ;---------------------------------------------------------------------
  1233. ; Checks if a directory is empty.
  1234. ; Input:        ebx = inode to check.
  1235. ;               ebp = pointer to EXTFS.
  1236. ;               [EXTFS.ext2_save_inode] = points to saved inode.
  1237. ; Output:       eax = 0 signifies empty directory.
  1238. ;---------------------------------------------------------------------
  1239. ext2_dir_empty:
  1240.         push    ebx ecx edx
  1241.        
  1242.         ; The index into the inode block data.
  1243.         push    dword 0
  1244.         mov     esi, [ebp + EXTFS.ext2_save_inode]
  1245.        
  1246.     .loop:
  1247.         mov     ecx, [esp]
  1248.         call    ext2_inode_get_block
  1249.  
  1250.         ; Treat a failure as not-empty.
  1251.         test    eax, eax
  1252.         jnz     .not_empty
  1253.         test    ecx, ecx
  1254.         jz      .empty
  1255.  
  1256.         mov     eax, ecx
  1257.         mov     ebx, [ebp + EXTFS.ext2_temp_block]
  1258.         call    ext2_block_read
  1259.         test    eax, eax
  1260.         jnz     .not_empty
  1261.  
  1262.         mov     edx, ebx
  1263.         add     edx, [ebp + EXTFS.block_size]
  1264.  
  1265.         movzx   ecx, [ebx + EXT2_DIR_STRUC.rec_len]
  1266.         add     ebx, ecx
  1267.  
  1268.     .dir_entry:
  1269.         ; Process entry.
  1270.         cmp     byte[ebx + EXT2_DIR_STRUC.name_len], 1
  1271.         jne     @F
  1272.  
  1273.         cmp     byte[ebx + EXT2_DIR_STRUC.name], '.'
  1274.         jne     .not_empty
  1275.  
  1276.     @@:
  1277.         cmp     byte[ebx + EXT2_DIR_STRUC.name_len], 2
  1278.         jne     .not_empty
  1279.  
  1280.         cmp     word[ebx + EXT2_DIR_STRUC.name], '..'
  1281.         jne     .not_empty
  1282.  
  1283.     @@:
  1284.         movzx   ecx, [ebx + EXT2_DIR_STRUC.rec_len]
  1285.         add     ebx, ecx
  1286.  
  1287.         cmp     ebx, edx
  1288.         jb      .dir_entry
  1289.  
  1290.         inc     dword[esp]
  1291.         jmp     .loop
  1292.  
  1293.     .empty:
  1294.         xor     eax, eax
  1295.     .return:
  1296.         add     esp, 4
  1297.         pop     edx ecx ebx
  1298.         ret
  1299.  
  1300.     .not_empty:
  1301.         xor     eax, eax
  1302.         not     eax
  1303.         jmp     .return
  1304.  
  1305. ;---------------------------------------------------------------------
  1306. ; Gets the block group's inode bitmap.
  1307. ; Input:        eax = block group.
  1308. ; Output:       eax = if zero, error; else, points to block group descriptor.
  1309. ;               ebx = inode bitmap's block (hard disk).
  1310. ;---------------------------------------------------------------------
  1311. ext2_bg_read_inode_bitmap:
  1312.         push    ecx
  1313.  
  1314.         call    ext2_bg_read_desc
  1315.         test    eax, eax
  1316.         jz      .fail
  1317.  
  1318.         mov     ebx, [eax + EXT2_BLOCK_GROUP_DESC.inode_bitmap] ; Block number of inode bitmap - in ext2 terms.
  1319.  
  1320.     .return:
  1321.         pop     ecx
  1322.         ret
  1323.  
  1324.     .fail:
  1325.         xor     eax, eax
  1326.         jmp     .return
  1327.  
  1328. ;---------------------------------------------------------------------
  1329. ; Allocates a inode.
  1330. ; Input:        eax = inode ID for "preference".
  1331. ;               ebp = pointer to EXTFS.
  1332. ; Output:       Inode marked as set in inode group.
  1333. ;               eax = error code.
  1334. ;               ebx = inode ID.
  1335. ;---------------------------------------------------------------------
  1336. ext2_inode_alloc:
  1337.         push    [ebp + EXTFS.superblock + EXT2_SB_STRUC.inodes_count]
  1338.         push    EXT2_BLOCK_GROUP_DESC.free_inodes_count
  1339.         push    [ebp + EXTFS.superblock + EXT2_SB_STRUC.inodes_per_group]
  1340.  
  1341.         lea     ebx, [ebp + EXTFS.superblock + EXT2_SB_STRUC.free_inodes_count]
  1342.         push    ebx
  1343.  
  1344.         push    ext2_bg_read_inode_bitmap
  1345.  
  1346.         call    ext2_resource_alloc
  1347.  
  1348.         ; Inode table starts with 1.
  1349.         inc     ebx
  1350.  
  1351.         ret
  1352.  
  1353. ;---------------------------------------------------------------------
  1354. ; Frees a inode.
  1355. ; Input:        eax = inode ID.
  1356. ;               ebp = pointer to EXTFS.
  1357. ; Output:       inode marked as free in block group.
  1358. ;               eax = error code.
  1359. ;---------------------------------------------------------------------
  1360. ext2_inode_free:
  1361.         push    edi ecx
  1362.  
  1363.         ; Inode table starts with 1.
  1364.         dec     eax
  1365.  
  1366.         mov     edi, ext2_bg_read_inode_bitmap
  1367.         xor     ecx, ecx
  1368.         inc     cl
  1369.         call    ext2_resource_free
  1370.  
  1371.         pop     ecx edi
  1372.         ret
  1373.  
  1374. ;---------------------------------------------------------------------
  1375. ; Blanks a particular entry in an inode.
  1376. ; Input:        eax = index into block.
  1377. ;               edx = inode.
  1378. ;               ebp = pointer to EXTFS.
  1379. ;               [ebp + EXTFS.ext2_temp_inode] = the inode.
  1380. ; Output:       eax = error code.
  1381. ;---------------------------------------------------------------------
  1382. ext2_inode_blank_entry:
  1383.         push    ebx ecx edx edi esi
  1384.  
  1385.         mov     edi, eax
  1386.  
  1387.         mov     ecx, eax
  1388.         mov     esi, [ebp + EXTFS.ext2_temp_inode]
  1389.         call    ext2_inode_get_block
  1390.         test    eax, eax
  1391.         jnz     .error
  1392.  
  1393.         test    ecx, ecx
  1394.         jz      .allocate
  1395.  
  1396.         mov     edx, ecx
  1397.         mov     ecx, [ebp + EXTFS.block_size]
  1398.         mov     edi, [ebp + EXTFS.ext2_temp_block]
  1399.         xor     eax, eax
  1400.         rep stosb
  1401.  
  1402.         mov     eax, edx
  1403.         mov     ebx, [ebp + EXTFS.ext2_temp_block]
  1404.         call    ext2_block_write
  1405.         test    eax, eax
  1406.         jnz     .error
  1407.  
  1408.         jmp     .success
  1409.  
  1410.     ; Need to allocate a block.
  1411.     .allocate:
  1412.         mov     eax, edx
  1413.         call    ext2_block_calloc
  1414.         test    eax, eax
  1415.         jnz     .error
  1416.  
  1417.         mov     ecx, edi
  1418.         mov     edi, ebx
  1419.         mov     esi, [ebp + EXTFS.ext2_temp_inode]
  1420.         call    ext2_inode_set_block
  1421.         test    eax, eax
  1422.         jnz     .error
  1423.  
  1424.         mov     ecx, [ebp + EXTFS.superblock + EXT2_SB_STRUC.log_block_size]
  1425.         mov     eax, 2
  1426.         shl     eax, cl
  1427.         add     [esi + EXT2_INODE_STRUC.i_blocks], eax
  1428.  
  1429.     .success:
  1430.         xor     eax, eax
  1431.  
  1432.     .ret:
  1433.         pop     esi edi edx ecx ebx
  1434.         ret
  1435.  
  1436.     .error:
  1437.         xor     eax, eax
  1438.         not     eax
  1439.         jmp     .ret
  1440.  
  1441. ;---------------------------------------------------------------------
  1442. ; Frees a particular entry in an inode.
  1443. ; Input:        eax = index into block.
  1444. ;               ebp = pointer to EXTFS.
  1445. ;               [ebp + EXTFS.ext2_temp_inode] = the inode.
  1446. ; Output:       eax = error code.
  1447. ;---------------------------------------------------------------------
  1448. ext2_inode_free_entry:
  1449.         push    ebx ecx edi esi
  1450.  
  1451.         mov     edi, eax
  1452.  
  1453.         mov     ecx, eax
  1454.         mov     esi, [ebp + EXTFS.ext2_temp_inode]
  1455.         call    ext2_inode_get_block
  1456.         test    eax, eax
  1457.         jnz     .error
  1458.  
  1459.         test    ecx, ecx
  1460.         jz      .success
  1461.  
  1462.         mov     eax, ecx
  1463.         call    ext2_block_free
  1464.         test    eax, eax
  1465.         jnz     .error
  1466.  
  1467.         mov     ecx, edi
  1468.         xor     edi, edi
  1469.         mov     esi, [ebp + EXTFS.ext2_temp_inode]
  1470.         call    ext2_inode_set_block
  1471.  
  1472.         mov     ecx, [ebp + EXTFS.superblock + EXT2_SB_STRUC.log_block_size]
  1473.         mov     eax, 2
  1474.         shl     eax, cl
  1475.         sub     [esi + EXT2_INODE_STRUC.i_blocks], eax
  1476.  
  1477.     .success:
  1478.         xor     eax, eax
  1479.  
  1480.     .ret:
  1481.         pop     esi edi ecx ebx
  1482.         ret
  1483.  
  1484.     .error:
  1485.         xor     eax, eax
  1486.         not     eax
  1487.         jmp     .ret
  1488.  
  1489. ;---------------------------------------------------------------------
  1490. ; Reads a particular entry from an inode.
  1491. ; Input:        eax = index into block.
  1492. ;               ebp = pointer to EXTFS.
  1493. ;               [ebp + EXTFS.ext2_temp_inode] = the inode.
  1494. ; Output:       eax = error code.
  1495. ;               [ebp + EXTFS.ext2_save_block] = the read block.
  1496. ;---------------------------------------------------------------------
  1497. ext2_inode_read_entry:
  1498.         push    ebx ecx edx esi
  1499.  
  1500.         mov     ecx, eax
  1501.         mov     esi, [ebp + EXTFS.ext2_temp_inode]
  1502.         call    ext2_inode_get_block
  1503.         test    eax, eax
  1504.         jnz     .error
  1505.  
  1506.         test    ecx, ecx
  1507.         jz      .error
  1508.  
  1509.         mov     eax, ecx
  1510.         mov     ebx, [ebp + EXTFS.ext2_save_block]
  1511.         call    ext2_block_read
  1512.         test    eax, eax
  1513.         jnz     .error
  1514.  
  1515.     .ret:
  1516.         pop     esi edx ecx ebx
  1517.         ret
  1518.  
  1519.     .error:
  1520.         xor     eax, eax
  1521.         not     eax
  1522.         jmp     .ret
  1523.  
  1524. ;---------------------------------------------------------------------
  1525. ; Writes a particular entry from an inode.
  1526. ; Input:        eax = index into block.
  1527. ;               ebp = pointer to EXTFS.
  1528. ;               [ebp + EXTFS.ext2_temp_inode] = the inode.
  1529. ;               [ebp + EXTFS.ext2_save_block] = the block to write.
  1530. ; Output:       eax = error code.
  1531. ;---------------------------------------------------------------------
  1532. ext2_inode_write_entry:
  1533.         push    ebx ecx edx esi
  1534.  
  1535.         mov     ecx, eax
  1536.         mov     esi, [ebp + EXTFS.ext2_temp_inode]
  1537.         call    ext2_inode_get_block
  1538.         test    eax, eax
  1539.         jnz     .error
  1540.  
  1541.         test    ecx, ecx
  1542.         jz      .error
  1543.  
  1544.         mov     eax, ecx
  1545.         mov     ebx, [ebp + EXTFS.ext2_save_block]
  1546.         call    ext2_block_write
  1547.         test    eax, eax
  1548.         jnz     .error
  1549.  
  1550.     .ret:
  1551.         pop     esi edx ecx ebx
  1552.         ret
  1553.  
  1554.     .error:
  1555.         xor     eax, eax
  1556.         not     eax
  1557.         jmp     .ret
  1558.  
  1559. ;---------------------------------------------------------------------
  1560. ; Extends inode to said size.
  1561. ; Input:        eax = inode ID.
  1562. ;               ecx = size to extend to.
  1563. ;               ebp = pointer to EXTFS.
  1564. ; Output:       eax = error code.
  1565. ;---------------------------------------------------------------------
  1566. ext2_inode_extend:
  1567.         push    ebx ecx edx esi edi
  1568.  
  1569.         ; Save the inode.
  1570.         push    eax
  1571.  
  1572.         ; Read the inode.
  1573.         mov     ebx, [ebp + EXTFS.ext2_temp_inode]
  1574.         call    ext2_inode_read
  1575.         test    eax, eax
  1576.         jnz     .error
  1577.  
  1578.         mov     eax, [ebx + EXT2_INODE_STRUC.i_size]
  1579.         cmp     eax, ecx
  1580.         jge     .success
  1581.  
  1582.         ; Save the size of the inode.
  1583.         push    eax
  1584.  
  1585.         ; ECX contains the size we've to write.
  1586.         sub     ecx, eax
  1587.         xor     edx, edx
  1588.         div     [ebp + EXTFS.block_size]
  1589.  
  1590.         test    edx, edx
  1591.         jz      .start_aligned
  1592.  
  1593.         ; Start isn't aligned, so deal with the non-aligned bytes.
  1594.         mov     esi, [ebp + EXTFS.block_size]
  1595.         sub     esi, edx
  1596.  
  1597.         cmp     esi, ecx
  1598.         jbe     @F
  1599.  
  1600.         ; If the size to entend to fits in current block, limit to that.
  1601.         mov     esi, ecx
  1602.  
  1603.     @@:
  1604.         ; Clear ESI bytes, in EAX indexed block.
  1605.         push    eax
  1606.         call    ext2_inode_read_entry
  1607.         test    eax, eax
  1608.         pop     eax
  1609.         jnz     .error_inode_size
  1610.  
  1611.         push    eax ecx
  1612.        
  1613.         xor     eax, eax
  1614.         mov     ecx, esi
  1615.         mov     edi, ebx
  1616.         add     edi, edx
  1617.  
  1618.         rep stosb
  1619.  
  1620.         pop     ecx eax
  1621.  
  1622.         ; Write the block.
  1623.         call    ext2_inode_write_entry
  1624.         test    eax, eax
  1625.         jnz     .error_inode_size
  1626.        
  1627.         add     [esp], esi
  1628.         sub     ecx, esi
  1629.         jz      .write_inode
  1630.  
  1631.     .start_aligned:
  1632.         cmp     ecx, [ebp + EXTFS.block_size]
  1633.         jb      @F
  1634.  
  1635.         mov     eax, [esp]
  1636.         xor     edx, edx
  1637.         div     [ebp + EXTFS.block_size]
  1638.  
  1639.         mov     edx, [esp + 4]
  1640.         call    ext2_inode_blank_entry
  1641.  
  1642.         test    eax, eax
  1643.         jnz     .error_inode_size
  1644.  
  1645.         mov     eax, [ebp + EXTFS.block_size]
  1646.         sub     ecx, eax
  1647.         add     [esp], eax
  1648.         jmp     .start_aligned        
  1649.  
  1650.     ; Handle the remaining bytes.
  1651.     @@:
  1652.         test    ecx, ecx
  1653.         jz      .write_inode
  1654.  
  1655.         mov     eax, [esp]
  1656.         xor     edx, edx
  1657.         div     [ebp + EXTFS.block_size]
  1658.  
  1659.         mov     edx, [esp + 4]
  1660.         call    ext2_inode_blank_entry
  1661.  
  1662.         test    eax, eax
  1663.         jnz     .error_inode_size
  1664.         add     [esp], ecx
  1665.  
  1666.     .write_inode:
  1667.         mov     ebx, [ebp + EXTFS.ext2_temp_inode]
  1668.         pop     eax
  1669.         mov     [ebx + EXT2_INODE_STRUC.i_size], eax
  1670.         mov     eax, [esp]
  1671.         call    ext2_inode_write
  1672.  
  1673.         test    eax, eax
  1674.         jnz     .error
  1675.  
  1676.     .success:
  1677.         xor     eax, eax
  1678.  
  1679.     .ret:
  1680.         add     esp, 4
  1681.  
  1682.         pop     edi esi edx ecx ebx
  1683.         ret
  1684.  
  1685.     .error_inode_size:
  1686.         mov     ebx, [ebp + EXTFS.ext2_temp_inode]
  1687.         pop     eax
  1688.         mov     [ebx + EXT2_INODE_STRUC.i_size], eax
  1689.         mov     eax, [esp]
  1690.         call    ext2_inode_write
  1691.  
  1692.     .error:
  1693.         xor     eax, eax
  1694.         not     eax
  1695.         jmp     .ret
  1696.  
  1697. ;---------------------------------------------------------------------
  1698. ; Truncates inode to said size.
  1699. ; Input:        eax = inode ID.
  1700. ;               ecx = size to truncate to.
  1701. ;               ebp = pointer to EXTFS.
  1702. ; Output:       eax = error code.
  1703. ;---------------------------------------------------------------------
  1704. ext2_inode_truncate:
  1705.         push    ebx ecx edx esi edi
  1706.  
  1707.         ; Save the inode.
  1708.         push    eax
  1709.  
  1710.         ; Read the inode.
  1711.         mov     ebx, [ebp + EXTFS.ext2_temp_inode]
  1712.         call    ext2_inode_read
  1713.         test    eax, eax
  1714.         jnz     .error
  1715.  
  1716.         mov     eax, [ebx + EXT2_INODE_STRUC.i_size]
  1717.         cmp     ecx, eax
  1718.         jge     .success
  1719.  
  1720.         ; Save the size of the inode.
  1721.         push    eax
  1722.  
  1723.         ; ECX contains the size we've to truncate.
  1724.         sub     ecx, eax
  1725.         not     ecx
  1726.         inc     ecx
  1727.         xor     edx, edx
  1728.         div     [ebp + EXTFS.block_size]
  1729.  
  1730.         test    edx, edx
  1731.         jz      .start_aligned
  1732.  
  1733.         ; Start isn't aligned, so deal with the non-aligned bytes.
  1734.         mov     esi, edx
  1735.  
  1736.         cmp     esi, ecx
  1737.         jbe     @F
  1738.  
  1739.         ; If the size to truncate is smaller than the un-aligned bytes
  1740.         ; we're going to have to mark neccessary bytes from the EOF
  1741.         ; as 0.
  1742.         push    eax
  1743.         call    ext2_inode_read_entry
  1744.         test    eax, eax
  1745.         pop     eax
  1746.         jnz     .error_inode_size
  1747.  
  1748.         mov     edi, [ebp + EXTFS.ext2_save_block]
  1749.         sub     edx, ecx
  1750.         add     edi, edx
  1751.  
  1752.         push    ecx eax
  1753.         xor     eax, eax
  1754.         rep stosb
  1755.         pop     eax ecx
  1756.  
  1757.         call    ext2_inode_write_entry
  1758.         test    eax, eax
  1759.         jnz     .error_inode_size
  1760.  
  1761.         sub     [esp], ecx
  1762.         jmp     .write_inode
  1763.  
  1764.     @@:
  1765.         ; Since ECX is greater than or equal to the bytes here un-aligned
  1766.         ; just free the block.
  1767.         call    ext2_inode_free_entry
  1768.  
  1769.         sub     [esp], esi
  1770.         sub     ecx, esi
  1771.         jz      .write_inode
  1772.  
  1773.     .start_aligned:
  1774.         cmp     ecx, [ebp + EXTFS.block_size]
  1775.         jb      @F
  1776.  
  1777.         mov     eax, [esp]
  1778.         xor     edx, edx
  1779.         div     [ebp + EXTFS.block_size]
  1780.         dec     eax
  1781.  
  1782.         call    ext2_inode_free_entry
  1783.  
  1784.         test    eax, eax
  1785.         jnz     .error_inode_size
  1786.  
  1787.         mov     eax, [ebp + EXTFS.block_size]
  1788.         sub     ecx, eax
  1789.         sub     [esp], eax
  1790.         jmp     .start_aligned        
  1791.  
  1792.     ; Handle the remaining bytes.
  1793.     @@:
  1794.         test    ecx, ecx
  1795.         jz      .write_inode
  1796.  
  1797.         mov     eax, [esp]
  1798.         xor     edx, edx
  1799.         div     [ebp + EXTFS.block_size]
  1800.         dec     eax
  1801.  
  1802.         push    eax
  1803.         call    ext2_inode_read_entry
  1804.         test    eax, eax
  1805.         pop     eax
  1806.         jnz     .error_inode_size
  1807.  
  1808.         mov     edi, [ebp + EXTFS.ext2_save_block]
  1809.         mov     edx, [ebp + EXTFS.block_size]
  1810.         sub     edx, ecx
  1811.         add     edi, edx
  1812.  
  1813.         push    ecx eax
  1814.         xor     eax, eax
  1815.         rep stosb
  1816.         pop     eax ecx
  1817.  
  1818.         call    ext2_inode_write_entry
  1819.         test    eax, eax
  1820.         jnz     .error_inode_size
  1821.  
  1822.         sub     [esp], ecx
  1823.  
  1824.     .write_inode:
  1825.         mov     ebx, [ebp + EXTFS.ext2_temp_inode]
  1826.         pop     eax
  1827.         mov     [ebx + EXT2_INODE_STRUC.i_size], eax
  1828.         mov     eax, [esp]
  1829.         call    ext2_inode_write
  1830.  
  1831.         test    eax, eax
  1832.         jnz     .error
  1833.  
  1834.     .success:
  1835.         xor     eax, eax
  1836.  
  1837.     .ret:
  1838.         add     esp, 4
  1839.  
  1840.         pop     edi esi edx ecx ebx
  1841.         ret
  1842.  
  1843.     .error_inode_size:
  1844.         mov     ebx, [ebp + EXTFS.ext2_temp_inode]
  1845.         pop     eax
  1846.         mov     [ebx + EXT2_INODE_STRUC.i_size], eax
  1847.         mov     eax, [esp]
  1848.         call    ext2_inode_write
  1849.  
  1850.     .error:
  1851.         xor     eax, eax
  1852.         not     eax
  1853.         jmp     .ret
  1854.