Subversion Repositories Kolibri OS

Rev

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

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