Subversion Repositories Kolibri OS

Rev

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

  1. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2. ;;                                                              ;;
  3. ;; Contains ext2 initialization, plus syscall 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. include 'ext2.inc'
  11. include 'blocks.asm'
  12. include 'inode.asm'
  13. include 'resource.asm'
  14.  
  15. iglobal
  16. align 4
  17. ext2_user_functions:
  18.         dd      ext2_free
  19.         dd      (ext2_user_functions_end - ext2_user_functions - 4) / 4
  20.         dd      ext2_Read
  21.         dd      ext2_ReadFolder
  22.         dd      ext2_Rewrite
  23.         dd      ext2_Write
  24.         dd      ext2_SetFileEnd
  25.         dd      ext2_GetFileInfo
  26.         dd      ext2_SetFileInfo
  27.         dd      0
  28.         dd      ext2_Delete
  29.         dd      ext2_CreateFolder
  30. ext2_user_functions_end:
  31. endg
  32.  
  33. ;---------------------------------------------------------------------
  34. ; Locks up an ext2 partition.
  35. ; Input:        ebp = pointer to EXTFS.
  36. ;---------------------------------------------------------------------
  37. proc ext2_lock
  38.         lea     ecx, [ebp + EXTFS.lock]
  39.         jmp     mutex_lock
  40. endp
  41.  
  42. ;---------------------------------------------------------------------
  43. ; Unlocks up an ext2 partition.
  44. ; Input:        ebp = pointer to EXTFS.
  45. ;---------------------------------------------------------------------
  46. proc ext2_unlock
  47.         lea     ecx, [ebp + EXTFS.lock]
  48.         jmp     mutex_unlock
  49. endp
  50.  
  51. ;---------------------------------------------------------------------
  52. ; Check if it's a valid ext* superblock.
  53. ; Input:        ebp:       first three fields of PARTITION structure.
  54. ;               ebx + 512: points to 512-bytes buffer that can be used for anything.
  55. ; Output:       eax:       clear if can't create partition; set to EXTFS otherwise.
  56. ;---------------------------------------------------------------------
  57. proc ext2_create_partition
  58.         push    ebx
  59.  
  60.         mov     eax, 2                          ; Superblock starts at 1024-bytes.
  61.         add     ebx, 512                        ; Get pointer to fs-specific buffer.
  62.         call    fs_read32_sys
  63.         test    eax, eax
  64.         jnz     .fail
  65.  
  66.         ; Allowed 1KiB, 2KiB, 4KiB, 8KiB.
  67.         cmp     [ebx + EXT2_SB_STRUC.log_block_size], 3  
  68.         ja      .fail
  69.  
  70.         cmp     [ebx + EXT2_SB_STRUC.magic], EXT2_SUPER_MAGIC
  71.         jne     .fail
  72.  
  73.         cmp     [ebx + EXT2_SB_STRUC.state], EXT2_VALID_FS
  74.         jne     .fail
  75.  
  76.         ; Can't have no inodes per group.
  77.         cmp     [ebx + EXT2_SB_STRUC.inodes_per_group], 0
  78.         je      .fail
  79.  
  80.         ; If incompatible features required, unusable superblock.
  81.         mov     eax, [ebx + EXT2_SB_STRUC.feature_incompat]
  82.         test    eax, not EXT4_FEATURE_INCOMPAT_SUPP
  83.         jz      .setup
  84.  
  85.     .fail:
  86.         ; Not a (valid/usable) EXT2 superblock.
  87.         pop     ebx
  88.         xor     eax, eax
  89.         ret
  90.  
  91.     .setup:
  92.         movi    eax, sizeof.EXTFS
  93.         call    malloc
  94.         test    eax, eax
  95.         jz      ext2_create_partition.fail
  96.  
  97.         ; Store the first sector field.
  98.         mov     ecx, dword[ebp + PARTITION.FirstSector]
  99.         mov     dword[eax + EXTFS.FirstSector], ecx
  100.         mov     ecx, dword [ebp + PARTITION.FirstSector+4]
  101.         mov     dword [eax + EXTFS.FirstSector+4], ecx
  102.  
  103.         ; The length field.
  104.         mov     ecx, dword[ebp + PARTITION.Length]
  105.         mov     dword[eax + EXTFS.Length], ecx
  106.         mov     ecx, dword[ebp + PARTITION.Length+4]
  107.         mov     dword[eax + EXTFS.Length+4], ecx
  108.  
  109.         ; The disk field.
  110.         mov     ecx, [ebp + PARTITION.Disk]
  111.         mov     [eax + EXTFS.Disk], ecx
  112.  
  113.         mov     [eax + EXTFS.FSUserFunctions], ext2_user_functions
  114.  
  115.         push    ebp esi edi
  116.  
  117.         mov     ebp, eax
  118.         lea     ecx, [eax + EXTFS.lock]
  119.         call    mutex_init
  120.  
  121.         ; Copy superblock from buffer to reserved memory.
  122.         mov     esi, ebx
  123.         lea     edi, [ebp + EXTFS.superblock]
  124.         mov     ecx, 512/4
  125.         rep movsd
  126.  
  127.         ; Get total groups.
  128.         mov     eax, [ebx + EXT2_SB_STRUC.blocks_count]
  129.         sub     eax, [ebx + EXT2_SB_STRUC.first_data_block]
  130.         dec     eax
  131.         xor     edx, edx
  132.         div     [ebx + EXT2_SB_STRUC.blocks_per_group]
  133.         inc     eax
  134.         mov     [ebp + EXTFS.groups_count], eax
  135.  
  136.         ; Get log(block_size), such that 1,2,3,4 equ 1KiB,2KiB,4KiB,8KiB.
  137.         mov     ecx, [ebx + EXT2_SB_STRUC.log_block_size]
  138.         inc     ecx
  139.         mov     [ebp + EXTFS.log_block_size], ecx
  140.  
  141.         ; 512-byte blocks in ext2 blocks.
  142.         mov     eax, 1
  143.         shl     eax, cl
  144.         mov     [ebp + EXTFS.count_block_in_block], eax
  145.  
  146.         ; Get block_size/4 (we'll find square later).
  147.         shl     eax, 7
  148.         mov     [ebp + EXTFS.count_pointer_in_block], eax
  149.         mov     edx, eax
  150.  
  151.         ; Get block size.
  152.         shl     eax, 2
  153.         mov     [ebp + EXTFS.block_size], eax
  154.  
  155.         ; Save block size for 2 kernel_alloc calls.
  156.         push    eax eax
  157.  
  158.         mov     eax, edx
  159.         mul     edx
  160.         mov     [ebp + EXTFS.count_pointer_in_block_square], eax
  161.  
  162.         ; Have temporary block storage for get_inode procedure, and one for global procedure.
  163.         KERNEL_ALLOC [ebp + EXTFS.ext2_save_block], .error
  164.         KERNEL_ALLOC [ebp + EXTFS.ext2_temp_block], .error
  165.        
  166.         mov     [ebp + EXTFS.partition_flags], 0x00000000
  167.         mov     eax, [ebx + EXT2_SB_STRUC.feature_ro_compat]
  168.         and     eax, not EXT2_FEATURE_RO_COMPAT_SUPP
  169.         jnz     .read_only
  170.  
  171.         mov     eax, [ebx + EXT2_SB_STRUC.feature_incompat]
  172.         and     eax, EXT4_FEATURE_INCOMPAT_W_NOT_SUPP
  173.         jz      @F
  174.  
  175.     .read_only:
  176.         ; Mark as read-only.
  177.         or      [ebp + EXTFS.partition_flags], EXT2_RO
  178.     @@:
  179.         mov     ecx, [ebx + EXT2_SB_STRUC.blocks_per_group]
  180.         mov     [ebp + EXTFS.blocks_per_group], ecx
  181.  
  182.         movzx   ecx, word[ebx + EXT2_SB_STRUC.inode_size]
  183.         mov     [ebp + EXTFS.inode_size], ecx
  184.  
  185.         ; Allocate for three inodes (loop would be overkill).
  186.         push    ecx ecx ecx
  187.  
  188.         KERNEL_ALLOC [ebp + EXTFS.ext2_save_inode], .error
  189.         KERNEL_ALLOC [ebp + EXTFS.ext2_temp_inode], .error
  190.         KERNEL_ALLOC [ebp + EXTFS.root_inode], .error
  191.  
  192.         ; Read root inode.
  193.         mov     ebx, eax
  194.         mov     eax, EXT2_ROOT_INO
  195.         call    ext2_inode_read
  196.  
  197.         test    eax, eax
  198.         jnz     .error
  199.  
  200.         mov     eax, ebp                        ; Return pointer to EXTFS.
  201.         pop     edi esi ebp ebx
  202.         ret
  203.  
  204.     ; Error in setting up.
  205.     .error:        
  206.         ; Free save block.
  207.         KERNEL_FREE [ebp + EXTFS.ext2_save_block], .fail
  208.  
  209.         ; Temporary block.
  210.         KERNEL_FREE [ebp + EXTFS.ext2_temp_block], .fail
  211.  
  212.         ; All inodes.
  213.         KERNEL_FREE [ebp + EXTFS.ext2_save_inode], .fail
  214.         KERNEL_FREE [ebp + EXTFS.ext2_temp_inode], .fail
  215.         KERNEL_FREE [ebp + EXTFS.root_inode], .fail
  216.  
  217.         mov     eax, ebp
  218.         call    free
  219.  
  220.         jmp     .fail
  221. endp
  222.  
  223. ; FUNCTIONS PROVIDED BY SYSCALLS.
  224.  
  225. ;---------------------------------------------------------------------
  226. ; Frees up all ext2 structures.
  227. ; Input:        eax = pointer to EXTFS.
  228. ;---------------------------------------------------------------------
  229. proc ext2_free
  230.         push    ebp
  231.  
  232.         xchg    ebp, eax
  233.         stdcall kernel_free, [ebp+EXTFS.ext2_save_block]
  234.         stdcall kernel_free, [ebp+EXTFS.ext2_temp_block]
  235.         stdcall kernel_free, [ebp+EXTFS.ext2_save_inode]
  236.         stdcall kernel_free, [ebp+EXTFS.ext2_temp_inode]
  237.         stdcall kernel_free, [ebp+EXTFS.root_inode]
  238.  
  239.         xchg    ebp, eax
  240.         call    free
  241.  
  242.         pop     ebp
  243.         ret
  244. endp
  245.  
  246. ;---------------------------------------------------------------------
  247. ; Read disk folder.
  248. ; Input:        ebp = pointer to EXTFS structure.
  249. ;               esi + [esp + 4] = file name.
  250. ;               ebx = pointer to parameters from sysfunc 70.
  251. ; Output:       ebx = blocks read (or 0xFFFFFFFF, folder not found)
  252. ;               eax = error code (0 implies no error)
  253. ;---------------------------------------------------------------------
  254. ext2_ReadFolder:
  255.         call    ext2_lock
  256.         cmp     byte [esi], 0
  257.         jz      .root_folder
  258.  
  259.         push    ebx
  260.         stdcall ext2_inode_find, [esp + 4 + 4]            ; Get inode.
  261.         pop     ebx
  262.  
  263.         mov     esi, [ebp + EXTFS.ext2_save_inode]
  264.         test    eax, eax
  265.         jnz     .error_ret
  266.  
  267.         ; If not a directory, then return with error.
  268.         test    [esi + EXT2_INODE_STRUC.i_mode], EXT2_S_IFDIR
  269.         jz      .error_not_found
  270.         jmp     @F
  271.  
  272.     .root_folder:
  273.         mov     esi, [ebp + EXTFS.root_inode]
  274.         test    [esi + EXT2_INODE_STRUC.i_mode], EXT2_S_IFDIR
  275.         jz      .error_root
  276.  
  277.         ; Copy the inode.
  278.         mov     edi, [ebp + EXTFS.ext2_save_inode]
  279.         mov     ecx, [ebp + EXTFS.inode_size]
  280.         shr     ecx, 2
  281.        
  282.         push    edi
  283.         rep movsd
  284.         pop     esi
  285.  
  286.     @@:
  287.         cmp     [esi + EXT2_INODE_STRUC.i_size], 0      ; Folder is empty.
  288.         je      .error_empty_dir
  289.        
  290.         mov     edx, [ebx + 16]
  291.         push    edx                                     ; Result address [edi + 28].
  292.         push    0                                       ; End of the current block in folder [edi + 24]
  293.         push    dword[ebx + 12]                         ; Blocks to read [edi + 20]
  294.         push    dword[ebx + 4]                          ; The first wanted file [edi + 16]
  295.         push    dword[ebx + 8]                          ; Flags [edi + 12]
  296.         push    0                                       ; Read files [edi + 8]
  297.         push    0                                       ; Files in folder [edi + 4]
  298.         push    0                                       ; Number of blocks read in dir (and current block index) [edi]
  299.  
  300.         ; Fill header with zeroes.
  301.         mov     edi, edx
  302.         mov     ecx, 32/4
  303.         rep stosd
  304.        
  305.         mov     edi, esp                                ; edi = pointer to local variables.
  306.         add     edx, 32                                 ; edx = mem to return.
  307.  
  308.         xor     ecx, ecx                                ; Get number of first block.
  309.         call    ext2_get_inode_block
  310.         test    eax, eax
  311.         jnz     .error_get_block
  312.  
  313.         mov     eax, ecx
  314.         mov     ebx, [ebp + EXTFS.ext2_save_block]
  315.         call    ext2_block_read                          ; Read the block.
  316.         test    eax, eax
  317.         jnz     .error_get_block
  318.  
  319.         mov     eax, ebx                                ; esi: current directory record
  320.         add     eax, [ebp + EXTFS.block_size]
  321.        
  322.         mov     [edi + 24], eax
  323.  
  324.         mov     ecx, [edi + 16]                         ; ecx = first wanted (flags ommited)
  325.  
  326.     .find_wanted_start:
  327.         jecxz   .find_wanted_end
  328.        
  329.     .find_wanted_cycle:
  330.         cmp     [ebx + EXT2_DIR_STRUC.inode], 0         ; Don't count unused inode in total files.
  331.         jz      @F
  332.  
  333.         inc     dword [edi + 4]                         ; EXT2 files in folder.
  334.         dec     ecx
  335.     @@:
  336.         movzx   eax, [ebx + EXT2_DIR_STRUC.rec_len]
  337.        
  338.         cmp     eax, 12                                 ; Minimum record length.
  339.         jb      .error_bad_len
  340.         test    eax, 0x3                                ; Record length must be divisible by four.
  341.         jnz     .error_bad_len
  342.  
  343.         sub     [esi + EXT2_INODE_STRUC.i_size], eax    ; Subtract "processed record" length directly from inode.
  344.         add     ebx, eax                                ; Go to next record.
  345.         cmp     ebx, [edi + 24]                         ; If not reached the next block, continue.
  346.         jb      .find_wanted_start
  347.  
  348.         push    .find_wanted_start
  349.    .end_block:                                          ; Get the next block.
  350.         cmp     [esi + EXT2_INODE_STRUC.i_size], 0
  351.         jle     .end_dir
  352.  
  353.         inc     dword [edi]                             ; Number of blocks read.
  354.        
  355.         ; Read the next block.
  356.         push    ecx
  357.         mov     ecx, [edi]
  358.         call    ext2_get_inode_block
  359.         test    eax, eax
  360.         jnz     .error_get_block
  361.  
  362.         mov     eax, ecx
  363.         mov     ebx, [ebp + EXTFS.ext2_save_block]
  364.         call    ext2_block_read
  365.         test    eax, eax
  366.         jnz     .error_get_block
  367.         pop     ecx
  368.  
  369.         mov     eax, ebx
  370.         add     eax, [ebp + EXTFS.block_size]
  371.         mov     [edi + 24], eax                         ; Update the end of the current block variable.  
  372.         ret
  373.  
  374.     .wanted_end:
  375.         loop    .find_wanted_cycle                      ; Skip files till we reach wanted one.
  376.        
  377.     ; First requisite file.
  378.     .find_wanted_end:
  379.         mov     ecx, [edi + 20]
  380.     .wanted_start:                                      ; Look for first_wanted + count.
  381.         jecxz   .wanted_end
  382.  
  383.         cmp     [ebx + EXT2_DIR_STRUC.inode], 0         ; if (inode == 0): not used;
  384.         jz      .empty_rec
  385.  
  386.         ; Increment "files in dir" and "read files" count.
  387.         inc     dword [edi + 8]
  388.         inc     dword [edi + 4]
  389.  
  390.         push    edi ecx
  391.         mov     edi, edx                                ; Zero out till the name field.
  392.         xor     eax, eax
  393.         mov     ecx, 40 / 4
  394.         rep stosd
  395.         pop     ecx edi
  396.  
  397.         push    ebx edi edx
  398.         mov     eax, [ebx + EXT2_DIR_STRUC.inode]       ; Get the child inode.
  399.         mov     ebx, [ebp + EXTFS.ext2_temp_inode]
  400.         call    ext2_inode_read
  401.         test    eax, eax
  402.         jnz     .error_read_subinode
  403.  
  404.         lea     edi, [edx + 8]
  405.  
  406.         mov     eax, [ebx + EXT2_INODE_STRUC.i_ctime]   ; Convert time in NTFS format.
  407.         xor     edx, edx
  408.         add     eax, 3054539008                         ; (369 * 365 + 89) * 24 * 3600
  409.         adc     edx, 2
  410.         call    ntfs_datetime_to_bdfe.sec
  411.  
  412.         mov     eax, [ebx + EXT2_INODE_STRUC.i_atime]
  413.         xor     edx, edx
  414.         add     eax, 3054539008
  415.         adc     edx, 2
  416.         call    ntfs_datetime_to_bdfe.sec
  417.  
  418.         mov     eax, [ebx + EXT2_INODE_STRUC.i_mtime]
  419.         xor     edx, edx
  420.         add     eax, 3054539008
  421.         adc     edx, 2
  422.         call    ntfs_datetime_to_bdfe.sec
  423.  
  424.         pop     edx
  425.         test    [ebx + EXT2_INODE_STRUC.i_mode], EXT2_S_IFDIR ; If folder, don't report size.
  426.         jnz     @F
  427.  
  428.         mov     eax, [ebx + EXT2_INODE_STRUC.i_size]    ; Low size
  429.         stosd
  430.         mov     eax, [ebx + EXT2_INODE_STRUC.i_dir_acl] ; High size
  431.         stosd
  432.  
  433.         xor     dword [edx], FS_FT_DIR                  ; Mark as file.
  434.     @@:
  435.         xor     dword [edx], FS_FT_DIR                  ; Mark as directory.
  436.  
  437.         ; Copy name after converting from UTF-8 to CP866.
  438.         push    ecx esi
  439.         mov     esi, [esp + 12]
  440.         movzx   ecx, [esi + EXT2_DIR_STRUC.name_len]
  441.         lea     edi, [edx + 40]
  442.         lea     esi, [esi + EXT2_DIR_STRUC.name]
  443.         call    utf8_to_cp866
  444.         and     byte [edi], 0
  445.         pop     esi ecx edi ebx
  446.  
  447.         cmp     byte [edx + 40], '.'                    ; If it begins with ".", mark it as hidden.
  448.         jne     @F
  449.         or      dword [edx], FS_FT_HIDDEN
  450.    
  451.     @@:
  452.         add     edx, 40 + 264                           ; Go to next record.
  453.         dec     ecx
  454.     .empty_rec:
  455.         movzx   eax, [ebx + EXT2_DIR_STRUC.rec_len]
  456.  
  457.         cmp     eax, 12                                 ; Illegal length.
  458.         jb      .error_bad_len
  459.         test    eax, 0x3                                ; Not a multiple of four.
  460.         jnz     .error_bad_len
  461.  
  462.         sub     [esi + EXT2_INODE_STRUC.i_size], eax    ; Subtract directly from the inode.
  463.         add     ebx, eax    
  464.         cmp     ebx, [edi + 24]                         ; Are we at the end of the block?
  465.         jb      .wanted_start
  466.  
  467.         push    .wanted_start
  468.         jmp     .end_block
  469.  
  470.     .end_dir:                                           ; End of the directory.
  471.         call    ext2_unlock
  472.         mov     edx, [edi + 28]                         ; Address of where to return data.
  473.         mov     ebx, [edi + 8]                          ; EXT2_read_in_folder
  474.         mov     ecx, [edi + 4]                          ; EXT2_files_in_folder
  475.         mov     dword [edx], 1                          ; Version
  476.         mov     [edx + 4], ebx
  477.         mov     [edx + 8], ecx
  478.        
  479.         lea     esp, [edi + 32]
  480.        
  481.         xor     eax, eax                                ; Reserved in current implementation.
  482.         lea     edi, [edx + 12]
  483.         mov     ecx, 20 / 4
  484.         rep stosd
  485.         ret
  486.  
  487.     .error_bad_len:
  488.         mov     eax, ERROR_FS_FAIL
  489.  
  490.     .error_read_subinode:
  491.     .error_get_block:
  492.         ; Fix the stack.
  493.         lea     esp, [edi + 32]
  494.  
  495.     .error_ret:
  496.         or      ebx, -1
  497.         push    eax
  498.         call    ext2_unlock
  499.         pop     eax
  500.  
  501.         ret
  502.        
  503.     .error_empty_dir:                                   ; inode of folder without blocks.
  504.     .error_root:                                        ; Root has to be a folder.
  505.         mov     eax, ERROR_FS_FAIL
  506.         jmp     .error_ret
  507.  
  508.     .error_not_found:                                   ; Directory not found.
  509.         mov     eax, ERROR_FILE_NOT_FOUND
  510.         jmp     .error_ret
  511.  
  512. ;---------------------------------------------------------------------
  513. ; Read file from the hard disk.
  514. ; Input:        esi + [esp + 4] = points to file name.
  515. ;               ebx = pointer to paramteres from sysfunc 70.
  516. ;               ebp = pointer to EXTFS structure.
  517. ; Output:       ebx = bytes read (0xFFFFFFFF -> file not found)
  518. ;               eax = error code (0 implies no error)
  519. ;---------------------------------------------------------------------
  520. ext2_Read:
  521.         call    ext2_lock
  522.         cmp     byte [esi], 0
  523.         jnz     @F
  524.  
  525.     .this_is_nofile:
  526.         call    ext2_unlock
  527.         or      ebx, -1
  528.         mov     eax, ERROR_ACCESS_DENIED
  529.         ret
  530.  
  531.     @@:
  532.         push    ebx
  533.         stdcall ext2_inode_find, [esp + 4 + 4]
  534.         pop     ebx
  535.  
  536.         mov     esi, [ebp + EXTFS.ext2_save_inode]
  537.         test    eax, eax
  538.         jz      @F
  539.  
  540.         call    ext2_unlock
  541.         or      ebx, -1
  542.         mov     eax, ERROR_FILE_NOT_FOUND
  543.         ret
  544.  
  545.     @@:
  546.         mov     ax, [esi + EXT2_INODE_STRUC.i_mode]
  547.         and     ax, EXT2_S_IFMT                         ; Leave the file format in AX.
  548.  
  549.         ; Check if file.
  550.         cmp     ax, EXT2_S_IFREG
  551.         jne     .this_is_nofile
  552.  
  553.         mov     edi, [ebx + 16]
  554.         mov     ecx, [ebx + 12]
  555.  
  556.         mov     eax, [ebx + 4]
  557.         mov     edx, [ebx + 8]                          ; edx:eax = start byte number.
  558.  
  559.         ; Check if file is big enough for us.
  560.         cmp     [esi + EXT2_INODE_STRUC.i_dir_acl], edx
  561.         ja      .size_greater
  562.         jb      .size_less
  563.  
  564.         cmp     [esi + EXT2_INODE_STRUC.i_size], eax
  565.         ja      .size_greater
  566.  
  567.     .size_less:
  568.         call    ext2_unlock
  569.         xor     ebx, ebx
  570.         mov     eax, ERROR_END_OF_FILE
  571.         ret
  572.        
  573.     @@:
  574.     .size_greater:
  575.         add     eax, ecx                                ; Get last byte.
  576.         adc     edx, 0
  577.  
  578.         ; Check if we've to read whole file, or till requested.
  579.         cmp     [esi + EXT2_INODE_STRUC.i_dir_acl], edx
  580.         ja      .read_till_requested
  581.         jb      .read_whole_file
  582.         cmp     [esi + EXT2_INODE_STRUC.i_size], eax
  583.         jae     .read_till_requested
  584.  
  585.     .read_whole_file:
  586.         push    1                                       ; Read till the end of file.
  587.         mov     ecx, [esi + EXT2_INODE_STRUC.i_size]
  588.         sub     ecx, [ebx + 4]                          ; To read = (size - starting byte)
  589.         jmp     @F
  590.  
  591.     .read_till_requested:
  592.         push    0                                       ; Read as much as requested.
  593.  
  594.     @@:
  595.         ; ecx = bytes to read.
  596.         ; edi = return memory
  597.         ; [esi] = starting byte.
  598.  
  599.         push    ecx                                     ; Number of bytes to read.
  600.        
  601.         ; Get part of the first block.
  602.         mov     edx, [ebx + 8]
  603.         mov     eax, [ebx + 4]
  604.         div     [ebp + EXTFS.block_size]
  605.  
  606.         push    eax                                     ; Save block counter to stack.
  607.        
  608.         push    ecx
  609.         mov     ecx, eax
  610.         call    ext2_get_inode_block
  611.         test    eax, eax
  612.         jnz     .error_at_first_block
  613.  
  614.         mov     ebx, [ebp + EXTFS.ext2_save_block]
  615.         mov     eax, ecx
  616.         call    ext2_block_read
  617.         test    eax, eax
  618.         jnz     .error_at_first_block
  619.  
  620.         pop     ecx
  621.         ; Get index inside block.
  622.         add     ebx, edx
  623.  
  624.         neg     edx
  625.         add     edx, [ebp + EXTFS.block_size]          ; Get number of bytes in this block.
  626.  
  627.         ; If it's smaller than total bytes to read, then only one block.
  628.         cmp     ecx, edx
  629.         jbe     .only_one_block
  630.  
  631.         mov     eax, ecx
  632.         sub     eax, edx
  633.         mov     ecx, edx
  634.  
  635.         push    esi
  636.         mov     esi, ebx
  637.         rep movsb                                       ; Copy part of 1st block.
  638.         pop     esi
  639.  
  640.         ; eax -> bytes to read.
  641.     .calc_blocks_count:
  642.         mov     ebx, edi                                ; Read the block in ebx.
  643.         xor     edx, edx
  644.         div     [ebp + EXTFS.block_size]                ; Get number of bytes in last block in edx.
  645.         mov     edi, eax                                ; Get number of blocks in edi.
  646.  
  647.     @@:
  648.         ; Test if all blocks are done.
  649.         test    edi, edi
  650.         jz      .finish_block
  651.        
  652.         inc     dword [esp]
  653.         mov     ecx, [esp]
  654.         call    ext2_get_inode_block
  655.  
  656.         test    eax, eax
  657.         jnz     .error_at_read_cycle
  658.  
  659.         mov     eax, ecx                                ; ebx already contains desired values.
  660.         call    ext2_block_read
  661.  
  662.         test    eax, eax
  663.         jnz     .error_at_read_cycle
  664.  
  665.         add     ebx, [ebp + EXTFS.block_size]
  666.  
  667.         dec     edi
  668.         jmp     @B
  669.  
  670.     ; In edx -- number of bytes in the last block.
  671.     .finish_block:          
  672.         test    edx, edx
  673.         jz      .end_read
  674.  
  675.         pop     ecx                                     ; Pop block counter in ECX.
  676.         inc     ecx
  677.         call    ext2_get_inode_block
  678.        
  679.         test    eax, eax
  680.         jnz     .error_at_finish_block
  681.  
  682.         mov     edi, ebx
  683.         mov     eax, ecx
  684.         mov     ebx, [ebp + EXTFS.ext2_save_block]
  685.         call    ext2_block_read
  686.  
  687.         test    eax, eax
  688.         jnz     .error_at_finish_block
  689.  
  690.         mov     ecx, edx
  691.         mov     esi, ebx
  692.         rep movsb                                       ; Copy last piece of block.
  693.         jmp     @F
  694.  
  695.     .end_read:
  696.         pop     ecx                                     ; Pop block counter in ECX.
  697.     @@:
  698.         pop     ebx                                     ; Number of bytes read.
  699.         call    ext2_unlock
  700.         pop     eax                                     ; If we were asked to read more, say EOF.
  701.         test    eax, eax
  702.         jz      @F
  703.  
  704.         mov     eax, ERROR_END_OF_FILE
  705.         ret
  706.     @@:
  707.         xor     eax, eax
  708.         ret
  709.        
  710.     .only_one_block:
  711.         mov     esi, ebx
  712.         rep movsb                                       ; Copy last piece of block.
  713.         jmp     .end_read
  714.        
  715.     .error_at_first_block:
  716.         pop     edx
  717.     .error_at_read_cycle:
  718.         pop     ebx
  719.     .error_at_finish_block:
  720.         pop     ecx edx
  721.         or      ebx, -1
  722.         push    eax
  723.         call    ext2_unlock
  724.         pop     eax
  725.         ret
  726.  
  727. ;---------------------------------------------------------------------
  728. ; Read file information from block device.
  729. ; Input:        esi + [esp + 4] = file name.
  730. ;               ebx = pointer to paramteres from sysfunc 70.
  731. ;               ebp = pointer to EXTFS structure.
  732. ; Output:       eax = error code.
  733. ;---------------------------------------------------------------------
  734. ext2_GetFileInfo:
  735.         call    ext2_lock
  736.         mov     edx, [ebx + 16]
  737.         cmp     byte [esi], 0
  738.         jz      .is_root
  739.  
  740.         push    edx
  741.         stdcall ext2_inode_find, [esp + 4 + 4]
  742.         mov     ebx, edx
  743.         pop     edx
  744.        
  745.         mov     esi, [ebp + EXTFS.ext2_save_inode]
  746.         test    eax, eax
  747.         jz      @F
  748.  
  749.         push    eax
  750.         call    ext2_unlock
  751.         pop     eax
  752.         ret
  753.  
  754.     .is_root:      
  755.         xor     ebx, ebx                                ; Clear out first char, since we don't want to set hidden flag on root.
  756.         mov     esi, [ebp + EXTFS.root_inode]
  757.  
  758.     @@:
  759.         xor     eax, eax
  760.         mov     edi, edx
  761.         mov     ecx, 40/4
  762.         rep stosd                                       ; Zero fill buffer.
  763.  
  764.         cmp     bl, '.'
  765.         jne     @F
  766.         or      dword [edx], FS_FT_HIDDEN
  767.  
  768.     @@:
  769.         test    [esi + EXT2_INODE_STRUC.i_mode], EXT2_S_IFDIR
  770.         jnz     @F                                      ; If a directory, don't put in file size.
  771.  
  772.         mov     eax, [esi + EXT2_INODE_STRUC.i_size]    ; Low file size.
  773.         mov     ebx, [esi + EXT2_INODE_STRUC.i_dir_acl] ; High file size.
  774.         mov     dword [edx+32], eax
  775.         mov     dword [edx+36], ebx
  776.  
  777.         xor     dword [edx], FS_FT_DIR                  ; Next XOR will clean this, to mark it as a file.
  778.     @@:
  779.         xor     dword [edx], FS_FT_DIR                  ; Mark as directory.
  780.  
  781.         lea     edi, [edx + 8]
  782.  
  783.         ; Store all time.
  784.         mov     eax, [esi + EXT2_INODE_STRUC.i_ctime]
  785.         xor     edx, edx
  786.         add     eax, 3054539008
  787.         adc     edx, 2
  788.         call    ntfs_datetime_to_bdfe.sec
  789.  
  790.         mov     eax, [esi + EXT2_INODE_STRUC.i_atime]
  791.         xor     edx, edx
  792.         add     eax, 3054539008
  793.         adc     edx, 2
  794.         call    ntfs_datetime_to_bdfe.sec
  795.  
  796.         mov     eax, [esi + EXT2_INODE_STRUC.i_mtime]
  797.         xor     edx, edx
  798.         add     eax, 3054539008
  799.         adc     edx, 2
  800.         call    ntfs_datetime_to_bdfe.sec
  801.  
  802.         call    ext2_unlock
  803.         xor     eax, eax
  804.         ret
  805.  
  806. ;---------------------------------------------------------------------
  807. ; Set file information for block device.
  808. ; Input:        esi + [esp + 4] = file name.
  809. ;               ebx = pointer to paramteres from sysfunc 70.
  810. ;               ebp = pointer to EXTFS structure.
  811. ; Output:       eax = error code.
  812. ;---------------------------------------------------------------------
  813. ext2_SetFileInfo:
  814.         push    edx esi edi ebx
  815.         call    ext2_lock
  816.         mov     edx, [ebx + 16]
  817.  
  818.         ; Is this read-only?
  819.         test    [ebp + EXTFS.partition_flags], EXT2_RO
  820.         jnz     .fail
  821.  
  822.         ; Not supported for root.
  823.         cmp     byte [esi], 0
  824.         je      .fail
  825.  
  826.     .get_inode:
  827.         push    edx
  828.         stdcall ext2_inode_find, [esp + 4 + 20]
  829.         pop     edx
  830.  
  831.         test    eax, eax
  832.         jnz     @F
  833.  
  834.         ; Save inode number.
  835.         push    esi
  836.         mov     esi, [ebp + EXTFS.ext2_save_inode]
  837.  
  838.         ; From the BDFE, we ignore read-only file flags, hidden file flags;
  839.         ; We ignore system file flags, file was archived or not.
  840.  
  841.         ; Also ignored is file creation time. ext2 stores "inode modification"
  842.         ; time in the ctime field, which is updated by the respective inode_write
  843.         ; procedure, and any writes on it would be overwritten anyway.
  844.  
  845.         ; Access time.
  846.         lea     edi, [esi + EXT2_INODE_STRUC.i_atime]
  847.         lea     esi, [edx + 16]
  848.         call    bdfe_to_unix_time
  849.  
  850.         ; Modification time.
  851.         add     esi, 8
  852.         add     edi, 8
  853.         call    bdfe_to_unix_time
  854.  
  855.         mov     ebx, [ebp + EXTFS.ext2_save_inode] ; Get address of inode into ebx.
  856.         pop     eax                             ; Get inode number in eax.
  857.         call    ext2_inode_write                ; eax contains error code, if any.
  858.         test    eax, eax
  859.         jnz     @F
  860.  
  861.         call    ext2_sb_update
  862.         ; Sync the disk.
  863.         mov     esi, [ebp + PARTITION.Disk]
  864.         call    disk_sync                       ; eax contains error code, if any.
  865.  
  866.     @@:
  867.         push    eax
  868.         call    ext2_unlock
  869.         pop     eax
  870.  
  871.         pop     ebx edi esi edx
  872.         ret
  873.  
  874.     .fail:
  875.         call    ext2_sb_update
  876.         ; Sync the disk.
  877.         mov     esi, [ebp + PARTITION.Disk]
  878.         call    disk_sync                       ; eax contains error code, if any.
  879.  
  880.         mov     eax, ERROR_UNSUPPORTED_FS
  881.         jmp     @B
  882.  
  883. ;---------------------------------------------------------------------
  884. ; Set file information for block device.
  885. ; Input:        esi + [esp + 4] = file name.
  886. ;               ebx = pointer to paramteres from sysfunc 70.
  887. ;               ebp = pointer to EXTFS structure.
  888. ; Output:       eax = error code.
  889. ;---------------------------------------------------------------------
  890. ext2_Delete:
  891.         push    ebx ecx edx esi edi
  892.         call    ext2_lock
  893.  
  894.         add     esi, [esp + 20 + 4]
  895.  
  896.         ; Can't delete root.
  897.         cmp     byte [esi], 0
  898.         jz      .error_access_denied
  899.  
  900.         push    esi
  901.         stdcall ext2_inode_find, 0
  902.         mov     ebx, esi
  903.         pop     esi
  904.  
  905.         test    eax, eax
  906.         jnz     .error_access_denied
  907.  
  908.         mov     edx, [ebp + EXTFS.ext2_save_inode]
  909.         movzx   edx, [edx + EXT2_INODE_STRUC.i_mode]
  910.         and     edx, EXT2_S_IFMT                                ; Get the mask.
  911.         cmp     edx, EXT2_S_IFDIR
  912.         jne     @F                                              ; If not a directory, we don't need to check if it's empty.
  913.  
  914.         call    ext2_dir_empty                                  ; 0 means directory is empty.
  915.  
  916.         test    eax, eax
  917.         jnz     .error_access_denied
  918.  
  919.     @@:
  920.         ; Find parent.
  921.         call    ext2_inode_find_parent
  922.         test    eax, eax
  923.         jnz     .error_access_denied
  924.         mov     eax, esi
  925.  
  926.         ; Save file/dir & parent inode.
  927.         push    ebx eax
  928.  
  929.         cmp     edx, EXT2_S_IFDIR
  930.         jne     @F      
  931.  
  932.         ; Unlink '.'
  933.         mov     eax, [esp + 4]
  934.         call    ext2_inode_unlink
  935.         cmp     eax, 0xFFFFFFFF
  936.         je      .error_stack8
  937.  
  938.         ; Unlink '..'
  939.         mov     eax, [esp + 4]
  940.         mov     ebx, [esp]
  941.         call    ext2_inode_unlink
  942.         cmp     eax, 0xFFFFFFFF
  943.         je      .error_stack8
  944.  
  945.     @@:
  946.         pop     eax
  947.         mov     ebx, [esp]
  948.         ; Unlink the inode.
  949.         call    ext2_inode_unlink
  950.         cmp     eax, 0xFFFFFFFF
  951.         je      .error_stack4
  952.        
  953.         ; If hardlinks aren't zero, shouldn't completely free.
  954.         test    eax, eax
  955.         jz      @F
  956.  
  957.         add     esp, 4
  958.         jmp     .disk_sync
  959.  
  960.     @@:
  961.         ; Read the inode.
  962.         mov     eax, [esp]
  963.         mov     ebx, [ebp + EXTFS.ext2_save_inode]
  964.         call    ext2_inode_read
  965.         test    eax, eax
  966.         jnz     .error_stack4
  967.        
  968.         ; Free inode data.
  969.         mov     esi, [ebp + EXTFS.ext2_save_inode]
  970.         xor     ecx, ecx
  971.  
  972.     @@:
  973.         push    ecx
  974.         call    ext2_get_inode_block
  975.         test    eax, eax
  976.         jnz     .error_stack8
  977.         mov     eax, ecx
  978.         pop     ecx
  979.  
  980.         ; If 0, we're done.
  981.         test    eax, eax
  982.         jz      @F
  983.  
  984.         call    ext2_block_free
  985.         test    eax, eax
  986.         jnz     .error_stack4
  987.  
  988.         inc     ecx
  989.         jmp     @B
  990.  
  991.     @@:
  992.         ; Clear the inode, and add deletion time.
  993.         mov     edi, [ebp + EXTFS.ext2_save_inode]
  994.         xor     eax, eax
  995.         mov     ecx, [ebp + EXTFS.inode_size]
  996.         rep stosb
  997.  
  998.         mov     edi, [ebp + EXTFS.ext2_save_inode]
  999.         add     edi, EXT2_INODE_STRUC.i_dtime
  1000.         call    current_unix_time
  1001.  
  1002.         ; Write the inode.
  1003.         mov     eax, [esp]
  1004.         mov     ebx, [ebp + EXTFS.ext2_save_inode]
  1005.         call    ext2_inode_write
  1006.         test    eax, eax
  1007.         jnz     .error_stack4
  1008.  
  1009.         ; Check if directory.
  1010.         cmp     edx, EXT2_S_IFDIR
  1011.         jne     @F
  1012.  
  1013.         ; If it is, decrement used_dirs_count.
  1014.  
  1015.         ; Get block group.
  1016.         mov     eax, [esp]
  1017.         dec     eax
  1018.         xor     edx, edx
  1019.         div     [ebp + EXTFS.superblock + EXT2_SB_STRUC.inodes_per_group]
  1020.  
  1021.         push    eax
  1022.         call    ext2_bg_read_desc
  1023.         test    eax, eax
  1024.         jz      .error_stack8
  1025.  
  1026.         dec     [eax + EXT2_BLOCK_GROUP_DESC.used_dirs_count]
  1027.        
  1028.         pop     eax
  1029.         call    ext2_bg_write_desc
  1030.  
  1031.     @@:
  1032.         pop     eax
  1033.         call    ext2_inode_free
  1034.         test    eax, eax
  1035.         jnz     .error_access_denied
  1036.  
  1037.     .disk_sync:
  1038.         call    ext2_sb_update
  1039.  
  1040.         ; Sync the disk.
  1041.         mov     esi, [ebp + PARTITION.Disk]
  1042.         call    disk_sync                       ; eax contains error code, if any.
  1043.  
  1044.     .return:    
  1045.         push    eax
  1046.         call    ext2_unlock
  1047.         pop     eax
  1048.  
  1049.         pop     edi esi edx ecx ebx
  1050.         ret
  1051.  
  1052.     .error_stack8:
  1053.         add     esp, 4
  1054.     .error_stack4:
  1055.         add     esp, 4
  1056.     .error_access_denied:
  1057.         call    ext2_sb_update
  1058.  
  1059.         ; Sync the disk.
  1060.         mov     esi, [ebp + PARTITION.Disk]
  1061.         call    disk_sync                       ; eax contains error code, if any.
  1062.  
  1063.         mov     eax, ERROR_ACCESS_DENIED
  1064.         jmp     .return
  1065.  
  1066. ;---------------------------------------------------------------------
  1067. ; Set file information for block device.
  1068. ; Input:        esi + [esp + 4] = file name.
  1069. ;               ebx = pointer to paramteres from sysfunc 70.
  1070. ;               ebp = pointer to EXTFS structure.
  1071. ; Output:       eax = error code.
  1072. ;---------------------------------------------------------------------
  1073. ext2_CreateFolder:
  1074.         push    ebx ecx edx esi edi
  1075.         call    ext2_lock
  1076.  
  1077.         add     esi, [esp + 20 + 4]
  1078.  
  1079.         ; Can't create root, but for CreateFile already existing directory is success.
  1080.         cmp     byte [esi], 0
  1081.         jz      .success
  1082.  
  1083.         push    esi
  1084.         stdcall ext2_inode_find, 0
  1085.         pop     esi
  1086.  
  1087.         ; If the directory is there, we've succeeded.
  1088.         test    eax, eax
  1089.         jz      .success
  1090.  
  1091.         ; Find parent.
  1092.         call    ext2_inode_find_parent
  1093.         test    eax, eax
  1094.         jnz     .error
  1095.  
  1096.         ; Inode ID for preference.
  1097.         mov     eax, esi
  1098.         call    ext2_inode_alloc
  1099.         test    eax, eax
  1100.         jnz     .error_full
  1101.  
  1102.         ; Save allocated inode in EDX; filename is in EDI; parent ID in ESI.
  1103.         mov     edx, ebx
  1104.  
  1105.         push    edi
  1106.  
  1107.         xor     al, al
  1108.         mov     edi, [ebp + EXTFS.ext2_temp_inode]
  1109.         mov     ecx, [ebp + EXTFS.inode_size]
  1110.         rep stosb
  1111.  
  1112.         mov     edi, [ebp + EXTFS.ext2_temp_inode]
  1113.         add     edi, EXT2_INODE_STRUC.i_atime
  1114.         call    current_unix_time
  1115.  
  1116.         add     edi, 8
  1117.         call    current_unix_time
  1118.  
  1119.         pop     edi
  1120.  
  1121.         mov     ebx, [ebp + EXTFS.ext2_temp_inode]
  1122.         mov     [ebx + EXT2_INODE_STRUC.i_mode], EXT2_S_IFDIR
  1123.         mov     eax, edx
  1124.         call    ext2_inode_write
  1125.         test    eax, eax
  1126.         jnz     .error
  1127.  
  1128.         ; Link to self.
  1129.         push    edx esi
  1130.  
  1131.         mov     eax, edx
  1132.         mov     ebx, eax
  1133.         mov     dl, EXT2_FT_DIR
  1134.         mov     esi, self_link
  1135.         call    ext2_inode_link
  1136.  
  1137.         pop     esi edx
  1138.  
  1139.         test    eax, eax
  1140.         jnz     .error
  1141.  
  1142.         ; Link to parent.
  1143.         push    edx esi
  1144.  
  1145.         mov     eax, ebx
  1146.         mov     ebx, esi
  1147.         mov     dl, EXT2_FT_DIR
  1148.         mov     esi, parent_link
  1149.         call    ext2_inode_link
  1150.  
  1151.         pop     esi edx
  1152.  
  1153.         test    eax, eax
  1154.         jnz     .error
  1155.  
  1156.         ; Link parent to child.
  1157.         mov     eax, esi
  1158.         mov     ebx, edx
  1159.         mov     esi, edi
  1160.         mov     dl, EXT2_FT_DIR
  1161.         call    ext2_inode_link
  1162.         test    eax, eax
  1163.         jnz     .error
  1164.  
  1165.         ; Get block group descriptor for allocated inode's block.
  1166.         mov     eax, ebx
  1167.         dec     eax
  1168.         xor     edx, edx
  1169.        
  1170.         ; EAX = block group.
  1171.         div     [ebp + EXTFS.superblock + EXT2_SB_STRUC.inodes_per_group]
  1172.         mov     edx, eax
  1173.  
  1174.         call    ext2_bg_read_desc
  1175.         test    eax, eax
  1176.         jz      .error
  1177.  
  1178.         inc     [eax + EXT2_BLOCK_GROUP_DESC.used_dirs_count]
  1179.         mov     eax, edx
  1180.         call    ext2_bg_write_desc
  1181.         test    eax, eax
  1182.         jnz     .error
  1183.  
  1184.     .success:
  1185.         call    ext2_sb_update
  1186.  
  1187.         ; Sync the disk.
  1188.         mov     esi, [ebp + PARTITION.Disk]
  1189.         call    disk_sync                       ; eax contains error code, if any.
  1190.  
  1191.     .return:
  1192.         push    eax
  1193.         call    ext2_unlock
  1194.         pop     eax
  1195.  
  1196.         pop     edi esi edx ecx ebx
  1197.         ret
  1198.  
  1199.     .error:
  1200.         call    ext2_sb_update
  1201.  
  1202.         ; Sync the disk.
  1203.         mov     esi, [ebp + PARTITION.Disk]
  1204.         call    disk_sync                       ; eax contains error code, if any.
  1205.        
  1206.         mov     eax, ERROR_ACCESS_DENIED
  1207.         jmp     .return
  1208.  
  1209.     .error_full:
  1210.         mov     eax, ERROR_DISK_FULL
  1211.         jmp     .return
  1212.  
  1213. self_link:   db ".", 0
  1214. parent_link: db "..", 0
  1215.  
  1216. ext2_Rewrite:
  1217. ext2_Write:
  1218. ext2_SetFileEnd:
  1219.         xor     ebx, ebx
  1220.         mov     eax, ERROR_UNSUPPORTED_FS
  1221.         ret
  1222.