Subversion Repositories Kolibri OS

Rev

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 2004-2013. All rights reserved. ;;
  6. ;; Distributed under the terms of the new BSD license.          ;;
  7. ;;                                                              ;;
  8. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  9.  
  10. ; KSOC_EXT2_WRITE_END_TODO: clean this up.
  11. ;---------------------------------------------------------------------
  12. ; Receives block number from extent-based inode.
  13. ; Input:        ecx = number of block in inode
  14. ;               esi = address of extent header
  15. ;               ebp = pointer to EXTFS
  16. ; Output:       ecx = address of next block, if successful
  17. ;               eax = error code (0 implies no error)
  18. ;---------------------------------------------------------------------
  19. ext4_block_recursive_search:
  20.         cmp     word [esi + EXT4_EXTENT_HEADER.eh_magic], 0xF30A ;EXT4_EXT_MAGIC
  21.         jne     .fail
  22.        
  23.         movzx   ebx, [esi + EXT4_EXTENT_HEADER.eh_entries]
  24.         add     esi, sizeof.EXT4_EXTENT_HEADER
  25.         cmp     word [esi - sizeof.EXT4_EXTENT_HEADER + EXT4_EXTENT_HEADER.eh_depth], 0
  26.         je      .leaf_block     ;листовой ли это блок?
  27.        
  28.         ;не листовой блок, а индексный ; eax - ext4_extent_idx
  29.         test    ebx, ebx
  30.         jz      .fail               ;пустой индексный блок -> ошибка
  31.  
  32.         ;цикл по индексам экстентов
  33.     @@:
  34.         cmp     ebx, 1              ;у индексов не хранится длина,
  35.         je      .end_search_index   ;поэтому, если остался последний - то это нужный
  36.        
  37.         cmp     ecx, [esi + EXT4_EXTENT_IDX.ei_block]
  38.         jb      .fail
  39.        
  40.         cmp     ecx, [esi + sizeof.EXT4_EXTENT_IDX + EXT4_EXTENT_IDX.ei_block] ;блок слeдующего индекса
  41.         jb      .end_search_index ;следующий дальше - значит текущий, то что нам нужен
  42.        
  43.         add     esi, sizeof.EXT4_EXTENT_IDX
  44.         dec     ebx
  45.         jmp     @B
  46.  
  47.     .end_search_index:
  48.         ;ebp указывает на нужный extent_idx, считываем следующий блок
  49.         mov     ebx, [ebp + EXTFS.ext2_temp_block]
  50.         mov     eax, [esi + EXT4_EXTENT_IDX.ei_leaf_lo]
  51.         call    ext2_block_read
  52.         test    eax, eax
  53.         jnz     .fail
  54.         mov     esi, ebx
  55.         jmp     ext4_block_recursive_search ;рекурсивно прыгаем в начало
  56.        
  57.     .leaf_block:    ;листовой блок esi - ext4_extent
  58.         ;цикл по экстентам
  59.     @@:
  60.         test    ebx, ebx
  61.         jz      .fail       ;ни один узел не подошел - ошибка
  62.  
  63.         mov     edx, [esi + EXT4_EXTENT.ee_block]
  64.         cmp     ecx, edx
  65.         jb      .fail       ;если меньше, значит он был в предыдущих блоках -> ошибка
  66.  
  67.         movzx   edi, [esi + EXT4_EXTENT.ee_len]
  68.         add     edx, edi
  69.         cmp     ecx, edx
  70.         jb      .end_search_extent     ;нашли нужный блок
  71.        
  72.         add     esi, sizeof.EXT4_EXTENT
  73.         dec     ebx
  74.         jmp     @B
  75.        
  76.     .end_search_extent:
  77.         mov     edx, [esi + EXT4_EXTENT.ee_start_lo]
  78.         sub     ecx, [esi + EXT4_EXTENT.ee_block] ;разница в ext4 блоках
  79.         add     ecx, edx
  80.         xor     eax, eax
  81.         ret
  82.  
  83.     .fail:
  84.         mov     eax, ERROR_FS_FAIL
  85.         ret
  86.  
  87. ;---------------------------------------------------------------------
  88. ; Sets block ID for indirect-addressing inode.
  89. ; Input:        ecx = index of block in inode
  90. ;               edi = block ID to set to
  91. ;               esi = address of inode
  92. ;               ebp = pointer to EXTFS.
  93. ; Output:       eax = error code (0 implies no error)
  94. ;---------------------------------------------------------------------
  95. ext2_set_inode_block:
  96.         push    ebx ecx edx
  97.  
  98.         ; 0 to 11: direct blocks.
  99.         cmp     ecx, 12
  100.         jb      .direct_block
  101.  
  102.         ; Indirect blocks
  103.         sub     ecx, 12
  104.         cmp     ecx, [ebp + EXTFS.count_pointer_in_block]
  105.         jb      .indirect_block
  106.  
  107.         ; Double indirect blocks.
  108.         sub     ecx, [ebp + EXTFS.count_pointer_in_block]
  109.         cmp     ecx, [ebp + EXTFS.count_pointer_in_block_square]
  110.         jb      .double_indirect_block
  111.  
  112.         ; Triple indirect blocks.
  113.         sub     ecx, [ebp + EXTFS.count_pointer_in_block_square]
  114.  
  115.         ; Get triply-indirect block in temp_block.
  116.         mov     eax, [esi + EXT2_INODE_STRUC.i_block + 14*4]
  117.         test    eax, eax
  118.         jnz     @F
  119.  
  120.         ; TODO: fix to have correct preference.
  121.         mov     eax, EXT2_ROOT_INO
  122.         call    ext2_block_calloc
  123.         test    eax, eax
  124.         jnz     .fail_alloc
  125.  
  126.         mov     [esi + EXT2_INODE_STRUC.i_block + 14*4], ebx
  127.         mov     eax, ebx
  128.  
  129.     @@:
  130.         push    eax
  131.         mov     ebx, [ebp + EXTFS.ext2_temp_block]
  132.         call    ext2_block_read
  133.         test    eax, eax
  134.         jnz     .fail_alloc_4
  135.  
  136.         ; Get index in triply-indirect block.
  137.         xor     edx, edx
  138.         mov     eax, ecx
  139.         div     [ebp + EXTFS.count_pointer_in_block_square]
  140.  
  141.         ; eax: index in triply-indirect block, edx: index in doubly-indirect block.
  142.         lea     ecx, [ebx + eax*4]
  143.         mov     eax, [ebx + eax*4]
  144.         test    eax, eax
  145.         jnz     @F
  146.  
  147.         mov     eax, EXT2_ROOT_INO
  148.         call    ext2_block_calloc
  149.         test    eax, eax
  150.         jnz     .fail_alloc_4
  151.  
  152.         mov     [ecx], ebx
  153.  
  154.         mov     eax, [esp]
  155.         mov     ebx, [ebp + EXTFS.ext2_temp_block]
  156.         call    ext2_block_write    
  157.         test    eax, eax
  158.         jnz     .fail_alloc_4
  159.  
  160.         mov     eax, [ecx]
  161.     @@:
  162.         mov     [esp], eax
  163.         call    ext2_block_read
  164.         test    eax, eax
  165.         jnz     .fail_alloc_4
  166.  
  167.         mov     eax, edx
  168.         jmp     @F
  169.  
  170.     .double_indirect_block:
  171.         ; Get doubly-indirect block.
  172.         mov     eax, [esi + EXT2_INODE_STRUC.i_block + 13*4]
  173.         test    eax, eax
  174.         jnz     .double_indirect_present
  175.  
  176.         ; TODO: fix to have correct preference.
  177.         mov     eax, EXT2_ROOT_INO
  178.         call    ext2_block_calloc
  179.         test    eax, eax
  180.         jnz     .fail_alloc
  181.  
  182.         mov     [esi + EXT2_INODE_STRUC.i_block + 13*4], ebx
  183.         mov     eax, ebx
  184.  
  185.     .double_indirect_present:
  186.         ; Save block we're at.
  187.         push    eax
  188.  
  189.         mov     ebx, [ebp + EXTFS.ext2_temp_block]
  190.         call    ext2_block_read
  191.         test    eax, eax
  192.         jnz     .fail_alloc_4
  193.  
  194.         mov     eax, ecx
  195.     @@:
  196.         xor     edx, edx
  197.         div     [ebp + EXTFS.count_pointer_in_block]
  198.  
  199.         ; eax: index in doubly-indirect block, edx: index in indirect block.
  200.         lea     ecx, [ebx + edx*4]
  201.         push    ecx
  202.  
  203.         lea     ecx, [ebx + eax*4]
  204.         cmp     dword[ecx], 0
  205.         jne     @F
  206.  
  207.         ; TODO: fix to have correct preference.
  208.         mov     eax, EXT2_ROOT_INO
  209.         call    ext2_block_calloc
  210.         test    eax, eax
  211.         jnz     .fail_alloc_8
  212.  
  213.         mov     [ecx], ebx
  214.  
  215.         mov     eax, [esp + 4]
  216.         mov     ebx, [ebp + EXTFS.ext2_temp_block]
  217.         call    ext2_block_write    
  218.         test    eax, eax
  219.         jnz     .fail_alloc_8      
  220.  
  221.     @@:
  222.         mov     eax, [ecx]
  223.         push    eax
  224.         call    ext2_block_read
  225.         test    eax, eax
  226.         jnz     .fail_alloc_12
  227.  
  228.         pop     eax
  229.         pop     ecx
  230.         mov     [ecx], edi
  231.         call    ext2_block_write
  232.  
  233.         add     esp, 4
  234.         jmp     .return
  235.  
  236.     .indirect_block:
  237.         ; Get index of indirect block.
  238.         mov     eax, [esi + EXT2_INODE_STRUC.i_block + 12*4]
  239.         test    eax, eax
  240.         jnz     @F
  241.  
  242.         ; TODO: fix to have correct preference.
  243.         mov     eax, EXT2_ROOT_INO
  244.         call    ext2_block_calloc
  245.         test    eax, eax
  246.         jnz     .fail_alloc
  247.  
  248.         mov     [esi + EXT2_INODE_STRUC.i_block + 12*4], ebx
  249.         mov     eax, ebx
  250.    
  251.     @@:
  252.         push    eax
  253.         mov     ebx, [ebp + EXTFS.ext2_temp_block]
  254.         call    ext2_block_read
  255.         test    eax, eax
  256.         jnz     .fail_alloc_4
  257.        
  258.         ; Get the block ID.
  259.         mov     [ebx + ecx*4], edi
  260.         pop     eax
  261.         call    ext2_block_write
  262.         jmp     .return
  263.  
  264.     .direct_block:
  265.         mov     [esi + EXT2_INODE_STRUC.i_block + ecx*4], edi
  266.         xor     eax, eax
  267.  
  268.     .return:
  269.         pop     edx ecx ebx
  270.         ret
  271.  
  272.     .fail_alloc:
  273.         xor     eax, eax
  274.         not     eax
  275.         jmp     .return
  276.  
  277.     .fail_alloc_12:
  278.         add     esp, 4
  279.     .fail_alloc_8:
  280.         add     esp, 4
  281.     .fail_alloc_4:
  282.         add     esp, 4
  283.         jmp     .fail_alloc
  284.  
  285. ;---------------------------------------------------------------------
  286. ; Receives block ID from indirect-addressing inode.
  287. ; Input:        ecx = index of block in inode
  288. ;               esi = address of inode
  289. ;               ebp = pointer to EXTFS
  290. ; Output:       ecx = block ID, if successful
  291. ;               eax = error code (0 implies no error)
  292. ;---------------------------------------------------------------------
  293. ext2_get_inode_block:
  294.         ; If inode is extent-based, use ext4_block_recursive_search.
  295.         test    [esi + EXT2_INODE_STRUC.i_flags], EXT2_EXTENTS_FL
  296.         jz      @F
  297.  
  298.         pushad
  299.  
  300.         ; Get extent header in EBP.
  301.         add     esi, EXT2_INODE_STRUC.i_block
  302.         call    ext4_block_recursive_search
  303.         mov     PUSHAD_ECX, ecx
  304.         mov     PUSHAD_EAX, eax
  305.  
  306.         popad
  307.         ret
  308.  
  309.     @@:
  310.         ; 0 to 11: direct blocks.
  311.         cmp     ecx, 12
  312.         jb      .get_direct_block
  313.  
  314.         ; Indirect blocks
  315.         sub     ecx, 12
  316.         cmp     ecx, [ebp + EXTFS.count_pointer_in_block]
  317.         jb      .get_indirect_block
  318.  
  319.         ; Double indirect blocks.
  320.         sub     ecx, [ebp + EXTFS.count_pointer_in_block]
  321.         cmp     ecx, [ebp + EXTFS.count_pointer_in_block_square]
  322.         jb      .get_double_indirect_block
  323.  
  324.         ; Triple indirect blocks.
  325.         sub     ecx, [ebp + EXTFS.count_pointer_in_block_square]
  326.         push    edx ebx
  327.  
  328.         ; Get triply-indirect block in temp_block.
  329.         mov     eax, [esi + EXT2_INODE_STRUC.i_block + 14*4]
  330.         mov     ebx, [ebp + EXTFS.ext2_temp_block]
  331.         call    ext2_block_read
  332.         test    eax, eax
  333.         jnz     .fail
  334.  
  335.         ; Get index in triply-indirect block.
  336.         xor     edx, edx
  337.         mov     eax, ecx
  338.         div     [ebp + EXTFS.count_pointer_in_block_square]
  339.  
  340.         ; eax: index in triply-indirect block, edx: index in doubly-indirect block.
  341.         mov     eax, [ebx + eax*4]
  342.         call    ext2_block_read
  343.         test    eax, eax
  344.         jnz     .fail
  345.  
  346.         mov     eax, edx
  347.         jmp     @F
  348.  
  349.     .get_double_indirect_block:
  350.         push    edx ebx
  351.  
  352.         ; Get doubly-indirect block.
  353.         mov     eax, [esi + EXT2_INODE_STRUC.i_block + 13*4]
  354.         mov     ebx, [ebp + EXTFS.ext2_temp_block]
  355.         call    ext2_block_read
  356.         test    eax, eax
  357.         jnz     .fail
  358.  
  359.         mov     eax, ecx
  360.     @@:
  361.         xor     edx, edx
  362.         div     [ebp + EXTFS.count_pointer_in_block]
  363.  
  364.         ; eax: index in doubly-indirect block, edx: index in indirect block.
  365.         mov     eax, [ebx + eax*4]
  366.  
  367.         call    ext2_block_read
  368.         test    eax, eax
  369.         jnz     .fail
  370.  
  371.         mov     ecx, [ebx + edx*4]
  372.     .fail:
  373.         pop     ebx edx
  374.  
  375.         ret
  376.  
  377.     .get_indirect_block:
  378.         push    ebx
  379.  
  380.         ; Get index of indirect block.
  381.         mov     eax, [esi + EXT2_INODE_STRUC.i_block + 12*4]
  382.         mov     ebx, [ebp + EXTFS.ext2_temp_block]
  383.         call    ext2_block_read
  384.         test    eax, eax
  385.         jnz     @F
  386.        
  387.         ; Get the block ID.
  388.         mov     ecx, [ebx + ecx*4]
  389.     @@:
  390.         pop     ebx
  391.  
  392.         ret
  393.  
  394.     .get_direct_block:
  395.         mov     ecx, [esi + EXT2_INODE_STRUC.i_block + ecx*4]
  396.         xor     eax, eax
  397.  
  398.         ret
  399.  
  400. ;---------------------------------------------------------------------
  401. ; Get block containing inode.
  402. ; Input:        eax = inode number.
  403. ;               ebp = pointer to EXTFS.
  404. ; Output:       ebx = block (hard disk) containing inode.
  405. ;               edx = index inside block.
  406. ;               eax = error code (0 implies no error)
  407. ;---------------------------------------------------------------------
  408. ext2_read_block_of_inode:
  409.         pushad
  410.  
  411.         dec     eax
  412.         xor     edx, edx
  413.        
  414.         ; EAX = block group.
  415.         div     [ebp + EXTFS.superblock + EXT2_SB_STRUC.inodes_per_group]
  416.  
  417.         push    edx                             ; Index in group.
  418.  
  419.         mov     edx, 32
  420.         mul     edx                             ; Get index of descriptor in global_desc_table.
  421.  
  422.         ; eax: inode group offset relative to global descriptor table start
  423.         ; Find the block this block descriptor is in.
  424.         div     [ebp + EXTFS.block_size]
  425.         add     eax, [ebp + EXTFS.superblock + EXT2_SB_STRUC.first_data_block]
  426.         inc     eax
  427.         mov     ebx, [ebp + EXTFS.ext2_temp_block]
  428.         call    ext2_block_read
  429.         test    eax, eax
  430.         jnz     .return    
  431.  
  432.         add     ebx, edx                        ; edx: local index of descriptor inside block
  433.         mov     eax, [ebx + EXT2_BLOCK_GROUP_DESC.inode_table]   ; Block number of inode table - in ext2 terms.
  434.         mov     ecx, [ebp + EXTFS.log_block_size]
  435.         shl     eax, cl
  436.  
  437.         ; eax: points to inode table on HDD.
  438.         mov     esi, eax
  439.  
  440.         ; Add local address of inode.
  441.         pop     eax
  442.         mov     ecx, [ebp + EXTFS.inode_size]
  443.         mul     ecx                             ; (index * inode_size)
  444.  
  445.         mov     ebp, 512
  446.         div     ebp                             ; Divide by hard disk block size.
  447.  
  448.         add     eax, esi                        ; Found block to read.
  449.         mov     ebx, eax                        ; Get it inside ebx.
  450.  
  451.         xor     eax, eax
  452.     .return:
  453.         mov     PUSHAD_EAX, eax
  454.         mov     PUSHAD_EBX, ebx
  455.         mov     PUSHAD_EDX, edx
  456.  
  457.         popad
  458.         ret
  459.  
  460. ;---------------------------------------------------------------------
  461. ; Sets content of inode by number.
  462. ; Input:        eax = inode number.
  463. ;               ebx = address from where to write inode content.
  464. ;               ebp = pointer to EXTFS.
  465. ; Output:       eax = error code (0 implies no error)
  466. ;---------------------------------------------------------------------
  467. ext2_inode_write:
  468.         push    edx edi esi ecx ebx
  469.         mov     esi, ebx
  470.  
  471.         ; Ext2 actually stores time of modification of inode in ctime.
  472.         lea     edi, [ebx + EXT2_INODE_STRUC.i_ctime]
  473.         call    current_unix_time
  474.  
  475.         ; Get block where inode is situated.
  476.         call    ext2_read_block_of_inode
  477.         test    eax, eax
  478.         jnz     .error
  479.  
  480.         mov     eax, ebx                        ; Get block into EAX.
  481.         mov     ebx, [ebp + EXTFS.ext2_temp_block]
  482.  
  483.         mov     ecx, eax                        ; Save block.    
  484.         call    fs_read32_sys
  485.         test    eax, eax
  486.         jz      @F
  487.  
  488.     .error:
  489.         mov     eax, ERROR_DEVICE
  490.         jmp     .return
  491.  
  492.     @@:
  493.         mov     eax, ecx
  494.         mov     ecx, [ebp + EXTFS.inode_size]
  495.         mov     edi, edx                        ; The index into the block.
  496.         add     edi, ebx
  497.         rep movsb
  498.  
  499.         ; Write the block.
  500.         call    fs_write32_sys
  501.  
  502.     .return:
  503.         pop     ebx ecx esi edi edx
  504.         ret
  505.  
  506. ;---------------------------------------------------------------------
  507. ; Get content of inode by number.
  508. ; Input:        eax = inode number.
  509. ;               ebx = address where to store inode content.
  510. ;               ebp = pointer to EXTFS.
  511. ; Output:       eax = error code (0 implies no error)
  512. ;---------------------------------------------------------------------
  513. ext2_inode_read:
  514.         push    edx edi esi ecx ebx
  515.         mov     edi, ebx
  516.  
  517.         ; Get block where inode is situated.
  518.         call    ext2_read_block_of_inode
  519.         test    eax, eax
  520.         jnz     .error
  521.  
  522.         mov     eax, ebx                        ; Get block into EAX.
  523.         mov     ebx, [ebp + EXTFS.ext2_temp_block]
  524.         call    fs_read32_sys
  525.         test    eax, eax
  526.         jz      @F
  527.  
  528.     .error:
  529.         mov     eax, ERROR_DEVICE
  530.         jmp     .return
  531.  
  532.     @@:
  533.         mov     ecx, [ebp + EXTFS.inode_size]
  534.         mov     esi, edx                        ; The index into the inode.
  535.         add     esi, ebx
  536.         rep movsb
  537.  
  538.         xor     eax, eax
  539.     .return:
  540.         pop     ebx ecx esi edi edx
  541.         ret
  542.  
  543. ;---------------------------------------------------------------------
  544. ; Seek inode from the path.
  545. ; Input:        esi + [esp + 4] = name.
  546. ;               ebp = pointer to EXTFS.
  547. ; Output:       eax = error code (0 implies no error)
  548. ;               esi = inode number.
  549. ;                dl = first byte of file/folder name.
  550. ;                     [ext2_data.ext2_save_inode] stores the inode.
  551. ;---------------------------------------------------------------------
  552. ext2_inode_find:
  553.         mov     edx, [ebp + EXTFS.root_inode]
  554.  
  555.         ; Check for empty root.
  556.         cmp     [edx + EXT2_INODE_STRUC.i_blocks], 0
  557.         je      .error_empty_root
  558.  
  559.         ; Check for root.
  560.         cmp     byte[esi], 0
  561.         jne     .next_path_part
  562.  
  563.         push    edi ecx
  564.         mov     esi, [ebp + EXTFS.root_inode]
  565.         mov     edi, [ebp + EXTFS.ext2_save_inode]
  566.         mov     ecx, [ebp + EXTFS.inode_size]
  567.         rep movsb
  568.         pop     ecx edi
  569.  
  570.         xor     eax, eax
  571.         xor     dl, dl
  572.         mov     esi, EXT2_ROOT_INO
  573.         ret     4
  574.    
  575.     .next_path_part:
  576.         push    [edx + EXT2_INODE_STRUC.i_blocks]
  577.         xor     ecx, ecx
  578.  
  579.     .folder_block_cycle:
  580.         push    ecx
  581.         xchg    esi, edx
  582.         call    ext2_get_inode_block
  583.         xchg    esi, edx
  584.         test    eax, eax
  585.         jnz     .error_get_inode_block
  586.        
  587.         mov     eax, ecx
  588.         mov     ebx, [ebp + EXTFS.ext2_save_block]              ; Get directory records from directory.
  589.         call    ext2_block_read
  590.         test    eax, eax
  591.         jnz     .error_get_block
  592.        
  593.         push    esi
  594.         push    edx
  595.         call    ext2_block_find_parent
  596.         pop     edx
  597.         pop     edi ecx
  598.  
  599.         cmp     edi, esi                                        ; Did something match?
  600.         je      .next_folder_block                              ; No, move to next block.
  601.        
  602.         cmp     byte [esi], 0                                   ; Reached the "end" of path successfully.
  603.         jnz     @F
  604.         cmp     dword[esp + 8], 0
  605.         je      .get_inode_ret
  606.         mov     esi, [esp + 8]
  607.         mov     dword[esp + 8], 0
  608.  
  609.     @@:
  610.         mov     eax, [ebx + EXT2_DIR_STRUC.inode]
  611.         mov     ebx, [ebp + EXTFS.ext2_save_inode]
  612.         call    ext2_inode_read
  613.         test    eax, eax
  614.         jnz     .error_get_inode
  615.  
  616.         movzx   eax, [ebx + EXT2_INODE_STRUC.i_mode]
  617.         and     eax, EXT2_S_IFMT                                ; Get the mask.
  618.         cmp     eax, EXT2_S_IFDIR
  619.         jne     .not_found                                      ; Matched till part, but directory entry we got doesn't point to folder.
  620.  
  621.         pop     ecx                                             ; Stack top contains number of blocks.
  622.         mov     edx, ebx
  623.         jmp     .next_path_part
  624.        
  625.     .next_folder_block:
  626.         ; Next block in current folder.
  627.         pop     eax                                             ; Get blocks counter.
  628.         sub     eax, [ebp + EXTFS.count_block_in_block]
  629.         jle     .not_found
  630.        
  631.         push    eax
  632.         inc     ecx
  633.         jmp     .folder_block_cycle
  634.  
  635.     .not_found:
  636.         mov     eax, ERROR_FILE_NOT_FOUND
  637.         ret     4
  638.  
  639.     .get_inode_ret:
  640.         pop     ecx                                             ; Stack top contains number of blocks.
  641.  
  642.         mov     dl, [ebx + EXT2_DIR_STRUC.name]                 ; First character of file-name.
  643.         mov     eax, [ebx + EXT2_DIR_STRUC.inode]
  644.         mov     ebx, [ebp + EXTFS.ext2_save_inode]
  645.         mov     esi, eax
  646.  
  647.         ; If we can't get the inode, eax contains the error.        
  648.         call    ext2_inode_read
  649.         ret     4
  650.  
  651.     .error_get_inode_block:
  652.     .error_get_block:
  653.         pop     ecx
  654.     .error_get_inode:
  655.         pop     ebx
  656.     .error_empty_root:
  657.         mov     eax, ERROR_FS_FAIL
  658.         ret     4
  659.  
  660. ;---------------------------------------------------------------------
  661. ; Seeks parent inode from path.
  662. ; Input:        esi = path.
  663. ;               ebp = pointer to EXTFS.
  664. ; Output:       eax = error code.
  665. ;               esi = inode.
  666. ;               edi = pointer to file name.
  667. ;---------------------------------------------------------------------
  668. ext2_inode_find_parent:
  669.         push    esi
  670.         xor     edi, edi  
  671.  
  672.     .loop:
  673.         cmp     byte[esi], '/'
  674.         jne     @F
  675.  
  676.         mov     edi, esi
  677.         inc     esi
  678.         jmp     .loop
  679.  
  680.     @@:
  681.         inc     esi
  682.         cmp     byte[esi - 1], 0
  683.         jne     .loop
  684.  
  685.         ; If it was just a filename (without any additional directories),
  686.         ; use the last byte as "parent path".
  687.         cmp     edi, 0
  688.         jne     @F
  689.  
  690.         pop     edi
  691.         dec     esi
  692.         jmp     .get_inode
  693.  
  694.         ; It had some additional directories, so handle it that way.
  695.     @@:
  696.         mov     byte[edi], 0
  697.         inc     edi
  698.         pop     esi
  699.  
  700.     .get_inode:
  701.         push    ebx edx
  702.         stdcall ext2_inode_find, 0
  703.         pop     edx ebx
  704.  
  705.     .return:
  706.         ret
  707.  
  708. ;---------------------------------------------------------------------
  709. ; Link an inode.
  710. ; Input:        eax = inode on which to link.
  711. ;               ebx = inode to link.
  712. ;                dl = file type.
  713. ;               esi = name.
  714. ;               ebp = pointer to EXTFS.
  715. ; Output:       eax = error code.
  716. ;---------------------------------------------------------------------
  717. ext2_inode_link:
  718.         push    eax
  719.         push    esi edi ebx ecx edx
  720.  
  721.         ; Get string length, and then directory entry structure size.
  722.         call    strlen
  723.         add     ecx, 8
  724.  
  725.         push    esi ebx ecx
  726.  
  727.         xor     ecx, ecx
  728.         mov     esi, [ebp + EXTFS.ext2_temp_inode]
  729.         mov     ebx, esi
  730.  
  731.         call    ext2_inode_read
  732.         test    eax, eax
  733.         jnz     .error_inode_read
  734.  
  735.         ; Get the maximum addressible i_block index by (i_blocks/(2 << s_log_block_size)).
  736.         ; Note that i_blocks contains number of reserved 512B blocks, which is why we've to
  737.         ; find out the ext2 blocks.
  738.         mov     eax, 2
  739.         mov     ecx, [ebp + EXTFS.superblock + EXT2_SB_STRUC.log_block_size]
  740.         shl     eax, cl
  741.         mov     ecx, eax
  742.  
  743.         mov     eax, [esi + EXT2_INODE_STRUC.i_blocks]
  744.         xor     edx, edx
  745.  
  746.         div     ecx
  747.  
  748.         ; EAX is the maximum index inside i_block we can go.
  749.         push    eax
  750.         push    dword 0
  751.  
  752.         ; ECX contains the "block inside i_block" index.
  753.         xor     ecx, ecx
  754.     @@:
  755.         call    ext2_get_inode_block
  756.         test    eax, eax
  757.         jnz     .error_get_inode_block
  758.         test    ecx, ecx
  759.         jz      .alloc_block        ; We've got no block here, so allocate one.
  760.  
  761.         push    ecx                 ; Save block number.
  762.  
  763.         mov     eax, ecx
  764.         mov     ebx, [ebp + EXTFS.ext2_temp_block]
  765.         call    ext2_block_read
  766.         test    eax, eax
  767.         jnz     .error_block_read
  768.  
  769.         ; Try to find free space in current block.
  770.         mov     ecx, [esp + 8]
  771.         call    ext2_block_find_fspace
  772.         test    eax, eax
  773.         jz      .found
  774.  
  775.         cmp     eax, 0x00000001
  776.         jne     .next_iter
  777.  
  778.         ; This block wasn't linking to the next block, so fix that, and use the next one.
  779.         ; Write the block.
  780.         pop     eax
  781.         mov     ebx, [ebp + EXTFS.ext2_temp_block]
  782.         call    ext2_block_write    
  783.         test    eax, eax
  784.         jnz     .error_get_inode_block
  785.  
  786.         inc     dword [esp]
  787.         mov     ecx, [esp]
  788.         call    ext2_get_inode_block
  789.         test    eax, eax
  790.         jnz     .error_get_inode_block
  791.  
  792.         test    ecx, ecx
  793.         jz      .alloc_block
  794.  
  795.         ; If there was a block there, prepare it for our use!
  796.         push    ecx
  797.         jmp     .prepare_block
  798.  
  799.     .next_iter:
  800.         add     esp, 4
  801.  
  802.         inc     dword [esp]
  803.         mov     ecx, [esp]
  804.         cmp     ecx, [esp + 4]
  805.         jbe     @B      
  806.  
  807.     .alloc_block:
  808.         mov     eax, [esp + 12]     ; Get inode ID of what we're linking.
  809.         call    ext2_block_calloc
  810.         test    eax, eax
  811.         jnz     .error_get_inode_block
  812.  
  813.         mov     ecx, [esp]          ; Get the index of it inside the inode.
  814.         mov     edi, ebx            ; And what to set to.
  815.         call    ext2_set_inode_block
  816.         test    eax, eax
  817.         jnz     .error_get_inode_block
  818.  
  819.         ; Update i_size.
  820.         mov     eax, [ebp + EXTFS.block_size]
  821.         add     [esi + EXT2_INODE_STRUC.i_size], eax
  822.  
  823.         ; Update i_blocks.
  824.         mov     ecx, [ebp + EXTFS.superblock + EXT2_SB_STRUC.log_block_size]
  825.         mov     eax, 2
  826.         shl     eax, cl
  827.         add     [esi + EXT2_INODE_STRUC.i_blocks], eax
  828.  
  829.         ; Write the inode.
  830.         mov     eax, [esp + 40]
  831.         mov     ebx, esi
  832.         call    ext2_inode_write
  833.         test    eax, eax
  834.         jnz     .error_get_inode_block
  835.  
  836.         push    edi                 ; Save the block we just allocated.
  837.  
  838.     ; If we've allocated/using-old-block outside of loop, prepare it.
  839.     .prepare_block:
  840.         mov     eax, [esp]
  841.         mov     ebx, [ebp + EXTFS.ext2_temp_block]
  842.         call    ext2_block_read
  843.         test    eax, eax
  844.         jnz     .error_block_read
  845.  
  846.         mov     edi, ebx
  847.         mov     eax, [ebp + EXTFS.block_size]
  848.         mov     [edi + EXT2_DIR_STRUC.rec_len], ax
  849.  
  850.     .found:
  851.         pop     edx
  852.         add     esp, 8
  853.         pop     ecx ebx esi
  854.  
  855.         push    ebx
  856.         mov     [edi], ebx          ; Save inode.
  857.  
  858.         mov     eax, [esp + 4]      ; Get EDX off the stack -- contains the file_type.
  859.         cmp     [ebp + EXTFS.superblock + EXT2_SB_STRUC.rev_level], EXT2_GOOD_OLD_REV
  860.         je      .name
  861.  
  862.         ; Set the file-type.
  863.         mov     [edi + EXT2_DIR_STRUC.file_type], al
  864.  
  865.     .name:
  866.         ; Save name.
  867.         sub     ecx, 8
  868.         mov     [edi + EXT2_DIR_STRUC.name_len], cl
  869.         add     edi, 8
  870.         rep movsb
  871.  
  872.         ; Write block.
  873.         mov     eax, edx
  874.         mov     ebx, [ebp + EXTFS.ext2_temp_block]
  875.         call    ext2_block_write
  876.         test    eax, eax
  877.         jnz     .error_block_write
  878.  
  879.         mov     eax, [esp]
  880.         mov     ebx, [ebp + EXTFS.ext2_temp_inode]
  881.         call    ext2_inode_read
  882.         test    eax, eax
  883.         jnz     .error_block_write
  884.  
  885.         pop     eax
  886.         inc     [ebx + EXT2_INODE_STRUC.i_links_count]
  887.         call    ext2_inode_write
  888.         test    eax, eax
  889.         jnz     .error
  890.  
  891.         xor     eax, eax
  892.     .ret:
  893.         pop     edx ecx ebx edi esi
  894.         add     esp, 4
  895.         ret
  896.  
  897.     .error_block_read:
  898.         add     esp, 4
  899.     .error_get_inode_block:
  900.         add     esp, 8
  901.     .error_inode_read:
  902.         add     esp, 8
  903.     .error_block_write:
  904.         add     esp, 4
  905.     .error:
  906.         xor     eax, eax
  907.         not     eax
  908.         jmp     .ret
  909.  
  910. ;---------------------------------------------------------------------
  911. ; Unlink an inode.
  912. ; Input:        eax = inode from which to unlink.
  913. ;               ebx = inode to unlink.
  914. ;               ebp = pointer to EXTFS.
  915. ; Output:       eax = number of links to inode, after unlinking (0xFFFFFFFF implies error)
  916. ;---------------------------------------------------------------------
  917. ext2_inode_unlink:
  918.         push    ebx ecx edx esi edi
  919.  
  920.         push    ebx
  921.         mov     ebx, [ebp + EXTFS.ext2_temp_inode]
  922.         call    ext2_inode_read
  923.  
  924.         test    eax, eax
  925.         jnz     .fail_get_inode
  926.  
  927.         ; The index into the inode block data.
  928.         push    dword 0
  929.         mov     esi, [ebp + EXTFS.ext2_temp_inode]
  930.        
  931.     .loop:
  932.         mov     ecx, [esp]
  933.         call    ext2_get_inode_block
  934.  
  935.         test    eax, eax
  936.         jnz     .fail_loop
  937.         test    ecx, ecx
  938.         jz      .fail_loop
  939.  
  940.         mov     eax, ecx
  941.         mov     edi, eax
  942.         mov     ebx, [ebp + EXTFS.ext2_temp_block]
  943.         call    ext2_block_read
  944.         test    eax, eax
  945.         jnz     .fail_loop
  946.  
  947.     ; edi -> block.
  948.     .first_dir_entry:
  949.         mov     eax, [esp + 4]
  950.         cmp     [ebx], eax
  951.         jne     @F
  952.  
  953.         mov     dword[ebx], 0                               ; inode.
  954.         mov     word[ebx + 6], 0                            ; name_len + file_type.
  955.         jmp     .write_block
  956.  
  957.     @@:
  958.         mov     edx, ebx
  959.         add     edx, [ebp + EXTFS.block_size]
  960.         push    edx
  961.  
  962.         mov     edx, ebx
  963.         movzx   ecx, [ebx + EXT2_DIR_STRUC.rec_len]
  964.         add     ebx, ecx
  965.  
  966.     .dir_entry:
  967.         cmp     [ebx], eax
  968.         jne     @F
  969.  
  970.         mov     cx, [ebx + EXT2_DIR_STRUC.rec_len]
  971.         add     [edx + EXT2_DIR_STRUC.rec_len], cx
  972.         add     esp, 4
  973.         jmp     .write_block
  974.  
  975.     @@:
  976.         mov     edx, ebx
  977.         movzx   ecx, [ebx + EXT2_DIR_STRUC.rec_len]
  978.        
  979.         ; If it's a zero length entry, error.
  980.         test    ecx, ecx
  981.         jz      .fail_inode
  982.  
  983.         add     ebx, ecx
  984.  
  985.         cmp     ebx, [esp]
  986.         jb      .dir_entry
  987.  
  988.         add     esp, 4
  989.         inc     dword[esp]
  990.         jmp     .loop
  991.  
  992.     .write_block:
  993.         mov     eax, edi
  994.         mov     ebx, [ebp + EXTFS.ext2_temp_block]
  995.         call    ext2_block_write
  996.         test    eax, eax
  997.         jnz     .fail_loop
  998.  
  999.         add     esp, 4
  1000.         mov     ebx, [ebp + EXTFS.ext2_temp_inode]
  1001.         mov     eax, [esp]
  1002.         call    ext2_inode_read
  1003.         test    eax, eax
  1004.         jnz     .fail_get_inode
  1005.  
  1006.         dec     word[ebx + EXT2_INODE_STRUC.i_links_count]
  1007.         movzx   eax, word[ebx + EXT2_INODE_STRUC.i_links_count]
  1008.         push    eax
  1009.  
  1010.         mov     eax, [esp + 4]
  1011.         call    ext2_inode_write
  1012.         test    eax, eax
  1013.         jnz     .fail_loop
  1014.  
  1015.         pop     eax
  1016.         add     esp, 4
  1017.     .return:
  1018.         pop     edi esi edx ecx ebx
  1019.         ret
  1020.  
  1021.     .fail_inode:
  1022.         add     esp, 4
  1023.  
  1024.     .fail_loop:
  1025.         add     esp, 4
  1026.  
  1027.     .fail_get_inode:
  1028.         add     esp, 4
  1029.  
  1030.     .fail:
  1031.         xor     eax, eax
  1032.         not     eax
  1033.         jmp     .return
  1034.  
  1035. ;---------------------------------------------------------------------
  1036. ; Checks if a directory is empty.
  1037. ; Input:        ebx = inode to check.
  1038. ;               ebp = pointer to EXTFS.
  1039. ;               [EXTFS.ext2_save_inode] = points to saved inode.
  1040. ; Output:       eax = 0 signifies empty directory.
  1041. ;---------------------------------------------------------------------
  1042. ext2_dir_empty:
  1043.         push    ebx ecx edx
  1044.        
  1045.         ; The index into the inode block data.
  1046.         push    dword 0
  1047.         mov     esi, [ebp + EXTFS.ext2_save_inode]
  1048.        
  1049.     .loop:
  1050.         mov     ecx, [esp]
  1051.         call    ext2_get_inode_block
  1052.  
  1053.         ; Treat a failure as not-empty.
  1054.         test    eax, eax
  1055.         jnz     .not_empty
  1056.         test    ecx, ecx
  1057.         jz      .empty
  1058.  
  1059.         mov     eax, ecx
  1060.         mov     ebx, [ebp + EXTFS.ext2_temp_block]
  1061.         call    ext2_block_read
  1062.         test    eax, eax
  1063.         jnz     .not_empty
  1064.  
  1065.         mov     edx, ebx
  1066.         add     edx, [ebp + EXTFS.block_size]
  1067.  
  1068.         movzx   ecx, [ebx + EXT2_DIR_STRUC.rec_len]
  1069.         add     ebx, ecx
  1070.  
  1071.     .dir_entry:
  1072.         ; Process entry.
  1073.         cmp     byte[ebx + EXT2_DIR_STRUC.name_len], 1
  1074.         jne     @F
  1075.  
  1076.         cmp     byte[ebx + EXT2_DIR_STRUC.name], '.'
  1077.         jne     .not_empty
  1078.  
  1079.     @@:
  1080.         cmp     byte[ebx + EXT2_DIR_STRUC.name_len], 2
  1081.         jne     .not_empty
  1082.  
  1083.         cmp     word[ebx + EXT2_DIR_STRUC.name], '..'
  1084.         jne     .not_empty
  1085.  
  1086.     @@:
  1087.         movzx   ecx, [ebx + EXT2_DIR_STRUC.rec_len]
  1088.         add     ebx, ecx
  1089.  
  1090.         cmp     ebx, edx
  1091.         jb      .dir_entry
  1092.  
  1093.         inc     dword[esp]
  1094.         jmp     .loop
  1095.  
  1096.     .empty:
  1097.         xor     eax, eax
  1098.     .return:
  1099.         add     esp, 4
  1100.         pop     edx ecx ebx
  1101.         ret
  1102.  
  1103.     .not_empty:
  1104.         xor     eax, eax
  1105.         not     eax
  1106.         jmp     .return
  1107.  
  1108. ;---------------------------------------------------------------------
  1109. ; Gets the block group's inode bitmap.
  1110. ; Input:        eax = block group.
  1111. ; Output:       eax = if zero, error; else, points to block group descriptor.
  1112. ;               ebx = inode bitmap's block (hard disk).
  1113. ;---------------------------------------------------------------------
  1114. ext2_bg_read_inode_bitmap:
  1115.         push    ecx
  1116.  
  1117.         call    ext2_bg_read_desc
  1118.         test    eax, eax
  1119.         jz      .fail
  1120.  
  1121.         mov     ebx, [eax + EXT2_BLOCK_GROUP_DESC.inode_bitmap] ; Block number of inode bitmap - in ext2 terms.
  1122.  
  1123.     .return:
  1124.         pop     ecx
  1125.         ret
  1126.  
  1127.     .fail:
  1128.         xor     eax, eax
  1129.         jmp     .return
  1130.  
  1131. ;---------------------------------------------------------------------
  1132. ; Allocates a inode.
  1133. ; Input:        eax = inode ID for "preference".
  1134. ;               ebp = pointer to EXTFS.
  1135. ; Output:       Inode marked as set in inode group.
  1136. ;               eax = error code.
  1137. ;               ebx = inode ID.
  1138. ;---------------------------------------------------------------------
  1139. ext2_inode_alloc:
  1140.         push    [ebp + EXTFS.superblock + EXT2_SB_STRUC.inodes_count]
  1141.         push    EXT2_BLOCK_GROUP_DESC.free_inodes_count
  1142.         push    [ebp + EXTFS.superblock + EXT2_SB_STRUC.inodes_per_group]
  1143.  
  1144.         lea     ebx, [ebp + EXTFS.superblock + EXT2_SB_STRUC.free_inodes_count]
  1145.         push    ebx
  1146.  
  1147.         push    ext2_bg_read_inode_bitmap
  1148.  
  1149.         call    ext2_resource_alloc
  1150.  
  1151.         ; Inode table starts with 1.
  1152.         inc     ebx
  1153.  
  1154.         ret
  1155.  
  1156. ;---------------------------------------------------------------------
  1157. ; Frees a inode.
  1158. ; Input:        eax = inode ID.
  1159. ;               ebp = pointer to EXTFS.
  1160. ; Output:       inode marked as free in block group.
  1161. ;               eax = error code.
  1162. ;---------------------------------------------------------------------
  1163. ext2_inode_free:
  1164.         push    edi ecx
  1165.  
  1166.         ; Inode table starts with 1.
  1167.         dec     eax
  1168.  
  1169.         mov     edi, ext2_bg_read_inode_bitmap
  1170.         xor     ecx, ecx
  1171.         inc     cl
  1172.         call    ext2_resource_free
  1173.  
  1174.         pop     ecx edi
  1175.         ret