Subversion Repositories Kolibri OS

Rev

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