Subversion Repositories Kolibri OS

Rev

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

  1. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2. ;;                                                              ;;
  3. ;; Contains ext2 initialization, plus syscall handling code.    ;;
  4. ;;                                                              ;;
  5. ;; Copyright (C) KolibriOS team 2013-2014. All rights reserved. ;;
  6. ;; Distributed under terms of the GNU General Public License    ;;
  7. ;;                                                              ;;
  8. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  9.  
  10. $Revision: 4891 $
  11.  
  12.  
  13. include 'ext2.inc'
  14. include 'blocks.inc'
  15. include 'inode.inc'
  16. include 'resource.inc'
  17.  
  18. iglobal
  19. align 4
  20. ext2_user_functions:
  21.         dd      ext2_free
  22.         dd      (ext2_user_functions_end - ext2_user_functions - 4) / 4
  23.         dd      ext2_Read
  24.         dd      ext2_ReadFolder
  25.         dd      ext2_Rewrite
  26.         dd      ext2_Write
  27.         dd      ext2_SetFileEnd
  28.         dd      ext2_GetFileInfo
  29.         dd      ext2_SetFileInfo
  30.         dd      0
  31.         dd      ext2_Delete
  32.         dd      ext2_CreateFolder
  33. ext2_user_functions_end:
  34. endg
  35.  
  36. ;---------------------------------------------------------------------
  37. ; Locks up an ext2 partition.
  38. ; Input:        ebp = pointer to EXTFS.
  39. ;---------------------------------------------------------------------
  40. proc ext2_lock
  41.         lea     ecx, [ebp + EXTFS.lock]
  42.         jmp     mutex_lock
  43. endp
  44.  
  45. ;---------------------------------------------------------------------
  46. ; Unlocks up an ext2 partition.
  47. ; Input:        ebp = pointer to EXTFS.
  48. ;---------------------------------------------------------------------
  49. proc ext2_unlock
  50.         lea     ecx, [ebp + EXTFS.lock]
  51.         jmp     mutex_unlock
  52. endp
  53.  
  54. ;---------------------------------------------------------------------
  55. ; Check if it's a valid ext* superblock.
  56. ; Input:        ebp:       first three fields of PARTITION structure.
  57. ;               ebx + 512: points to 512-bytes buffer that can be used for anything.
  58. ; Output:       eax:       clear if can't create partition; set to EXTFS otherwise.
  59. ;---------------------------------------------------------------------
  60. proc ext2_create_partition
  61.         push    ebx
  62.  
  63.         mov     eax, 2                          ; Superblock starts at 1024-bytes.
  64.         add     ebx, 512                        ; Get pointer to fs-specific buffer.
  65.         call    fs_read32_sys
  66.         test    eax, eax
  67.         jnz     .fail
  68.  
  69.         ; Allowed 1KiB, 2KiB, 4KiB, 8KiB.
  70.         cmp     [ebx + EXT2_SB_STRUC.log_block_size], 3  
  71.         ja      .fail
  72.  
  73.         cmp     [ebx + EXT2_SB_STRUC.magic], EXT2_SUPER_MAGIC
  74.         jne     .fail
  75.  
  76.         cmp     [ebx + EXT2_SB_STRUC.state], EXT2_VALID_FS
  77.         jne     .fail
  78.  
  79.         ; Can't have no inodes per group.
  80.         cmp     [ebx + EXT2_SB_STRUC.inodes_per_group], 0
  81.         je      .fail
  82.  
  83.         ; If incompatible features required, unusable superblock.
  84.         mov     eax, [ebx + EXT2_SB_STRUC.feature_incompat]
  85.         test    eax, not EXT4_FEATURE_INCOMPAT_SUPP
  86.         jz      .setup
  87.  
  88.     .fail:
  89.         ; Not a (valid/usable) EXT2 superblock.
  90.         pop     ebx
  91.         xor     eax, eax
  92.         ret
  93.  
  94.     .setup:
  95.         movi    eax, sizeof.EXTFS
  96.         call    malloc
  97.         test    eax, eax
  98.         jz      ext2_create_partition.fail
  99.  
  100.         ; Store the first sector field.
  101.         mov     ecx, dword[ebp + PARTITION.FirstSector]
  102.         mov     dword[eax + EXTFS.FirstSector], ecx
  103.         mov     ecx, dword [ebp + PARTITION.FirstSector+4]
  104.         mov     dword [eax + EXTFS.FirstSector+4], ecx
  105.  
  106.         ; The length field.
  107.         mov     ecx, dword[ebp + PARTITION.Length]
  108.         mov     dword[eax + EXTFS.Length], ecx
  109.         mov     ecx, dword[ebp + PARTITION.Length+4]
  110.         mov     dword[eax + EXTFS.Length+4], ecx
  111.  
  112.         ; The disk field.
  113.         mov     ecx, [ebp + PARTITION.Disk]
  114.         mov     [eax + EXTFS.Disk], ecx
  115.  
  116.         mov     [eax + EXTFS.FSUserFunctions], ext2_user_functions
  117.  
  118.         push    ebp esi edi
  119.  
  120.         mov     ebp, eax
  121.         lea     ecx, [eax + EXTFS.lock]
  122.         call    mutex_init
  123.  
  124.         ; Copy superblock from buffer to reserved memory.
  125.         mov     esi, ebx
  126.         lea     edi, [ebp + EXTFS.superblock]
  127.         mov     ecx, 512/4
  128.         rep movsd
  129.  
  130.         ; Get total groups.
  131.         mov     eax, [ebx + EXT2_SB_STRUC.blocks_count]
  132.         sub     eax, [ebx + EXT2_SB_STRUC.first_data_block]
  133.         dec     eax
  134.         xor     edx, edx
  135.         div     [ebx + EXT2_SB_STRUC.blocks_per_group]
  136.         inc     eax
  137.         mov     [ebp + EXTFS.groups_count], eax
  138.  
  139.         ; Get log(block_size), such that 1,2,3,4 equ 1KiB,2KiB,4KiB,8KiB.
  140.         mov     ecx, [ebx + EXT2_SB_STRUC.log_block_size]
  141.         inc     ecx
  142.         mov     [ebp + EXTFS.log_block_size], ecx
  143.  
  144.         ; 512-byte blocks in ext2 blocks.
  145.         mov     eax, 1
  146.         shl     eax, cl
  147.         mov     [ebp + EXTFS.count_block_in_block], eax
  148.  
  149.         ; Get block_size/4 (we'll find square later).
  150.         shl     eax, 7
  151.         mov     [ebp + EXTFS.count_pointer_in_block], eax
  152.         mov     edx, eax
  153.  
  154.         ; Get block size.
  155.         shl     eax, 2
  156.         mov     [ebp + EXTFS.block_size], eax
  157.  
  158.         ; Save block size for 2 kernel_alloc calls.
  159.         push    eax eax
  160.  
  161.         mov     eax, edx
  162.         mul     edx
  163.         mov     [ebp + EXTFS.count_pointer_in_block_square], eax
  164.  
  165.         ; Have temporary block storage for get_inode procedure, and one for global procedure.
  166.         KERNEL_ALLOC [ebp + EXTFS.ext2_save_block], .error
  167.         KERNEL_ALLOC [ebp + EXTFS.ext2_temp_block], .error
  168.        
  169.         mov     [ebp + EXTFS.partition_flags], 0x00000000
  170.         mov     eax, [ebx + EXT2_SB_STRUC.feature_ro_compat]
  171.         and     eax, not EXT2_FEATURE_RO_COMPAT_SUPP
  172.         jnz     .read_only
  173.  
  174.         mov     eax, [ebx + EXT2_SB_STRUC.feature_incompat]
  175.         and     eax, EXT4_FEATURE_INCOMPAT_W_NOT_SUPP
  176.         jz      @F
  177.  
  178.     .read_only:
  179.         ; Mark as read-only.
  180.         or      [ebp + EXTFS.partition_flags], EXT2_RO
  181.     @@:
  182.         mov     ecx, [ebx + EXT2_SB_STRUC.blocks_per_group]
  183.         mov     [ebp + EXTFS.blocks_per_group], ecx
  184.  
  185.         movzx   ecx, word[ebx + EXT2_SB_STRUC.inode_size]
  186.         mov     [ebp + EXTFS.inode_size], ecx
  187.  
  188.         ; Allocate for three inodes (loop would be overkill).
  189.         push    ecx ecx ecx
  190.  
  191.         KERNEL_ALLOC [ebp + EXTFS.ext2_save_inode], .error
  192.         KERNEL_ALLOC [ebp + EXTFS.ext2_temp_inode], .error
  193.         KERNEL_ALLOC [ebp + EXTFS.root_inode], .error
  194.  
  195.         ; Read root inode.
  196.         mov     ebx, eax
  197.         mov     eax, EXT2_ROOT_INO
  198.         call    ext2_inode_read
  199.  
  200.         test    eax, eax
  201.         jnz     .error
  202.  
  203.         ;call    ext2_sb_update
  204.         ; Sync the disk.
  205.         ;mov     esi, [ebp + PARTITION.Disk]
  206.         ;call    disk_sync                       ; eax contains error code, if any.
  207.  
  208.         mov     eax, ebp                        ; Return pointer to EXTFS.
  209.         pop     edi esi ebp ebx
  210.         ret
  211.  
  212.     ; Error in setting up.
  213.     .error:        
  214.         ; Free save block.
  215.         KERNEL_FREE [ebp + EXTFS.ext2_save_block], .fail
  216.  
  217.         ; Temporary block.
  218.         KERNEL_FREE [ebp + EXTFS.ext2_temp_block], .fail
  219.  
  220.         ; All inodes.
  221.         KERNEL_FREE [ebp + EXTFS.ext2_save_inode], .fail
  222.         KERNEL_FREE [ebp + EXTFS.ext2_temp_inode], .fail
  223.         KERNEL_FREE [ebp + EXTFS.root_inode], .fail
  224.  
  225.         mov     eax, ebp
  226.         call    free
  227.  
  228.         jmp     .fail
  229. endp
  230.  
  231. ; FUNCTIONS PROVIDED BY SYSCALLS.
  232.  
  233. ;---------------------------------------------------------------------
  234. ; Frees up all ext2 structures.
  235. ; Input:        eax = pointer to EXTFS.
  236. ;---------------------------------------------------------------------
  237. proc ext2_free
  238.         push    ebp
  239.  
  240.         xchg    ebp, eax
  241.         stdcall kernel_free, [ebp+EXTFS.ext2_save_block]
  242.         stdcall kernel_free, [ebp+EXTFS.ext2_temp_block]
  243.         stdcall kernel_free, [ebp+EXTFS.ext2_save_inode]
  244.         stdcall kernel_free, [ebp+EXTFS.ext2_temp_inode]
  245.         stdcall kernel_free, [ebp+EXTFS.root_inode]
  246.  
  247.         xchg    ebp, eax
  248.         call    free
  249.  
  250.         pop     ebp
  251.         ret
  252. endp
  253.  
  254. ;---------------------------------------------------------------------
  255. ; Read disk folder.
  256. ; Input:        ebp = pointer to EXTFS structure.
  257. ;               esi + [esp + 4] = file name.
  258. ;               ebx = pointer to parameters from sysfunc 70.
  259. ; Output:       ebx = blocks read (or 0xFFFFFFFF, folder not found)
  260. ;               eax = error code (0 implies no error)
  261. ;---------------------------------------------------------------------
  262. ext2_ReadFolder:
  263.         ;DEBUGF  1, "Reading folder.\n"
  264.         call    ext2_lock
  265.         cmp     byte [esi], 0
  266.         jz      .root_folder
  267.  
  268.         push    ebx
  269.         stdcall ext2_inode_find, [esp + 4 + 4]            ; Get inode.
  270.         pop     ebx
  271.  
  272.         mov     esi, [ebp + EXTFS.ext2_save_inode]
  273.         test    eax, eax
  274.         jnz     .error_ret
  275.  
  276.         ; If not a directory, then return with error.
  277.         test    [esi + EXT2_INODE_STRUC.i_mode], EXT2_S_IFDIR
  278.         jz      .error_not_found
  279.         jmp     @F
  280.  
  281.     .root_folder:
  282.         mov     esi, [ebp + EXTFS.root_inode]
  283.         test    [esi + EXT2_INODE_STRUC.i_mode], EXT2_S_IFDIR
  284.         jz      .error_root
  285.  
  286.         ; Copy the inode.
  287.         mov     edi, [ebp + EXTFS.ext2_save_inode]
  288.         mov     ecx, [ebp + EXTFS.inode_size]
  289.         shr     ecx, 2
  290.        
  291.         push    edi
  292.         rep movsd
  293.         pop     esi
  294.  
  295.     @@:
  296.         cmp     [esi + EXT2_INODE_STRUC.i_size], 0      ; Folder is empty.
  297.         je      .error_empty_dir
  298.        
  299.         mov     edx, [ebx + 16]
  300.         push    edx                                     ; Result address [edi + 28].
  301.         push    0                                       ; End of the current block in folder [edi + 24]
  302.         push    dword[ebx + 12]                         ; Blocks to read [edi + 20]
  303.         push    dword[ebx + 4]                          ; The first wanted file [edi + 16]
  304.         push    dword[ebx + 8]                          ; Flags [edi + 12]
  305.         push    0                                       ; Read files [edi + 8]
  306.         push    0                                       ; Files in folder [edi + 4]
  307.         push    0                                       ; Number of blocks read in dir (and current block index) [edi]
  308.  
  309.         ; Fill header with zeroes.
  310.         mov     edi, edx
  311.         mov     ecx, 32/4
  312.         rep stosd
  313.        
  314.         mov     edi, esp                                ; edi = pointer to local variables.
  315.         add     edx, 32                                 ; edx = mem to return.
  316.  
  317.         xor     ecx, ecx                                ; Get number of first block.
  318.         call    ext2_inode_get_block
  319.         test    eax, eax
  320.         jnz     .error_get_block
  321.  
  322.         mov     eax, ecx
  323.         mov     ebx, [ebp + EXTFS.ext2_save_block]
  324.         call    ext2_block_read                          ; Read the block.
  325.         test    eax, eax
  326.         jnz     .error_get_block
  327.  
  328.         mov     eax, ebx                                ; esi: current directory record
  329.         add     eax, [ebp + EXTFS.block_size]
  330.        
  331.         mov     [edi + 24], eax
  332.  
  333.         mov     ecx, [edi + 16]                         ; ecx = first wanted (flags ommited)
  334.  
  335.     .find_wanted_start:
  336.         jecxz   .find_wanted_end
  337.        
  338.     .find_wanted_cycle:
  339.         cmp     [ebx + EXT2_DIR_STRUC.inode], 0         ; Don't count unused inode in total files.
  340.         jz      @F
  341.  
  342.         inc     dword [edi + 4]                         ; EXT2 files in folder.
  343.         dec     ecx
  344.     @@:
  345.         movzx   eax, [ebx + EXT2_DIR_STRUC.rec_len]
  346.        
  347.         cmp     eax, 12                                 ; Minimum record length.
  348.         jb      .error_bad_len
  349.         test    eax, 0x3                                ; Record length must be divisible by four.
  350.         jnz     .error_bad_len
  351.  
  352.         sub     [esi + EXT2_INODE_STRUC.i_size], eax    ; Subtract "processed record" length directly from inode.
  353.         add     ebx, eax                                ; Go to next record.
  354.         cmp     ebx, [edi + 24]                         ; If not reached the next block, continue.
  355.         jb      .find_wanted_start
  356.  
  357.         push    .find_wanted_start
  358.    .end_block:                                          ; Get the next block.
  359.         cmp     [esi + EXT2_INODE_STRUC.i_size], 0
  360.         jle     .end_dir
  361.  
  362.         inc     dword [edi]                             ; Number of blocks read.
  363.        
  364.         ; Read the next block.
  365.         push    ecx
  366.         mov     ecx, [edi]
  367.         call    ext2_inode_get_block
  368.         test    eax, eax
  369.         jnz     .error_get_block
  370.  
  371.         mov     eax, ecx
  372.         mov     ebx, [ebp + EXTFS.ext2_save_block]
  373.         call    ext2_block_read
  374.         test    eax, eax
  375.         jnz     .error_get_block
  376.         pop     ecx
  377.  
  378.         mov     eax, ebx
  379.         add     eax, [ebp + EXTFS.block_size]
  380.         mov     [edi + 24], eax                         ; Update the end of the current block variable.  
  381.         ret
  382.  
  383.     .wanted_end:
  384.         loop    .find_wanted_cycle                      ; Skip files till we reach wanted one.
  385.        
  386.     ; First requisite file.
  387.     .find_wanted_end:
  388.         mov     ecx, [edi + 20]
  389.     .wanted_start:                                      ; Look for first_wanted + count.
  390.         jecxz   .wanted_end
  391.  
  392.         cmp     [ebx + EXT2_DIR_STRUC.inode], 0         ; if (inode == 0): not used;
  393.         jz      .empty_rec
  394.  
  395.         ; Increment "files in dir" and "read files" count.
  396.         inc     dword [edi + 8]
  397.         inc     dword [edi + 4]
  398.  
  399.         push    edi ecx
  400.         mov     edi, edx                                ; Zero out till the name field.
  401.         xor     eax, eax
  402.         mov     ecx, 40 / 4
  403.         rep stosd
  404.         pop     ecx edi
  405.  
  406.         push    ebx edi edx
  407.         mov     eax, [ebx + EXT2_DIR_STRUC.inode]       ; Get the child inode.
  408.         mov     ebx, [ebp + EXTFS.ext2_temp_inode]
  409.         call    ext2_inode_read
  410.         test    eax, eax
  411.         jnz     .error_read_subinode
  412.  
  413.         lea     edi, [edx + 8]
  414.  
  415.         mov     eax, [ebx + EXT2_INODE_STRUC.i_ctime]   ; Convert time in NTFS format.
  416.         xor     edx, edx
  417.         add     eax, 3054539008                         ; (369 * 365 + 89) * 24 * 3600
  418.         adc     edx, 2
  419.         call    ntfs_datetime_to_bdfe.sec
  420.  
  421.         mov     eax, [ebx + EXT2_INODE_STRUC.i_atime]
  422.         xor     edx, edx
  423.         add     eax, 3054539008
  424.         adc     edx, 2
  425.         call    ntfs_datetime_to_bdfe.sec
  426.  
  427.         mov     eax, [ebx + EXT2_INODE_STRUC.i_mtime]
  428.         xor     edx, edx
  429.         add     eax, 3054539008
  430.         adc     edx, 2
  431.         call    ntfs_datetime_to_bdfe.sec
  432.  
  433.         pop     edx
  434.         test    [ebx + EXT2_INODE_STRUC.i_mode], EXT2_S_IFDIR ; If folder, don't report size.
  435.         jnz     @F
  436.  
  437.         mov     eax, [ebx + EXT2_INODE_STRUC.i_size]    ; Low size
  438.         stosd
  439.         mov     eax, [ebx + EXT2_INODE_STRUC.i_dir_acl] ; High size
  440.         stosd
  441.  
  442.         xor     dword [edx], FS_FT_DIR                  ; Mark as file.
  443.     @@:
  444.         xor     dword [edx], FS_FT_DIR                  ; Mark as directory.
  445.  
  446.         ; Copy name after converting from UTF-8 to CP866.
  447.         push    ecx esi
  448.         mov     esi, [esp + 12]
  449.         movzx   ecx, [esi + EXT2_DIR_STRUC.name_len]
  450.         lea     edi, [edx + 40]
  451.         lea     esi, [esi + EXT2_DIR_STRUC.name]
  452.         call    utf8_to_cp866
  453.         and     byte [edi], 0
  454.         pop     esi ecx edi ebx
  455.  
  456.         cmp     byte [edx + 40], '.'                    ; If it begins with ".", mark it as hidden.
  457.         jne     @F
  458.         or      dword [edx], FS_FT_HIDDEN
  459.    
  460.     @@:
  461.         add     edx, 40 + 264                           ; Go to next record.
  462.         dec     ecx
  463.     .empty_rec:
  464.         movzx   eax, [ebx + EXT2_DIR_STRUC.rec_len]
  465.  
  466.         cmp     eax, 12                                 ; Illegal length.
  467.         jb      .error_bad_len
  468.         test    eax, 0x3                                ; Not a multiple of four.
  469.         jnz     .error_bad_len
  470.  
  471.         sub     [esi + EXT2_INODE_STRUC.i_size], eax    ; Subtract directly from the inode.
  472.         add     ebx, eax    
  473.         cmp     ebx, [edi + 24]                         ; Are we at the end of the block?
  474.         jb      .wanted_start
  475.  
  476.         push    .wanted_start
  477.         jmp     .end_block
  478.  
  479.     .end_dir:                                           ; End of the directory.
  480.         call    ext2_unlock
  481.         mov     edx, [edi + 28]                         ; Address of where to return data.
  482.         mov     ebx, [edi + 8]                          ; EXT2_read_in_folder
  483.         mov     ecx, [edi + 4]                          ; EXT2_files_in_folder
  484.         mov     dword [edx], 1                          ; Version
  485.         mov     [edx + 4], ebx
  486.         mov     [edx + 8], ecx
  487.        
  488.         lea     esp, [edi + 32]
  489.        
  490.         xor     eax, eax                                ; Reserved in current implementation.
  491.         lea     edi, [edx + 12]
  492.         mov     ecx, 20 / 4
  493.         rep stosd
  494.  
  495.         ;DEBUGF  1, "Returning with: %x.\n", eax
  496.         ret
  497.  
  498.     .error_bad_len:
  499.         mov     eax, ERROR_FS_FAIL
  500.  
  501.     .error_read_subinode:
  502.     .error_get_block:
  503.         ; Fix the stack.
  504.         lea     esp, [edi + 32]
  505.  
  506.     .error_ret:
  507.         or      ebx, -1
  508.         push    eax
  509.         call    ext2_unlock
  510.         pop     eax
  511.         ;DEBUGF  1, "Returning with: %x.\n", eax
  512.         ret
  513.        
  514.     .error_empty_dir:                                   ; inode of folder without blocks.
  515.     .error_root:                                        ; Root has to be a folder.
  516.         mov     eax, ERROR_FS_FAIL
  517.         jmp     .error_ret
  518.  
  519.     .error_not_found:                                   ; Directory not found.
  520.         mov     eax, ERROR_FILE_NOT_FOUND
  521.         jmp     .error_ret
  522.  
  523. ;---------------------------------------------------------------------
  524. ; Read file from the hard disk.
  525. ; Input:        esi + [esp + 4] = points to file name.
  526. ;               ebx = pointer to paramteres from sysfunc 70.
  527. ;               ebp = pointer to EXTFS structure.
  528. ; Output:       ebx = bytes read (0xFFFFFFFF -> file not found)
  529. ;               eax = error code (0 implies no error)
  530. ;---------------------------------------------------------------------
  531. ext2_Read:
  532.         ;DEBUGF  1, "Attempting read.\n"
  533.         call    ext2_lock
  534.         cmp     byte [esi], 0
  535.         jnz     @F
  536.  
  537.     .this_is_nofile:
  538.         call    ext2_unlock
  539.         or      ebx, -1
  540.         mov     eax, ERROR_ACCESS_DENIED
  541.         ret
  542.  
  543.     @@:
  544.         push    ebx
  545.         stdcall ext2_inode_find, [esp + 4 + 4]
  546.         pop     ebx
  547.  
  548.         mov     esi, [ebp + EXTFS.ext2_save_inode]
  549.         test    eax, eax
  550.         jz      @F
  551.  
  552.         call    ext2_unlock
  553.         or      ebx, -1
  554.         mov     eax, ERROR_FILE_NOT_FOUND
  555.         ret
  556.  
  557.     @@:
  558.         mov     ax, [esi + EXT2_INODE_STRUC.i_mode]
  559.         and     ax, EXT2_S_IFMT                         ; Leave the file format in AX.
  560.  
  561.         ; Check if file.
  562.         cmp     ax, EXT2_S_IFREG
  563.         jne     .this_is_nofile
  564.  
  565.         mov     edi, [ebx + 16]
  566.         mov     ecx, [ebx + 12]
  567.  
  568.         mov     eax, [ebx + 4]
  569.         mov     edx, [ebx + 8]                          ; edx:eax = start byte number.
  570.  
  571.         ; Check if file is big enough for us.
  572.         cmp     [esi + EXT2_INODE_STRUC.i_dir_acl], edx
  573.         ja      .size_greater
  574.         jb      .size_less
  575.  
  576.         cmp     [esi + EXT2_INODE_STRUC.i_size], eax
  577.         ja      .size_greater
  578.  
  579.     .size_less:
  580.         call    ext2_unlock
  581.         xor     ebx, ebx
  582.         mov     eax, ERROR_END_OF_FILE
  583.         ret
  584.        
  585.     @@:
  586.     .size_greater:
  587.         add     eax, ecx                                ; Get last byte.
  588.         adc     edx, 0
  589.  
  590.         ; Check if we've to read whole file, or till requested.
  591.         cmp     [esi + EXT2_INODE_STRUC.i_dir_acl], edx
  592.         ja      .read_till_requested
  593.         jb      .read_whole_file
  594.         cmp     [esi + EXT2_INODE_STRUC.i_size], eax
  595.         jae     .read_till_requested
  596.  
  597.     .read_whole_file:
  598.         push    1                                       ; Read till the end of file.
  599.         mov     ecx, [esi + EXT2_INODE_STRUC.i_size]
  600.         sub     ecx, [ebx + 4]                          ; To read = (size - starting byte)
  601.         jmp     @F
  602.  
  603.     .read_till_requested:
  604.         push    0                                       ; Read as much as requested.
  605.  
  606.     @@:
  607.         ; ecx = bytes to read.
  608.         ; edi = return memory
  609.         ; [esi] = starting byte.
  610.  
  611.         push    ecx                                     ; Number of bytes to read.
  612.        
  613.         ; Get part of the first block.
  614.         mov     edx, [ebx + 8]
  615.         mov     eax, [ebx + 4]
  616.         div     [ebp + EXTFS.block_size]
  617.  
  618.         push    eax                                     ; Save block counter to stack.
  619.        
  620.         push    ecx
  621.         mov     ecx, eax
  622.         call    ext2_inode_get_block
  623.         test    eax, eax
  624.         jnz     .error_at_first_block
  625.  
  626.         mov     ebx, [ebp + EXTFS.ext2_save_block]
  627.         mov     eax, ecx
  628.         call    ext2_block_read
  629.         test    eax, eax
  630.         jnz     .error_at_first_block
  631.  
  632.         pop     ecx
  633.         ; Get index inside block.
  634.         add     ebx, edx
  635.  
  636.         neg     edx
  637.         add     edx, [ebp + EXTFS.block_size]          ; Get number of bytes in this block.
  638.  
  639.         ; If it's smaller than total bytes to read, then only one block.
  640.         cmp     ecx, edx
  641.         jbe     .only_one_block
  642.  
  643.         mov     eax, ecx
  644.         sub     eax, edx
  645.         mov     ecx, edx
  646.  
  647.         push    esi
  648.         mov     esi, ebx
  649.         rep movsb                                       ; Copy part of 1st block.
  650.         pop     esi
  651.  
  652.         ; eax -> bytes to read.
  653.     .calc_blocks_count:
  654.         mov     ebx, edi                                ; Read the block in ebx.
  655.         xor     edx, edx
  656.         div     [ebp + EXTFS.block_size]                ; Get number of bytes in last block in edx.
  657.         mov     edi, eax                                ; Get number of blocks in edi.
  658.  
  659.     @@:
  660.         ; Test if all blocks are done.
  661.         test    edi, edi
  662.         jz      .finish_block
  663.        
  664.         inc     dword [esp]
  665.         mov     ecx, [esp]
  666.         call    ext2_inode_get_block
  667.  
  668.         test    eax, eax
  669.         jnz     .error_at_read_cycle
  670.  
  671.         mov     eax, ecx                                ; ebx already contains desired values.
  672.         call    ext2_block_read
  673.  
  674.         test    eax, eax
  675.         jnz     .error_at_read_cycle
  676.  
  677.         add     ebx, [ebp + EXTFS.block_size]
  678.  
  679.         dec     edi
  680.         jmp     @B
  681.  
  682.     ; In edx -- number of bytes in the last block.
  683.     .finish_block:          
  684.         test    edx, edx
  685.         jz      .end_read
  686.  
  687.         pop     ecx                                     ; Pop block counter in ECX.
  688.         inc     ecx
  689.         call    ext2_inode_get_block
  690.        
  691.         test    eax, eax
  692.         jnz     .error_at_finish_block
  693.  
  694.         mov     edi, ebx
  695.         mov     eax, ecx
  696.         mov     ebx, [ebp + EXTFS.ext2_save_block]
  697.         call    ext2_block_read
  698.  
  699.         test    eax, eax
  700.         jnz     .error_at_finish_block
  701.  
  702.         mov     ecx, edx
  703.         mov     esi, ebx
  704.         rep movsb                                       ; Copy last piece of block.
  705.         jmp     @F
  706.  
  707.     .end_read:
  708.         pop     ecx                                     ; Pop block counter in ECX.
  709.     @@:
  710.         pop     ebx                                     ; Number of bytes read.
  711.         call    ext2_unlock
  712.         pop     eax                                     ; If we were asked to read more, say EOF.
  713.         test    eax, eax
  714.         jz      @F
  715.  
  716.         mov     eax, ERROR_END_OF_FILE
  717.         ret
  718.     @@:
  719.         xor     eax, eax
  720.         ;DEBUGF  1, "Returning with: %x.\n", eax
  721.         ret
  722.        
  723.     .only_one_block:
  724.         mov     esi, ebx
  725.         rep movsb                                       ; Copy last piece of block.
  726.         jmp     .end_read
  727.        
  728.     .error_at_first_block:
  729.         pop     edx
  730.     .error_at_read_cycle:
  731.         pop     ebx
  732.     .error_at_finish_block:
  733.         pop     ecx edx
  734.         or      ebx, -1
  735.         push    eax
  736.         call    ext2_unlock
  737.         pop     eax
  738.  
  739.         ;DEBUGF  1, "Returning with: %x.\n", eax
  740.         ret
  741.  
  742. ;---------------------------------------------------------------------
  743. ; Read file information from block device.
  744. ; Input:        esi + [esp + 4] = file name.
  745. ;               ebx = pointer to paramteres from sysfunc 70.
  746. ;               ebp = pointer to EXTFS structure.
  747. ; Output:       eax = error code.
  748. ;---------------------------------------------------------------------
  749. ext2_GetFileInfo:
  750.         ;DEBUGF  1, "Calling for file info, for: %s.\n", esi
  751.         call    ext2_lock
  752.         mov     edx, [ebx + 16]
  753.         cmp     byte [esi], 0
  754.         jz      .is_root
  755.  
  756.         push    edx
  757.         stdcall ext2_inode_find, [esp + 4 + 4]
  758.         mov     ebx, edx
  759.         pop     edx
  760.        
  761.         mov     esi, [ebp + EXTFS.ext2_save_inode]
  762.         test    eax, eax
  763.         jz      @F
  764.  
  765.         push    eax
  766.         call    ext2_unlock
  767.         pop     eax
  768.         ;DEBUGF  1, "Returning with: %x.\n", eax
  769.         ret
  770.  
  771.     .is_root:      
  772.         xor     ebx, ebx                                ; Clear out first char, since we don't want to set hidden flag on root.
  773.         mov     esi, [ebp + EXTFS.root_inode]
  774.  
  775.     @@:
  776.         xor     eax, eax
  777.         mov     edi, edx
  778.         mov     ecx, 40/4
  779.         rep stosd                                       ; Zero fill buffer.
  780.  
  781.         cmp     bl, '.'
  782.         jne     @F
  783.         or      dword [edx], FS_FT_HIDDEN
  784.  
  785.     @@:
  786.         test    [esi + EXT2_INODE_STRUC.i_mode], EXT2_S_IFDIR
  787.         jnz     @F                                      ; If a directory, don't put in file size.
  788.  
  789.         mov     eax, [esi + EXT2_INODE_STRUC.i_size]    ; Low file size.
  790.         mov     ebx, [esi + EXT2_INODE_STRUC.i_dir_acl] ; High file size.
  791.         mov     dword [edx+32], eax
  792.         mov     dword [edx+36], ebx
  793.  
  794.         xor     dword [edx], FS_FT_DIR                  ; Next XOR will clean this, to mark it as a file.
  795.     @@:
  796.         xor     dword [edx], FS_FT_DIR                  ; Mark as directory.
  797.  
  798.         lea     edi, [edx + 8]
  799.  
  800.         ; Store all time.
  801.         mov     eax, [esi + EXT2_INODE_STRUC.i_ctime]
  802.         xor     edx, edx
  803.         add     eax, 3054539008
  804.         adc     edx, 2
  805.         call    ntfs_datetime_to_bdfe.sec
  806.  
  807.         mov     eax, [esi + EXT2_INODE_STRUC.i_atime]
  808.         xor     edx, edx
  809.         add     eax, 3054539008
  810.         adc     edx, 2
  811.         call    ntfs_datetime_to_bdfe.sec
  812.  
  813.         mov     eax, [esi + EXT2_INODE_STRUC.i_mtime]
  814.         xor     edx, edx
  815.         add     eax, 3054539008
  816.         adc     edx, 2
  817.         call    ntfs_datetime_to_bdfe.sec
  818.  
  819.         call    ext2_unlock
  820.         xor     eax, eax
  821.         ;DEBUGF  1, "Returning with: %x.\n", eax
  822.         ret
  823.  
  824. ;---------------------------------------------------------------------
  825. ; Set file information for block device.
  826. ; Input:        esi + [esp + 4] = file name.
  827. ;               ebx = pointer to paramteres from sysfunc 70.
  828. ;               ebp = pointer to EXTFS structure.
  829. ; Output:       eax = error code.
  830. ;---------------------------------------------------------------------
  831. ext2_SetFileInfo:
  832.         test    [ebp + EXTFS.partition_flags], EXT2_RO
  833.         jz      @F
  834.  
  835.         mov     eax, ERROR_UNSUPPORTED_FS
  836.         ret
  837.  
  838.     @@:    
  839.         push    edx esi edi ebx
  840.         call    ext2_lock
  841.         mov     edx, [ebx + 16]
  842.  
  843.         ; Is this read-only?
  844.         test    [ebp + EXTFS.partition_flags], EXT2_RO
  845.         jnz     .fail
  846.  
  847.         ; Not supported for root.
  848.         cmp     byte [esi], 0
  849.         je      .fail
  850.  
  851.     .get_inode:
  852.         push    edx
  853.         stdcall ext2_inode_find, [esp + 4 + 20]
  854.         pop     edx
  855.  
  856.         test    eax, eax
  857.         jnz     @F
  858.  
  859.         ; Save inode number.
  860.         push    esi
  861.         mov     esi, [ebp + EXTFS.ext2_save_inode]
  862.  
  863.         ; From the BDFE, we ignore read-only file flags, hidden file flags;
  864.         ; We ignore system file flags, file was archived or not.
  865.  
  866.         ; Also ignored is file creation time. ext2 stores "inode modification"
  867.         ; time in the ctime field, which is updated by the respective inode_write
  868.         ; procedure, and any writes on it would be overwritten anyway.
  869.  
  870.         ; Access time.
  871.         lea     edi, [esi + EXT2_INODE_STRUC.i_atime]
  872.         lea     esi, [edx + 16]
  873.         call    bdfe_to_unix_time
  874.  
  875.         ; Modification time.
  876.         add     esi, 8
  877.         add     edi, 8
  878.         call    bdfe_to_unix_time
  879.  
  880.         mov     ebx, [ebp + EXTFS.ext2_save_inode] ; Get address of inode into ebx.
  881.         pop     eax                             ; Get inode number in eax.
  882.         call    ext2_inode_write                ; eax contains error code, if any.
  883.         test    eax, eax
  884.         jnz     @F
  885.  
  886.         call    ext2_sb_update
  887.         ; Sync the disk.
  888.         mov     esi, [ebp + PARTITION.Disk]
  889.         call    disk_sync                       ; eax contains error code, if any.
  890.  
  891.     @@:
  892.         push    eax
  893.         call    ext2_unlock
  894.         pop     eax
  895.  
  896.         pop     ebx edi esi edx
  897.         ret
  898.  
  899.     .fail:
  900.         call    ext2_sb_update
  901.         ; Sync the disk.
  902.         mov     esi, [ebp + PARTITION.Disk]
  903.         call    disk_sync                       ; eax contains error code, if any.
  904.  
  905.         mov     eax, ERROR_UNSUPPORTED_FS
  906.         jmp     @B
  907.  
  908. ;---------------------------------------------------------------------
  909. ; Set file information for block device.
  910. ; Input:        esi + [esp + 4] = file name.
  911. ;               ebx = pointer to paramteres from sysfunc 70.
  912. ;               ebp = pointer to EXTFS structure.
  913. ; Output:       eax = error code.
  914. ;---------------------------------------------------------------------
  915. ext2_Delete:
  916.         ;DEBUGF  1, "Attempting Delete.\n"
  917.         test    [ebp + EXTFS.partition_flags], EXT2_RO
  918.         jz      @F
  919.  
  920.         mov     eax, ERROR_UNSUPPORTED_FS
  921.         ret
  922.  
  923.     @@:    
  924.         push    ebx ecx edx esi edi
  925.         call    ext2_lock
  926.  
  927.         add     esi, [esp + 20 + 4]
  928.  
  929.         ; Can't delete root.
  930.         cmp     byte [esi], 0
  931.         jz      .error_access_denied
  932.  
  933.         push    esi
  934.         stdcall ext2_inode_find, 0
  935.         mov     ebx, esi
  936.         pop     esi
  937.  
  938.         test    eax, eax
  939.         jnz     .error_access_denied
  940.  
  941.         mov     edx, [ebp + EXTFS.ext2_save_inode]
  942.         movzx   edx, [edx + EXT2_INODE_STRUC.i_mode]
  943.         and     edx, EXT2_S_IFMT                                ; Get the mask.
  944.         cmp     edx, EXT2_S_IFDIR
  945.         jne     @F                                              ; If not a directory, we don't need to check if it's empty.
  946.  
  947.         call    ext2_dir_empty                                  ; 0 means directory is empty.
  948.  
  949.         test    eax, eax
  950.         jnz     .error_access_denied
  951.  
  952.     @@:
  953.         ; Find parent.
  954.         call    ext2_inode_find_parent
  955.         test    eax, eax
  956.         jnz     .error_access_denied
  957.         mov     eax, esi
  958.  
  959.         ; Save file/dir & parent inode.
  960.         push    ebx eax
  961.  
  962.         cmp     edx, EXT2_S_IFDIR
  963.         jne     @F      
  964.  
  965.         ; Unlink '.'
  966.         mov     eax, [esp + 4]
  967.         call    ext2_inode_unlink
  968.         cmp     eax, 0xFFFFFFFF
  969.         je      .error_stack8
  970.  
  971.         ; Unlink '..'
  972.         mov     eax, [esp + 4]
  973.         mov     ebx, [esp]
  974.         call    ext2_inode_unlink
  975.         cmp     eax, 0xFFFFFFFF
  976.         je      .error_stack8
  977.  
  978.     @@:
  979.         pop     eax
  980.         mov     ebx, [esp]
  981.         ; Unlink the inode.
  982.         call    ext2_inode_unlink
  983.         cmp     eax, 0xFFFFFFFF
  984.         je      .error_stack4
  985.        
  986.         ; If hardlinks aren't zero, shouldn't completely free.
  987.         test    eax, eax
  988.         jz      @F
  989.  
  990.         add     esp, 4
  991.         jmp     .disk_sync
  992.  
  993.     @@:
  994.         ; Read the inode.
  995.         mov     eax, [esp]
  996.         mov     ebx, [ebp + EXTFS.ext2_save_inode]
  997.         call    ext2_inode_read
  998.         test    eax, eax
  999.         jnz     .error_stack4
  1000.        
  1001.         ; Free inode data.
  1002.         mov     esi, [ebp + EXTFS.ext2_save_inode]
  1003.         xor     ecx, ecx
  1004.  
  1005.     @@:
  1006.         push    ecx
  1007.         call    ext2_inode_get_block
  1008.         test    eax, eax
  1009.         jnz     .error_stack8
  1010.         mov     eax, ecx
  1011.         pop     ecx
  1012.  
  1013.         ; If 0, we're done.
  1014.         test    eax, eax
  1015.         jz      @F
  1016.  
  1017.         call    ext2_block_free
  1018.         test    eax, eax
  1019.         jnz     .error_stack4
  1020.  
  1021.         inc     ecx
  1022.         jmp     @B
  1023.  
  1024.     @@:
  1025.         ; Free indirect blocks.
  1026.         call    ext2_inode_free_indirect_blocks
  1027.         test    eax, eax
  1028.         jnz     .error_stack4
  1029.  
  1030.         ; Clear the inode, and add deletion time.
  1031.         mov     edi, [ebp + EXTFS.ext2_save_inode]
  1032.         xor     eax, eax
  1033.         mov     ecx, [ebp + EXTFS.inode_size]
  1034.         rep stosb
  1035.  
  1036.         mov     edi, [ebp + EXTFS.ext2_save_inode]
  1037.         add     edi, EXT2_INODE_STRUC.i_dtime
  1038.         call    current_unix_time
  1039.  
  1040.         ; Write the inode.
  1041.         mov     eax, [esp]
  1042.         mov     ebx, [ebp + EXTFS.ext2_save_inode]
  1043.         call    ext2_inode_write
  1044.         test    eax, eax
  1045.         jnz     .error_stack4
  1046.  
  1047.         ; Check if directory.
  1048.         cmp     edx, EXT2_S_IFDIR
  1049.         jne     @F
  1050.  
  1051.         ; If it is, decrement used_dirs_count.
  1052.  
  1053.         ; Get block group.
  1054.         mov     eax, [esp]
  1055.         dec     eax
  1056.         xor     edx, edx
  1057.         div     [ebp + EXTFS.superblock + EXT2_SB_STRUC.inodes_per_group]
  1058.  
  1059.         push    eax
  1060.         call    ext2_bg_read_desc
  1061.         test    eax, eax
  1062.         jz      .error_stack8
  1063.  
  1064.         dec     [eax + EXT2_BLOCK_GROUP_DESC.used_dirs_count]
  1065.        
  1066.         pop     eax
  1067.         call    ext2_bg_write_desc
  1068.  
  1069.     @@:
  1070.         pop     eax
  1071.         call    ext2_inode_free
  1072.         test    eax, eax
  1073.         jnz     .error_access_denied
  1074.  
  1075.     .disk_sync:
  1076.         call    ext2_sb_update
  1077.  
  1078.         ; Sync the disk.
  1079.         mov     esi, [ebp + PARTITION.Disk]
  1080.         call    disk_sync                       ; eax contains error code, if any.
  1081.  
  1082.     .return:    
  1083.         push    eax
  1084.         call    ext2_unlock
  1085.         pop     eax
  1086.  
  1087.         pop     edi esi edx ecx ebx
  1088.         ;DEBUGF  1, "And returning with: %x.\n", eax
  1089.         ret
  1090.  
  1091.     .error_stack8:
  1092.         add     esp, 4
  1093.     .error_stack4:
  1094.         add     esp, 4
  1095.     .error_access_denied:
  1096.         call    ext2_sb_update
  1097.  
  1098.         ; Sync the disk.
  1099.         mov     esi, [ebp + PARTITION.Disk]
  1100.         call    disk_sync                       ; eax contains error code, if any.
  1101.  
  1102.         mov     eax, ERROR_ACCESS_DENIED
  1103.         jmp     .return
  1104.  
  1105. ;---------------------------------------------------------------------
  1106. ; Set file information for block device.
  1107. ; Input:        esi + [esp + 4] = file name.
  1108. ;               ebx = pointer to paramteres from sysfunc 70.
  1109. ;               ebp = pointer to EXTFS structure.
  1110. ; Output:       eax = error code.
  1111. ;---------------------------------------------------------------------
  1112. ext2_CreateFolder:
  1113.         ;DEBUGF  1, "Attempting to create folder.\n"
  1114.         test    [ebp + EXTFS.partition_flags], EXT2_RO
  1115.         jz      @F
  1116.  
  1117.         mov     eax, ERROR_UNSUPPORTED_FS
  1118.         ret
  1119.  
  1120.     @@:    
  1121.         push    ebx ecx edx esi edi
  1122.         call    ext2_lock
  1123.  
  1124.         add     esi, [esp + 20 + 4]
  1125.  
  1126.         ; Can't create root, but for CreateFolder already existing directory is success.
  1127.         cmp     byte [esi], 0
  1128.         jz      .success
  1129.  
  1130.         push    esi
  1131.         stdcall ext2_inode_find, 0
  1132.         pop     esi
  1133.  
  1134.         ; If the directory is there, we've succeeded.
  1135.         test    eax, eax
  1136.         jz      .success
  1137.  
  1138.         ; Find parent.
  1139.         call    ext2_inode_find_parent
  1140.         test    eax, eax
  1141.         jnz     .error
  1142.  
  1143.         ; Inode ID for preference.
  1144.         mov     eax, esi
  1145.         call    ext2_inode_alloc
  1146.         test    eax, eax
  1147.         jnz     .error_full
  1148.  
  1149.         ; Save allocated inode in EDX; filename is in EDI; parent ID in ESI.
  1150.         mov     edx, ebx
  1151.  
  1152.         push    edi
  1153.  
  1154.         xor     al, al
  1155.         mov     edi, [ebp + EXTFS.ext2_temp_inode]
  1156.         mov     ecx, [ebp + EXTFS.inode_size]
  1157.         rep stosb
  1158.  
  1159.         mov     edi, [ebp + EXTFS.ext2_temp_inode]
  1160.         add     edi, EXT2_INODE_STRUC.i_atime
  1161.         call    current_unix_time
  1162.  
  1163.         add     edi, 8
  1164.         call    current_unix_time
  1165.  
  1166.         pop     edi
  1167.  
  1168.         mov     ebx, [ebp + EXTFS.ext2_temp_inode]
  1169.         mov     [ebx + EXT2_INODE_STRUC.i_mode], EXT2_S_IFDIR or PERMISSIONS
  1170.         mov     eax, edx
  1171.         call    ext2_inode_write
  1172.         test    eax, eax
  1173.         jnz     .error
  1174.  
  1175.         ; Link to self.
  1176.         push    edx esi
  1177.  
  1178.         mov     eax, edx
  1179.         mov     ebx, eax
  1180.         mov     dl, EXT2_FT_DIR
  1181.         mov     esi, self_link
  1182.         call    ext2_inode_link
  1183.  
  1184.         pop     esi edx
  1185.  
  1186.         test    eax, eax
  1187.         jnz     .error
  1188.  
  1189.         ; Link to parent.
  1190.         push    edx esi
  1191.  
  1192.         mov     eax, ebx
  1193.         mov     ebx, esi
  1194.         mov     dl, EXT2_FT_DIR
  1195.         mov     esi, parent_link
  1196.         call    ext2_inode_link
  1197.  
  1198.         pop     esi edx
  1199.  
  1200.         test    eax, eax
  1201.         jnz     .error
  1202.  
  1203.         ; Link parent to child.
  1204.         mov     eax, esi
  1205.         mov     ebx, edx
  1206.         mov     esi, edi
  1207.         mov     dl, EXT2_FT_DIR
  1208.         call    ext2_inode_link
  1209.         test    eax, eax
  1210.         jnz     .error
  1211.  
  1212.         ; Get block group descriptor for allocated inode's block.
  1213.         mov     eax, ebx
  1214.         dec     eax
  1215.         xor     edx, edx
  1216.        
  1217.         ; EAX = block group.
  1218.         div     [ebp + EXTFS.superblock + EXT2_SB_STRUC.inodes_per_group]
  1219.         mov     edx, eax
  1220.  
  1221.         call    ext2_bg_read_desc
  1222.         test    eax, eax
  1223.         jz      .error
  1224.  
  1225.         inc     [eax + EXT2_BLOCK_GROUP_DESC.used_dirs_count]
  1226.         mov     eax, edx
  1227.         call    ext2_bg_write_desc
  1228.         test    eax, eax
  1229.         jnz     .error
  1230.  
  1231.     .success:
  1232.         call    ext2_sb_update
  1233.  
  1234.         ; Sync the disk.
  1235.         mov     esi, [ebp + PARTITION.Disk]
  1236.         call    disk_sync                       ; eax contains error code, if any.
  1237.  
  1238.     .return:
  1239.         push    eax
  1240.         call    ext2_unlock
  1241.         pop     eax
  1242.  
  1243.         pop     edi esi edx ecx ebx
  1244.         ;DEBUGF  1, "Returning with: %x.\n", eax
  1245.         ret
  1246.  
  1247.     .error:
  1248.         call    ext2_sb_update
  1249.  
  1250.         ; Sync the disk.
  1251.         mov     esi, [ebp + PARTITION.Disk]
  1252.         call    disk_sync                       ; eax contains error code, if any.
  1253.        
  1254.         mov     eax, ERROR_ACCESS_DENIED
  1255.         jmp     .return
  1256.  
  1257.     .error_full:
  1258.         mov     eax, ERROR_DISK_FULL
  1259.         jmp     .return
  1260.  
  1261. self_link   db ".", 0
  1262. parent_link db "..", 0
  1263.  
  1264. ;---------------------------------------------------------------------
  1265. ; Rewrite a file.
  1266. ; Input:        esi + [esp + 4] = file name.
  1267. ;               ebx = pointer to paramteres from sysfunc 70.
  1268. ;               ebp = pointer to EXTFS structure.
  1269. ; Output:       eax = error code.
  1270. ;               ebx = bytes written.
  1271. ;---------------------------------------------------------------------
  1272. ext2_Rewrite:
  1273.         ;DEBUGF  1, "Attempting Rewrite.\n"
  1274.         test    [ebp + EXTFS.partition_flags], EXT2_RO
  1275.         jz      @F
  1276.  
  1277.         mov     eax, ERROR_UNSUPPORTED_FS
  1278.         ret
  1279.  
  1280.     @@:
  1281.         push    ecx edx esi edi
  1282.         pushad
  1283.  
  1284.         call    ext2_lock
  1285.  
  1286.         add     esi, [esp + 16 + 32 + 4]
  1287.         ; Can't create root.
  1288.         cmp     byte [esi], 0
  1289.         jz      .error_access_denied
  1290.  
  1291.         push    esi
  1292.         stdcall ext2_inode_find, 0
  1293.         pop     esi
  1294.  
  1295.         ; If the file is there, delete it.
  1296.         test    eax, eax
  1297.         jnz     @F
  1298.  
  1299.         pushad
  1300.  
  1301.         push    eax
  1302.         call    ext2_unlock
  1303.         pop     eax
  1304.  
  1305.         push    dword 0x00000000
  1306.         call    ext2_Delete
  1307.         add     esp, 4
  1308.  
  1309.         push    eax
  1310.         call    ext2_lock
  1311.         pop     eax
  1312.  
  1313.         test    eax, eax
  1314.         jnz     .error_access_denied_delete
  1315.  
  1316.         popad
  1317.     @@:
  1318.         ; Find parent.
  1319.         call    ext2_inode_find_parent
  1320.         test    eax, eax
  1321.         jnz     .error_access_denied
  1322.  
  1323.         ; Inode ID for preference.
  1324.         mov     eax, esi
  1325.         call    ext2_inode_alloc
  1326.         test    eax, eax
  1327.         jnz     .error_full
  1328.  
  1329.         ; Save allocated inode in EDX; filename is in EDI; parent ID in ESI.
  1330.         mov     edx, ebx
  1331.  
  1332.         push    edi
  1333.  
  1334.         xor     al, al
  1335.         mov     edi, [ebp + EXTFS.ext2_temp_inode]
  1336.         mov     ecx, [ebp + EXTFS.inode_size]
  1337.         rep stosb
  1338.  
  1339.         mov     edi, [ebp + EXTFS.ext2_temp_inode]
  1340.         add     edi, EXT2_INODE_STRUC.i_atime
  1341.         call    current_unix_time
  1342.  
  1343.         add     edi, 8
  1344.         call    current_unix_time
  1345.  
  1346.         pop     edi
  1347.  
  1348.         mov     ebx, [ebp + EXTFS.ext2_temp_inode]
  1349.         mov     [ebx + EXT2_INODE_STRUC.i_mode], EXT2_S_IFREG or PERMISSIONS
  1350.         mov     eax, edx
  1351.         call    ext2_inode_write
  1352.         test    eax, eax
  1353.         jnz     .error
  1354.  
  1355.         ; Link parent to child.
  1356.         mov     eax, esi
  1357.         mov     ebx, edx
  1358.         mov     esi, edi
  1359.         mov     dl, EXT2_FT_REG_FILE
  1360.         call    ext2_inode_link
  1361.         test    eax, eax
  1362.         jnz     .error
  1363.  
  1364.         popad
  1365.         push    eax
  1366.         call    ext2_unlock
  1367.         pop     eax
  1368.  
  1369.         push    dword 0x00000000
  1370.         call    ext2_Write
  1371.         add     esp, 4
  1372.  
  1373.         push    eax
  1374.         call    ext2_lock
  1375.         pop     eax
  1376.  
  1377.     .success:
  1378.         push    eax
  1379.         call    ext2_sb_update
  1380.  
  1381.         ; Sync the disk.
  1382.         mov     esi, [ebp + PARTITION.Disk]
  1383.         call    disk_sync                       ; eax contains error code, if any.
  1384.         pop     eax
  1385.  
  1386.     .return:
  1387.         push    eax
  1388.         call    ext2_unlock
  1389.         pop     eax
  1390.  
  1391.         pop     edi esi edx ecx
  1392.  
  1393.         ;DEBUGF  1, "And returning with: %x.\n", eax
  1394.         ret
  1395.  
  1396.     .error:      
  1397.         mov     eax, ERROR_ACCESS_DENIED
  1398.         jmp     .success
  1399.  
  1400.     .error_access_denied_delete:
  1401.         popad
  1402.  
  1403.     .error_access_denied:
  1404.         popad
  1405.         xor     ebx, ebx
  1406.  
  1407.         mov     eax, ERROR_ACCESS_DENIED
  1408.         jmp     .return
  1409.  
  1410.     .error_full:
  1411.         popad
  1412.         xor     ebx, ebx
  1413.  
  1414.         mov     eax, ERROR_DISK_FULL
  1415.         jmp     .return
  1416.  
  1417. ;---------------------------------------------------------------------
  1418. ; Write to a file.
  1419. ; Input:        esi + [esp + 4] = file name.
  1420. ;               ebx = pointer to paramteres from sysfunc 70.
  1421. ;               ebp = pointer to EXTFS structure.
  1422. ; Output:       eax = error code.
  1423. ;               ebx = number of bytes written.
  1424. ;---------------------------------------------------------------------
  1425. ext2_Write:
  1426.         ;DEBUGF 1, "Attempting write, "
  1427.         test    [ebp + EXTFS.partition_flags], EXT2_RO
  1428.         jz      @F
  1429.  
  1430.         mov     eax, ERROR_UNSUPPORTED_FS
  1431.         ret
  1432.  
  1433.     @@:    
  1434.         push    ecx edx esi edi
  1435.         call    ext2_lock
  1436.  
  1437.         add     esi, [esp + 16 + 4]
  1438.  
  1439.         ; Can't write to root.
  1440.         cmp     byte [esi], 0
  1441.         jz      .error
  1442.  
  1443.         push    ebx ecx edx
  1444.         stdcall ext2_inode_find, 0
  1445.         pop     edx ecx ebx
  1446.         ; If file not there, error.
  1447.         xor     ecx, ecx
  1448.         test    eax, eax
  1449.         jnz     .error_file_not_found
  1450.  
  1451.         ; Save the inode.
  1452.         push    esi
  1453.  
  1454.         ; Check if it's a file.
  1455.         mov     edx, [ebp + EXTFS.ext2_save_inode]
  1456.         test    [edx + EXT2_INODE_STRUC.i_mode], EXT2_S_IFREG
  1457.         jz      .error
  1458.  
  1459.         mov     eax, esi
  1460.         mov     ecx, [ebx + 4]
  1461.  
  1462.         call    ext2_inode_extend
  1463.         xor     ecx, ecx
  1464.         test    eax, eax
  1465.         jnz     .error_device
  1466.  
  1467.         ; ECX contains the size to write, and ESI points to it.
  1468.         mov     ecx, [ebx + 0x0C]
  1469.         mov     esi, [ebx + 0x10]
  1470.  
  1471.         ; Save the size of the inode.
  1472.         mov     eax, [edx + EXT2_INODE_STRUC.i_size]
  1473.         push    eax
  1474.  
  1475.         xor     edx, edx
  1476.         div     [ebp + EXTFS.block_size]
  1477.  
  1478.         test    edx, edx
  1479.         jz      .start_aligned
  1480.  
  1481.         ; Start isn't aligned, so deal with the non-aligned bytes.
  1482.         mov     ebx, [ebp + EXTFS.block_size]
  1483.         sub     ebx, edx
  1484.  
  1485.         cmp     ebx, ecx
  1486.         jbe     @F
  1487.  
  1488.         ; If the size to copy fits in current block, limit to that, instead of the entire block.
  1489.         mov     ebx, ecx
  1490.  
  1491.     @@:
  1492.         ; Copy EBX bytes, in EAX indexed block.
  1493.         push    eax
  1494.         call    ext2_inode_read_entry
  1495.         test    eax, eax
  1496.         pop     eax
  1497.         jnz     .error_inode_size
  1498.  
  1499.         push    ecx
  1500.        
  1501.         mov     ecx, ebx
  1502.         mov     edi, ebx
  1503.         add     edi, edx
  1504.         rep movsb
  1505.  
  1506.         pop     ecx
  1507.  
  1508.         ; Write the block.
  1509.         call    ext2_inode_write_entry
  1510.         test    eax, eax
  1511.         jnz     .error_inode_size
  1512.  
  1513.         add     [esp], ebx
  1514.         sub     ecx, ebx
  1515.         jz      .write_inode
  1516.  
  1517.     .start_aligned:
  1518.         cmp     ecx, [ebp + EXTFS.block_size]
  1519.         jb      @F
  1520.  
  1521.         mov     eax, [esp]
  1522.         xor     edx, edx
  1523.         div     [ebp + EXTFS.block_size]
  1524.  
  1525.         push    eax
  1526.         mov     edx, [esp + 8]
  1527.         call    ext2_inode_blank_entry
  1528.         test    eax, eax
  1529.         pop     eax
  1530.         jnz     .error_inode_size
  1531.  
  1532.         push    ecx
  1533.  
  1534.         mov     ecx, [ebp + EXTFS.block_size]
  1535.         mov     edi, [ebp + EXTFS.ext2_save_block]
  1536.         rep movsb
  1537.  
  1538.         pop     ecx
  1539.  
  1540.         call    ext2_inode_write_entry
  1541.         test    eax, eax
  1542.         jnz     .error_inode_size
  1543.  
  1544.         mov     eax, [ebp + EXTFS.block_size]
  1545.         sub     ecx, eax
  1546.         add     [esp], eax
  1547.         jmp     .start_aligned        
  1548.  
  1549.     ; Handle the remaining bytes.
  1550.     @@:
  1551.         test    ecx, ecx
  1552.         jz      .write_inode
  1553.  
  1554.         mov     eax, [esp]
  1555.         xor     edx, edx
  1556.         div     [ebp + EXTFS.block_size]
  1557.  
  1558.         push    eax
  1559.         call    ext2_inode_read_entry
  1560.         test    eax, eax
  1561.         pop     eax
  1562.         jz      @F
  1563.  
  1564.         push    eax
  1565.         mov     edx, [esp + 8]
  1566.  
  1567.         call    ext2_inode_blank_entry
  1568.         test    eax, eax
  1569.         pop     eax
  1570.         jnz     .error_inode_size
  1571.  
  1572.     @@:
  1573.         push    ecx
  1574.         mov     edi, [ebp + EXTFS.ext2_save_block]
  1575.         rep movsb
  1576.         pop     ecx
  1577.  
  1578.         call    ext2_inode_write_entry
  1579.         test    eax, eax
  1580.         jnz     .error_inode_size
  1581.  
  1582.         add     [esp], ecx
  1583.         xor     ecx, ecx
  1584.  
  1585.     .write_inode:
  1586.         mov     ebx, [ebp + EXTFS.ext2_temp_inode]
  1587.         pop     eax
  1588.         mov     [ebx + EXT2_INODE_STRUC.i_size], eax
  1589.         mov     eax, [esp]
  1590.  
  1591.         call    ext2_inode_write
  1592.         test    eax, eax
  1593.         jnz     .error_device
  1594.  
  1595.     .success:
  1596.         call    ext2_sb_update
  1597.  
  1598.         ; Sync the disk.
  1599.         mov     esi, [ebp + PARTITION.Disk]
  1600.         call    disk_sync                       ; eax contains error code, if any.
  1601.  
  1602.     .return:
  1603.         push    eax
  1604.         call    ext2_unlock
  1605.         pop     eax
  1606.  
  1607.         add     esp, 4
  1608.  
  1609.         mov     ebx, [esp + 12]
  1610.         sub     ebx, ecx
  1611.         pop     edi esi edx ecx
  1612.  
  1613.         ;DEBUGF  1, "and returning with: %x.\n", eax
  1614.         ret
  1615.  
  1616.     .error:
  1617.         mov     eax, ERROR_ACCESS_DENIED
  1618.         jmp     .return
  1619.  
  1620.     .error_file_not_found:
  1621.         mov     eax, ERROR_FILE_NOT_FOUND
  1622.         jmp     .return
  1623.  
  1624.     .error_inode_size:
  1625.         mov     ebx, [ebp + EXTFS.ext2_temp_inode]
  1626.         pop     eax
  1627.         mov     [ebx + EXT2_INODE_STRUC.i_size], eax
  1628.         mov     eax, [esp]
  1629.  
  1630.         call    ext2_inode_write
  1631.  
  1632.     .error_device:        
  1633.         call    ext2_sb_update
  1634.  
  1635.         ; Sync the disk.
  1636.         mov     esi, [ebp + PARTITION.Disk]
  1637.         call    disk_sync                       ; eax contains error code, if any.
  1638.  
  1639.         mov     eax, ERROR_DEVICE
  1640.         jmp     .return
  1641.  
  1642. ;---------------------------------------------------------------------
  1643. ; Set the end of a file.
  1644. ; Input:        esi + [esp + 4] = file name.
  1645. ;               ebx = pointer to paramteres from sysfunc 70.
  1646. ;               ebp = pointer to EXTFS structure.
  1647. ; Output:       eax = error code.
  1648. ;---------------------------------------------------------------------
  1649. ext2_SetFileEnd:
  1650.         test    [ebp + EXTFS.partition_flags], EXT2_RO
  1651.         jz      @F
  1652.  
  1653.         mov     eax, ERROR_UNSUPPORTED_FS
  1654.         ret
  1655.  
  1656.     @@:    
  1657.         push    ebx ecx edx esi edi
  1658.         call    ext2_lock
  1659.  
  1660.         add     esi, [esp + 20 + 4]
  1661.  
  1662.         ; Can't write to root.
  1663.         cmp     byte [esi], 0
  1664.         jz      .error
  1665.  
  1666.         stdcall ext2_inode_find, 0
  1667.         ; If file not there, error.
  1668.         test    eax, eax
  1669.         jnz     .error_file_not_found
  1670.  
  1671.         ; Check if it's a file.
  1672.         mov     edx, [ebp + EXTFS.ext2_save_inode]
  1673.         cmp     [edx + EXT2_INODE_STRUC.i_mode], EXT2_S_IFREG
  1674.         jne     .error
  1675.  
  1676.         mov     eax, esi
  1677.         mov     ecx, [ebx + 4]
  1678.         call    ext2_inode_extend
  1679.         test    eax, eax
  1680.         jnz     .error_disk_full
  1681.  
  1682.         mov     eax, esi
  1683.         call    ext2_inode_truncate
  1684.         test    eax, eax
  1685.         jnz     .error_disk_full
  1686.  
  1687.         mov     eax, esi
  1688.         mov     ebx, [ebp + EXTFS.ext2_temp_inode]
  1689.         call    ext2_inode_write
  1690.  
  1691.         call    ext2_sb_update
  1692.  
  1693.         ; Sync the disk.
  1694.         mov     esi, [ebp + PARTITION.Disk]
  1695.         call    disk_sync                       ; eax contains error code, if any.
  1696.  
  1697.     .return:
  1698.         push    eax
  1699.         call    ext2_unlock
  1700.         pop     eax
  1701.  
  1702.         pop     edi esi edx ecx ebx
  1703.         ret
  1704.  
  1705.     .error:
  1706.         mov     eax, ERROR_ACCESS_DENIED
  1707.         jmp     .return
  1708.  
  1709.     .error_file_not_found:
  1710.         mov     eax, ERROR_FILE_NOT_FOUND
  1711.         jmp     .return
  1712.  
  1713.     .error_disk_full:        
  1714.         call    ext2_sb_update
  1715.  
  1716.         ; Sync the disk.
  1717.         mov     esi, [ebp + PARTITION.Disk]
  1718.         call    disk_sync                       ; eax contains error code, if any.
  1719.  
  1720.         mov     eax, ERROR_DISK_FULL
  1721.         jmp     .return
  1722.