Subversion Repositories Kolibri OS

Rev

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