Subversion Repositories Kolibri OS

Rev

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

  1. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2. ;;                                                              ;;
  3. ;; Contains ext2 initialization, plus syscall handling code.    ;;
  4. ;;                                                              ;;
  5. ;; Copyright (C) KolibriOS team 2004-2013. All rights reserved. ;;
  6. ;; Distributed under the terms of the new BSD license.          ;;
  7. ;;                                                              ;;
  8. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  9.  
  10. include 'ext2.inc'
  11. include 'blocks.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, for: %s.\n", esi
  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.         ;DEBUGF  1, "Returning with: %x.\n", eax
  766.         ret
  767.  
  768.     .is_root:      
  769.         xor     ebx, ebx                                ; Clear out first char, since we don't want to set hidden flag on root.
  770.         mov     esi, [ebp + EXTFS.root_inode]
  771.  
  772.     @@:
  773.         xor     eax, eax
  774.         mov     edi, edx
  775.         mov     ecx, 40/4
  776.         rep stosd                                       ; Zero fill buffer.
  777.  
  778.         cmp     bl, '.'
  779.         jne     @F
  780.         or      dword [edx], FS_FT_HIDDEN
  781.  
  782.     @@:
  783.         test    [esi + EXT2_INODE_STRUC.i_mode], EXT2_S_IFDIR
  784.         jnz     @F                                      ; If a directory, don't put in file size.
  785.  
  786.         mov     eax, [esi + EXT2_INODE_STRUC.i_size]    ; Low file size.
  787.         mov     ebx, [esi + EXT2_INODE_STRUC.i_dir_acl] ; High file size.
  788.         mov     dword [edx+32], eax
  789.         mov     dword [edx+36], ebx
  790.  
  791.         xor     dword [edx], FS_FT_DIR                  ; Next XOR will clean this, to mark it as a file.
  792.     @@:
  793.         xor     dword [edx], FS_FT_DIR                  ; Mark as directory.
  794.  
  795.         lea     edi, [edx + 8]
  796.  
  797.         ; Store all time.
  798.         mov     eax, [esi + EXT2_INODE_STRUC.i_ctime]
  799.         xor     edx, edx
  800.         add     eax, 3054539008
  801.         adc     edx, 2
  802.         call    ntfs_datetime_to_bdfe.sec
  803.  
  804.         mov     eax, [esi + EXT2_INODE_STRUC.i_atime]
  805.         xor     edx, edx
  806.         add     eax, 3054539008
  807.         adc     edx, 2
  808.         call    ntfs_datetime_to_bdfe.sec
  809.  
  810.         mov     eax, [esi + EXT2_INODE_STRUC.i_mtime]
  811.         xor     edx, edx
  812.         add     eax, 3054539008
  813.         adc     edx, 2
  814.         call    ntfs_datetime_to_bdfe.sec
  815.  
  816.         call    ext2_unlock
  817.         xor     eax, eax
  818.         ;DEBUGF  1, "Returning with: %x.\n", eax
  819.         ret
  820.  
  821. ;---------------------------------------------------------------------
  822. ; Set file information for block device.
  823. ; Input:        esi + [esp + 4] = file name.
  824. ;               ebx = pointer to paramteres from sysfunc 70.
  825. ;               ebp = pointer to EXTFS structure.
  826. ; Output:       eax = error code.
  827. ;---------------------------------------------------------------------
  828. ext2_SetFileInfo:
  829.         test    [ebp + EXTFS.partition_flags], EXT2_RO
  830.         jz      @F
  831.  
  832.         mov     eax, ERROR_UNSUPPORTED_FS
  833.         ret
  834.  
  835.     @@:    
  836.         push    edx esi edi ebx
  837.         call    ext2_lock
  838.         mov     edx, [ebx + 16]
  839.  
  840.         ; Is this read-only?
  841.         test    [ebp + EXTFS.partition_flags], EXT2_RO
  842.         jnz     .fail
  843.  
  844.         ; Not supported for root.
  845.         cmp     byte [esi], 0
  846.         je      .fail
  847.  
  848.     .get_inode:
  849.         push    edx
  850.         stdcall ext2_inode_find, [esp + 4 + 20]
  851.         pop     edx
  852.  
  853.         test    eax, eax
  854.         jnz     @F
  855.  
  856.         ; Save inode number.
  857.         push    esi
  858.         mov     esi, [ebp + EXTFS.ext2_save_inode]
  859.  
  860.         ; From the BDFE, we ignore read-only file flags, hidden file flags;
  861.         ; We ignore system file flags, file was archived or not.
  862.  
  863.         ; Also ignored is file creation time. ext2 stores "inode modification"
  864.         ; time in the ctime field, which is updated by the respective inode_write
  865.         ; procedure, and any writes on it would be overwritten anyway.
  866.  
  867.         ; Access time.
  868.         lea     edi, [esi + EXT2_INODE_STRUC.i_atime]
  869.         lea     esi, [edx + 16]
  870.         call    bdfe_to_unix_time
  871.  
  872.         ; Modification time.
  873.         add     esi, 8
  874.         add     edi, 8
  875.         call    bdfe_to_unix_time
  876.  
  877.         mov     ebx, [ebp + EXTFS.ext2_save_inode] ; Get address of inode into ebx.
  878.         pop     eax                             ; Get inode number in eax.
  879.         call    ext2_inode_write                ; eax contains error code, if any.
  880.         test    eax, eax
  881.         jnz     @F
  882.  
  883.         call    ext2_sb_update
  884.         ; Sync the disk.
  885.         mov     esi, [ebp + PARTITION.Disk]
  886.         call    disk_sync                       ; eax contains error code, if any.
  887.  
  888.     @@:
  889.         push    eax
  890.         call    ext2_unlock
  891.         pop     eax
  892.  
  893.         pop     ebx edi esi edx
  894.         ret
  895.  
  896.     .fail:
  897.         call    ext2_sb_update
  898.         ; Sync the disk.
  899.         mov     esi, [ebp + PARTITION.Disk]
  900.         call    disk_sync                       ; eax contains error code, if any.
  901.  
  902.         mov     eax, ERROR_UNSUPPORTED_FS
  903.         jmp     @B
  904.  
  905. ;---------------------------------------------------------------------
  906. ; Set file information for block device.
  907. ; Input:        esi + [esp + 4] = file name.
  908. ;               ebx = pointer to paramteres from sysfunc 70.
  909. ;               ebp = pointer to EXTFS structure.
  910. ; Output:       eax = error code.
  911. ;---------------------------------------------------------------------
  912. ext2_Delete:
  913.         ;DEBUGF  1, "Attempting Delete.\n"
  914.         test    [ebp + EXTFS.partition_flags], EXT2_RO
  915.         jz      @F
  916.  
  917.         mov     eax, ERROR_UNSUPPORTED_FS
  918.         ret
  919.  
  920.     @@:    
  921.         push    ebx ecx edx esi edi
  922.         call    ext2_lock
  923.  
  924.         add     esi, [esp + 20 + 4]
  925.  
  926.         ; Can't delete root.
  927.         cmp     byte [esi], 0
  928.         jz      .error_access_denied
  929.  
  930.         push    esi
  931.         stdcall ext2_inode_find, 0
  932.         mov     ebx, esi
  933.         pop     esi
  934.  
  935.         test    eax, eax
  936.         jnz     .error_access_denied
  937.  
  938.         mov     edx, [ebp + EXTFS.ext2_save_inode]
  939.         movzx   edx, [edx + EXT2_INODE_STRUC.i_mode]
  940.         and     edx, EXT2_S_IFMT                                ; Get the mask.
  941.         cmp     edx, EXT2_S_IFDIR
  942.         jne     @F                                              ; If not a directory, we don't need to check if it's empty.
  943.  
  944.         call    ext2_dir_empty                                  ; 0 means directory is empty.
  945.  
  946.         test    eax, eax
  947.         jnz     .error_access_denied
  948.  
  949.     @@:
  950.         ; Find parent.
  951.         call    ext2_inode_find_parent
  952.         test    eax, eax
  953.         jnz     .error_access_denied
  954.         mov     eax, esi
  955.  
  956.         ; Save file/dir & parent inode.
  957.         push    ebx eax
  958.  
  959.         cmp     edx, EXT2_S_IFDIR
  960.         jne     @F      
  961.  
  962.         ; Unlink '.'
  963.         mov     eax, [esp + 4]
  964.         call    ext2_inode_unlink
  965.         cmp     eax, 0xFFFFFFFF
  966.         je      .error_stack8
  967.  
  968.         ; Unlink '..'
  969.         mov     eax, [esp + 4]
  970.         mov     ebx, [esp]
  971.         call    ext2_inode_unlink
  972.         cmp     eax, 0xFFFFFFFF
  973.         je      .error_stack8
  974.  
  975.     @@:
  976.         pop     eax
  977.         mov     ebx, [esp]
  978.         ; Unlink the inode.
  979.         call    ext2_inode_unlink
  980.         cmp     eax, 0xFFFFFFFF
  981.         je      .error_stack4
  982.        
  983.         ; If hardlinks aren't zero, shouldn't completely free.
  984.         test    eax, eax
  985.         jz      @F
  986.  
  987.         add     esp, 4
  988.         jmp     .disk_sync
  989.  
  990.     @@:
  991.         ; Read the inode.
  992.         mov     eax, [esp]
  993.         mov     ebx, [ebp + EXTFS.ext2_save_inode]
  994.         call    ext2_inode_read
  995.         test    eax, eax
  996.         jnz     .error_stack4
  997.        
  998.         ; Free inode data.
  999.         mov     esi, [ebp + EXTFS.ext2_save_inode]
  1000.         xor     ecx, ecx
  1001.  
  1002.     @@:
  1003.         push    ecx
  1004.         call    ext2_inode_get_block
  1005.         test    eax, eax
  1006.         jnz     .error_stack8
  1007.         mov     eax, ecx
  1008.         pop     ecx
  1009.  
  1010.         ; If 0, we're done.
  1011.         test    eax, eax
  1012.         jz      @F
  1013.  
  1014.         call    ext2_block_free
  1015.         test    eax, eax
  1016.         jnz     .error_stack4
  1017.  
  1018.         inc     ecx
  1019.         jmp     @B
  1020.  
  1021.     @@:
  1022.         ; Free indirect blocks.
  1023.         call    ext2_inode_free_indirect_blocks
  1024.         test    eax, eax
  1025.         jnz     .error_stack4
  1026.  
  1027.         ; Clear the inode, and add deletion time.
  1028.         mov     edi, [ebp + EXTFS.ext2_save_inode]
  1029.         xor     eax, eax
  1030.         mov     ecx, [ebp + EXTFS.inode_size]
  1031.         rep stosb
  1032.  
  1033.         mov     edi, [ebp + EXTFS.ext2_save_inode]
  1034.         add     edi, EXT2_INODE_STRUC.i_dtime
  1035.         call    current_unix_time
  1036.  
  1037.         ; Write the inode.
  1038.         mov     eax, [esp]
  1039.         mov     ebx, [ebp + EXTFS.ext2_save_inode]
  1040.         call    ext2_inode_write
  1041.         test    eax, eax
  1042.         jnz     .error_stack4
  1043.  
  1044.         ; Check if directory.
  1045.         cmp     edx, EXT2_S_IFDIR
  1046.         jne     @F
  1047.  
  1048.         ; If it is, decrement used_dirs_count.
  1049.  
  1050.         ; Get block group.
  1051.         mov     eax, [esp]
  1052.         dec     eax
  1053.         xor     edx, edx
  1054.         div     [ebp + EXTFS.superblock + EXT2_SB_STRUC.inodes_per_group]
  1055.  
  1056.         push    eax
  1057.         call    ext2_bg_read_desc
  1058.         test    eax, eax
  1059.         jz      .error_stack8
  1060.  
  1061.         dec     [eax + EXT2_BLOCK_GROUP_DESC.used_dirs_count]
  1062.        
  1063.         pop     eax
  1064.         call    ext2_bg_write_desc
  1065.  
  1066.     @@:
  1067.         pop     eax
  1068.         call    ext2_inode_free
  1069.         test    eax, eax
  1070.         jnz     .error_access_denied
  1071.  
  1072.     .disk_sync:
  1073.         call    ext2_sb_update
  1074.  
  1075.         ; Sync the disk.
  1076.         mov     esi, [ebp + PARTITION.Disk]
  1077.         call    disk_sync                       ; eax contains error code, if any.
  1078.  
  1079.     .return:    
  1080.         push    eax
  1081.         call    ext2_unlock
  1082.         pop     eax
  1083.  
  1084.         pop     edi esi edx ecx ebx
  1085.         ;DEBUGF  1, "And returning with: %x.\n", eax
  1086.         ret
  1087.  
  1088.     .error_stack8:
  1089.         add     esp, 4
  1090.     .error_stack4:
  1091.         add     esp, 4
  1092.     .error_access_denied:
  1093.         call    ext2_sb_update
  1094.  
  1095.         ; Sync the disk.
  1096.         mov     esi, [ebp + PARTITION.Disk]
  1097.         call    disk_sync                       ; eax contains error code, if any.
  1098.  
  1099.         mov     eax, ERROR_ACCESS_DENIED
  1100.         jmp     .return
  1101.  
  1102. ;---------------------------------------------------------------------
  1103. ; Set file information for block device.
  1104. ; Input:        esi + [esp + 4] = file name.
  1105. ;               ebx = pointer to paramteres from sysfunc 70.
  1106. ;               ebp = pointer to EXTFS structure.
  1107. ; Output:       eax = error code.
  1108. ;---------------------------------------------------------------------
  1109. ext2_CreateFolder:
  1110.         ;DEBUGF  1, "Attempting to create folder.\n"
  1111.         test    [ebp + EXTFS.partition_flags], EXT2_RO
  1112.         jz      @F
  1113.  
  1114.         mov     eax, ERROR_UNSUPPORTED_FS
  1115.         ret
  1116.  
  1117.     @@:    
  1118.         push    ebx ecx edx esi edi
  1119.         call    ext2_lock
  1120.  
  1121.         add     esi, [esp + 20 + 4]
  1122.  
  1123.         ; Can't create root, but for CreateFolder already existing directory is success.
  1124.         cmp     byte [esi], 0
  1125.         jz      .success
  1126.  
  1127.         push    esi
  1128.         stdcall ext2_inode_find, 0
  1129.         pop     esi
  1130.  
  1131.         ; If the directory is there, we've succeeded.
  1132.         test    eax, eax
  1133.         jz      .success
  1134.  
  1135.         ; Find parent.
  1136.         call    ext2_inode_find_parent
  1137.         test    eax, eax
  1138.         jnz     .error
  1139.  
  1140.         ; Inode ID for preference.
  1141.         mov     eax, esi
  1142.         call    ext2_inode_alloc
  1143.         test    eax, eax
  1144.         jnz     .error_full
  1145.  
  1146.         ; Save allocated inode in EDX; filename is in EDI; parent ID in ESI.
  1147.         mov     edx, ebx
  1148.  
  1149.         push    edi
  1150.  
  1151.         xor     al, al
  1152.         mov     edi, [ebp + EXTFS.ext2_temp_inode]
  1153.         mov     ecx, [ebp + EXTFS.inode_size]
  1154.         rep stosb
  1155.  
  1156.         mov     edi, [ebp + EXTFS.ext2_temp_inode]
  1157.         add     edi, EXT2_INODE_STRUC.i_atime
  1158.         call    current_unix_time
  1159.  
  1160.         add     edi, 8
  1161.         call    current_unix_time
  1162.  
  1163.         pop     edi
  1164.  
  1165.         mov     ebx, [ebp + EXTFS.ext2_temp_inode]
  1166.         mov     [ebx + EXT2_INODE_STRUC.i_mode], EXT2_S_IFDIR or PERMISSIONS
  1167.         mov     eax, edx
  1168.         call    ext2_inode_write
  1169.         test    eax, eax
  1170.         jnz     .error
  1171.  
  1172.         ; Link to self.
  1173.         push    edx esi
  1174.  
  1175.         mov     eax, edx
  1176.         mov     ebx, eax
  1177.         mov     dl, EXT2_FT_DIR
  1178.         mov     esi, self_link
  1179.         call    ext2_inode_link
  1180.  
  1181.         pop     esi edx
  1182.  
  1183.         test    eax, eax
  1184.         jnz     .error
  1185.  
  1186.         ; Link to parent.
  1187.         push    edx esi
  1188.  
  1189.         mov     eax, ebx
  1190.         mov     ebx, esi
  1191.         mov     dl, EXT2_FT_DIR
  1192.         mov     esi, parent_link
  1193.         call    ext2_inode_link
  1194.  
  1195.         pop     esi edx
  1196.  
  1197.         test    eax, eax
  1198.         jnz     .error
  1199.  
  1200.         ; Link parent to child.
  1201.         mov     eax, esi
  1202.         mov     ebx, edx
  1203.         mov     esi, edi
  1204.         mov     dl, EXT2_FT_DIR
  1205.         call    ext2_inode_link
  1206.         test    eax, eax
  1207.         jnz     .error
  1208.  
  1209.         ; Get block group descriptor for allocated inode's block.
  1210.         mov     eax, ebx
  1211.         dec     eax
  1212.         xor     edx, edx
  1213.        
  1214.         ; EAX = block group.
  1215.         div     [ebp + EXTFS.superblock + EXT2_SB_STRUC.inodes_per_group]
  1216.         mov     edx, eax
  1217.  
  1218.         call    ext2_bg_read_desc
  1219.         test    eax, eax
  1220.         jz      .error
  1221.  
  1222.         inc     [eax + EXT2_BLOCK_GROUP_DESC.used_dirs_count]
  1223.         mov     eax, edx
  1224.         call    ext2_bg_write_desc
  1225.         test    eax, eax
  1226.         jnz     .error
  1227.  
  1228.     .success:
  1229.         call    ext2_sb_update
  1230.  
  1231.         ; Sync the disk.
  1232.         mov     esi, [ebp + PARTITION.Disk]
  1233.         call    disk_sync                       ; eax contains error code, if any.
  1234.  
  1235.     .return:
  1236.         push    eax
  1237.         call    ext2_unlock
  1238.         pop     eax
  1239.  
  1240.         pop     edi esi edx ecx ebx
  1241.         ;DEBUGF  1, "Returning with: %x.\n", eax
  1242.         ret
  1243.  
  1244.     .error:
  1245.         call    ext2_sb_update
  1246.  
  1247.         ; Sync the disk.
  1248.         mov     esi, [ebp + PARTITION.Disk]
  1249.         call    disk_sync                       ; eax contains error code, if any.
  1250.        
  1251.         mov     eax, ERROR_ACCESS_DENIED
  1252.         jmp     .return
  1253.  
  1254.     .error_full:
  1255.         mov     eax, ERROR_DISK_FULL
  1256.         jmp     .return
  1257.  
  1258. self_link   db ".", 0
  1259. parent_link db "..", 0
  1260.  
  1261. ;---------------------------------------------------------------------
  1262. ; Rewrite a file.
  1263. ; Input:        esi + [esp + 4] = file name.
  1264. ;               ebx = pointer to paramteres from sysfunc 70.
  1265. ;               ebp = pointer to EXTFS structure.
  1266. ; Output:       eax = error code.
  1267. ;               ebx = bytes written.
  1268. ;---------------------------------------------------------------------
  1269. ext2_Rewrite:
  1270.         ;DEBUGF  1, "Attempting Rewrite.\n"
  1271.         test    [ebp + EXTFS.partition_flags], EXT2_RO
  1272.         jz      @F
  1273.  
  1274.         mov     eax, ERROR_UNSUPPORTED_FS
  1275.         ret
  1276.  
  1277.     @@:
  1278.         push    ecx edx esi edi
  1279.         pushad
  1280.  
  1281.         call    ext2_lock
  1282.  
  1283.         add     esi, [esp + 16 + 32 + 4]
  1284.         ; Can't create root.
  1285.         cmp     byte [esi], 0
  1286.         jz      .error_access_denied
  1287.  
  1288.         push    esi
  1289.         stdcall ext2_inode_find, 0
  1290.         pop     esi
  1291.  
  1292.         ; If the file is there, delete it.
  1293.         test    eax, eax
  1294.         jnz     @F
  1295.  
  1296.         pushad
  1297.  
  1298.         push    eax
  1299.         call    ext2_unlock
  1300.         pop     eax
  1301.  
  1302.         push    dword 0x00000000
  1303.         call    ext2_Delete
  1304.         add     esp, 4
  1305.  
  1306.         push    eax
  1307.         call    ext2_lock
  1308.         pop     eax
  1309.  
  1310.         test    eax, eax
  1311.         jnz     .error_access_denied_delete
  1312.  
  1313.         popad
  1314.     @@:
  1315.         ; Find parent.
  1316.         call    ext2_inode_find_parent
  1317.         test    eax, eax
  1318.         jnz     .error_access_denied
  1319.  
  1320.         ; Inode ID for preference.
  1321.         mov     eax, esi
  1322.         call    ext2_inode_alloc
  1323.         test    eax, eax
  1324.         jnz     .error_full
  1325.  
  1326.         ; Save allocated inode in EDX; filename is in EDI; parent ID in ESI.
  1327.         mov     edx, ebx
  1328.  
  1329.         push    edi
  1330.  
  1331.         xor     al, al
  1332.         mov     edi, [ebp + EXTFS.ext2_temp_inode]
  1333.         mov     ecx, [ebp + EXTFS.inode_size]
  1334.         rep stosb
  1335.  
  1336.         mov     edi, [ebp + EXTFS.ext2_temp_inode]
  1337.         add     edi, EXT2_INODE_STRUC.i_atime
  1338.         call    current_unix_time
  1339.  
  1340.         add     edi, 8
  1341.         call    current_unix_time
  1342.  
  1343.         pop     edi
  1344.  
  1345.         mov     ebx, [ebp + EXTFS.ext2_temp_inode]
  1346.         mov     [ebx + EXT2_INODE_STRUC.i_mode], EXT2_S_IFREG or PERMISSIONS
  1347.         mov     eax, edx
  1348.         call    ext2_inode_write
  1349.         test    eax, eax
  1350.         jnz     .error
  1351.  
  1352.         ; Link parent to child.
  1353.         mov     eax, esi
  1354.         mov     ebx, edx
  1355.         mov     esi, edi
  1356.         mov     dl, EXT2_FT_REG_FILE
  1357.         call    ext2_inode_link
  1358.         test    eax, eax
  1359.         jnz     .error
  1360.  
  1361.         popad
  1362.         push    eax
  1363.         call    ext2_unlock
  1364.         pop     eax
  1365.  
  1366.         push    dword 0x00000000
  1367.         call    ext2_Write
  1368.         add     esp, 4
  1369.  
  1370.         push    eax
  1371.         call    ext2_lock
  1372.         pop     eax
  1373.  
  1374.     .success:
  1375.         push    eax
  1376.         call    ext2_sb_update
  1377.  
  1378.         ; Sync the disk.
  1379.         mov     esi, [ebp + PARTITION.Disk]
  1380.         call    disk_sync                       ; eax contains error code, if any.
  1381.         pop     eax
  1382.  
  1383.     .return:
  1384.         push    eax
  1385.         call    ext2_unlock
  1386.         pop     eax
  1387.  
  1388.         pop     edi esi edx ecx
  1389.  
  1390.         ;DEBUGF  1, "And returning with: %x.\n", eax
  1391.         ret
  1392.  
  1393.     .error:      
  1394.         mov     eax, ERROR_ACCESS_DENIED
  1395.         jmp     .success
  1396.  
  1397.     .error_access_denied_delete:
  1398.         popad
  1399.  
  1400.     .error_access_denied:
  1401.         popad
  1402.         xor     ebx, ebx
  1403.  
  1404.         mov     eax, ERROR_ACCESS_DENIED
  1405.         jmp     .return
  1406.  
  1407.     .error_full:
  1408.         popad
  1409.         xor     ebx, ebx
  1410.  
  1411.         mov     eax, ERROR_DISK_FULL
  1412.         jmp     .return
  1413.  
  1414. ;---------------------------------------------------------------------
  1415. ; Write to a file.
  1416. ; Input:        esi + [esp + 4] = file name.
  1417. ;               ebx = pointer to paramteres from sysfunc 70.
  1418. ;               ebp = pointer to EXTFS structure.
  1419. ; Output:       eax = error code.
  1420. ;               ebx = number of bytes written.
  1421. ;---------------------------------------------------------------------
  1422. ext2_Write:
  1423.         ;DEBUGF 1, "Attempting write, "
  1424.         test    [ebp + EXTFS.partition_flags], EXT2_RO
  1425.         jz      @F
  1426.  
  1427.         mov     eax, ERROR_UNSUPPORTED_FS
  1428.         ret
  1429.  
  1430.     @@:    
  1431.         push    ecx edx esi edi
  1432.         call    ext2_lock
  1433.  
  1434.         add     esi, [esp + 16 + 4]
  1435.  
  1436.         ; Can't write to root.
  1437.         cmp     byte [esi], 0
  1438.         jz      .error
  1439.  
  1440.         push    ebx ecx edx
  1441.         stdcall ext2_inode_find, 0
  1442.         pop     edx ecx ebx
  1443.         ; If file not there, error.
  1444.         xor     ecx, ecx
  1445.         test    eax, eax
  1446.         jnz     .error_file_not_found
  1447.  
  1448.         ; Save the inode.
  1449.         push    esi
  1450.  
  1451.         ; Check if it's a file.
  1452.         mov     edx, [ebp + EXTFS.ext2_save_inode]
  1453.         test    [edx + EXT2_INODE_STRUC.i_mode], EXT2_S_IFREG
  1454.         jz      .error
  1455.  
  1456.         mov     eax, esi
  1457.         mov     ecx, [ebx + 4]
  1458.  
  1459.         call    ext2_inode_extend
  1460.         xor     ecx, ecx
  1461.         test    eax, eax
  1462.         jnz     .error_device
  1463.  
  1464.         ; ECX contains the size to write, and ESI points to it.
  1465.         mov     ecx, [ebx + 0x0C]
  1466.         mov     esi, [ebx + 0x10]
  1467.  
  1468.         ; Save the size of the inode.
  1469.         mov     eax, [edx + EXT2_INODE_STRUC.i_size]
  1470.         push    eax
  1471.  
  1472.         xor     edx, edx
  1473.         div     [ebp + EXTFS.block_size]
  1474.  
  1475.         test    edx, edx
  1476.         jz      .start_aligned
  1477.  
  1478.         ; Start isn't aligned, so deal with the non-aligned bytes.
  1479.         mov     ebx, [ebp + EXTFS.block_size]
  1480.         sub     ebx, edx
  1481.  
  1482.         cmp     ebx, ecx
  1483.         jbe     @F
  1484.  
  1485.         ; If the size to copy fits in current block, limit to that, instead of the entire block.
  1486.         mov     ebx, ecx
  1487.  
  1488.     @@:
  1489.         ; Copy EBX bytes, in EAX indexed block.
  1490.         push    eax
  1491.         call    ext2_inode_read_entry
  1492.         test    eax, eax
  1493.         pop     eax
  1494.         jnz     .error_inode_size
  1495.  
  1496.         push    ecx
  1497.        
  1498.         mov     ecx, ebx
  1499.         mov     edi, ebx
  1500.         add     edi, edx
  1501.         rep movsb
  1502.  
  1503.         pop     ecx
  1504.  
  1505.         ; Write the block.
  1506.         call    ext2_inode_write_entry
  1507.         test    eax, eax
  1508.         jnz     .error_inode_size
  1509.  
  1510.         add     [esp], ebx
  1511.         sub     ecx, ebx
  1512.         jz      .write_inode
  1513.  
  1514.     .start_aligned:
  1515.         cmp     ecx, [ebp + EXTFS.block_size]
  1516.         jb      @F
  1517.  
  1518.         mov     eax, [esp]
  1519.         xor     edx, edx
  1520.         div     [ebp + EXTFS.block_size]
  1521.  
  1522.         push    eax
  1523.         mov     edx, [esp + 8]
  1524.         call    ext2_inode_blank_entry
  1525.         test    eax, eax
  1526.         pop     eax
  1527.         jnz     .error_inode_size
  1528.  
  1529.         push    ecx
  1530.  
  1531.         mov     ecx, [ebp + EXTFS.block_size]
  1532.         mov     edi, [ebp + EXTFS.ext2_save_block]
  1533.         rep movsb
  1534.  
  1535.         pop     ecx
  1536.  
  1537.         call    ext2_inode_write_entry
  1538.         test    eax, eax
  1539.         jnz     .error_inode_size
  1540.  
  1541.         mov     eax, [ebp + EXTFS.block_size]
  1542.         sub     ecx, eax
  1543.         add     [esp], eax
  1544.         jmp     .start_aligned        
  1545.  
  1546.     ; Handle the remaining bytes.
  1547.     @@:
  1548.         test    ecx, ecx
  1549.         jz      .write_inode
  1550.  
  1551.         mov     eax, [esp]
  1552.         xor     edx, edx
  1553.         div     [ebp + EXTFS.block_size]
  1554.  
  1555.         push    eax
  1556.         call    ext2_inode_read_entry
  1557.         test    eax, eax
  1558.         pop     eax
  1559.         jz      @F
  1560.  
  1561.         push    eax
  1562.         mov     edx, [esp + 8]
  1563.  
  1564.         call    ext2_inode_blank_entry
  1565.         test    eax, eax
  1566.         pop     eax
  1567.         jnz     .error_inode_size
  1568.  
  1569.     @@:
  1570.         push    ecx
  1571.         mov     edi, [ebp + EXTFS.ext2_save_block]
  1572.         rep movsb
  1573.         pop     ecx
  1574.  
  1575.         call    ext2_inode_write_entry
  1576.         test    eax, eax
  1577.         jnz     .error_inode_size
  1578.  
  1579.         add     [esp], ecx
  1580.         xor     ecx, ecx
  1581.  
  1582.     .write_inode:
  1583.         mov     ebx, [ebp + EXTFS.ext2_temp_inode]
  1584.         pop     eax
  1585.         mov     [ebx + EXT2_INODE_STRUC.i_size], eax
  1586.         mov     eax, [esp]
  1587.  
  1588.         call    ext2_inode_write
  1589.         test    eax, eax
  1590.         jnz     .error_device
  1591.  
  1592.     .success:
  1593.         call    ext2_sb_update
  1594.  
  1595.         ; Sync the disk.
  1596.         mov     esi, [ebp + PARTITION.Disk]
  1597.         call    disk_sync                       ; eax contains error code, if any.
  1598.  
  1599.     .return:
  1600.         push    eax
  1601.         call    ext2_unlock
  1602.         pop     eax
  1603.  
  1604.         add     esp, 4
  1605.  
  1606.         mov     ebx, [esp + 12]
  1607.         sub     ebx, ecx
  1608.         pop     edi esi edx ecx
  1609.  
  1610.         ;DEBUGF  1, "and returning with: %x.\n", eax
  1611.         ret
  1612.  
  1613.     .error:
  1614.         mov     eax, ERROR_ACCESS_DENIED
  1615.         jmp     .return
  1616.  
  1617.     .error_file_not_found:
  1618.         mov     eax, ERROR_FILE_NOT_FOUND
  1619.         jmp     .return
  1620.  
  1621.     .error_inode_size:
  1622.         mov     ebx, [ebp + EXTFS.ext2_temp_inode]
  1623.         pop     eax
  1624.         mov     [ebx + EXT2_INODE_STRUC.i_size], eax
  1625.         mov     eax, [esp]
  1626.  
  1627.         call    ext2_inode_write
  1628.  
  1629.     .error_device:        
  1630.         call    ext2_sb_update
  1631.  
  1632.         ; Sync the disk.
  1633.         mov     esi, [ebp + PARTITION.Disk]
  1634.         call    disk_sync                       ; eax contains error code, if any.
  1635.  
  1636.         mov     eax, ERROR_DEVICE
  1637.         jmp     .return
  1638.  
  1639. ;---------------------------------------------------------------------
  1640. ; Set the end of a file.
  1641. ; Input:        esi + [esp + 4] = file name.
  1642. ;               ebx = pointer to paramteres from sysfunc 70.
  1643. ;               ebp = pointer to EXTFS structure.
  1644. ; Output:       eax = error code.
  1645. ;---------------------------------------------------------------------
  1646. ext2_SetFileEnd:
  1647.         test    [ebp + EXTFS.partition_flags], EXT2_RO
  1648.         jz      @F
  1649.  
  1650.         mov     eax, ERROR_UNSUPPORTED_FS
  1651.         ret
  1652.  
  1653.     @@:    
  1654.         push    ebx ecx edx esi edi
  1655.         call    ext2_lock
  1656.  
  1657.         add     esi, [esp + 20 + 4]
  1658.  
  1659.         ; Can't write to root.
  1660.         cmp     byte [esi], 0
  1661.         jz      .error
  1662.  
  1663.         stdcall ext2_inode_find, 0
  1664.         ; If file not there, error.
  1665.         test    eax, eax
  1666.         jnz     .error_file_not_found
  1667.  
  1668.         ; Check if it's a file.
  1669.         mov     edx, [ebp + EXTFS.ext2_save_inode]
  1670.         cmp     [edx + EXT2_INODE_STRUC.i_mode], EXT2_S_IFREG
  1671.         jne     .error
  1672.  
  1673.         mov     eax, esi
  1674.         mov     ecx, [ebx + 4]
  1675.         call    ext2_inode_extend
  1676.         test    eax, eax
  1677.         jnz     .error_disk_full
  1678.  
  1679.         mov     eax, esi
  1680.         call    ext2_inode_truncate
  1681.         test    eax, eax
  1682.         jnz     .error_disk_full
  1683.  
  1684.         mov     eax, esi
  1685.         mov     ebx, [ebp + EXTFS.ext2_temp_inode]
  1686.         call    ext2_inode_write
  1687.  
  1688.         call    ext2_sb_update
  1689.  
  1690.         ; Sync the disk.
  1691.         mov     esi, [ebp + PARTITION.Disk]
  1692.         call    disk_sync                       ; eax contains error code, if any.
  1693.  
  1694.     .return:
  1695.         push    eax
  1696.         call    ext2_unlock
  1697.         pop     eax
  1698.  
  1699.         pop     edi esi edx ecx ebx
  1700.         ret
  1701.  
  1702.     .error:
  1703.         mov     eax, ERROR_ACCESS_DENIED
  1704.         jmp     .return
  1705.  
  1706.     .error_file_not_found:
  1707.         mov     eax, ERROR_FILE_NOT_FOUND
  1708.         jmp     .return
  1709.  
  1710.     .error_disk_full:        
  1711.         call    ext2_sb_update
  1712.  
  1713.         ; Sync the disk.
  1714.         mov     esi, [ebp + PARTITION.Disk]
  1715.         call    disk_sync                       ; eax contains error code, if any.
  1716.  
  1717.         mov     eax, ERROR_DISK_FULL
  1718.         jmp     .return
  1719.