Subversion Repositories Kolibri OS

Rev

Rev 6880 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2. ;;                                                              ;;
  3. ;; Copyright (C) KolibriOS team 2013-2016. All rights reserved. ;;
  4. ;;  Distributed under terms of the GNU General Public License.  ;;
  5. ;;                                                              ;;
  6. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  7.  
  8. $Revision: 6933 $
  9.  
  10. ; EXT external functions
  11. ;   in:
  12. ; ebx -> parameter structure of sysfunc 70
  13. ; ebp -> EXTFS structure
  14. ; esi -> path string in UTF-8
  15. ;   out:
  16. ; eax, ebx = return values for sysfunc 70
  17. iglobal
  18. align 4
  19. ext_user_functions:
  20.         dd      ext_free
  21.         dd      (ext_user_functions_end - ext_user_functions - 4) / 4
  22.         dd      ext_ReadFile
  23.         dd      ext_ReadFolder
  24.         dd      ext_CreateFile
  25.         dd      ext_WriteFile
  26.         dd      ext_SetFileEnd
  27.         dd      ext_GetFileInfo
  28.         dd      ext_SetFileInfo
  29.         dd      0
  30.         dd      ext_Delete
  31.         dd      ext_CreateFolder
  32.         dd      ext_Rename
  33. ext_user_functions_end:
  34. endg
  35.  
  36. struct DIRENTRY
  37. inodeNumber     dd  ?
  38. entryLength     dw  ?
  39. nameLength      db  ?
  40. fileType        db  ?
  41. name            db  ?   ; rb [nameLength]
  42. ends
  43.  
  44. struct INODE
  45. accessMode      dw  ?
  46. UID             dw  ?
  47. fileSize        dd  ?
  48. accessedTime    dd  ?
  49. inodeModified   dd  ?
  50. dataModified    dd  ?
  51. deletedTime     dd  ?
  52. GID             dw  ?
  53. linksCount      dw  ?
  54. sectorsUsed     dd  ?
  55. featureFlags    dd  ?
  56. reserved        dd  ?
  57. blockNumbers    rd  12
  58. addressBlock    dd  ?
  59. doubleAddress   dd  ?
  60. tripleAddress   dd  ?
  61. generation      dd  ?
  62. ACL             dd  ?
  63. fileSizeHigh    dd  ?
  64. ends
  65.  
  66. struct BGDESCR  ; block group descriptor
  67. blockBitmap         dd  ?
  68. inodeBitmap         dd  ?
  69. inodeTable          dd  ?
  70. blocksFree          dw  ?
  71. inodesFree          dw  ?
  72. directoriesCount    dw  ?
  73. reserved            rb  14
  74. ends
  75.  
  76. struct SUPERBLOCK
  77. inodesTotal         dd  ?
  78. blocksTotal         dd  ?
  79. blocksReserved      dd  ?
  80. blocksFree          dd  ?
  81. inodesFree          dd  ?
  82. firstGroupBlock     dd  ?
  83. sectorsPerBlockLog  dd  ?   ; shift for 1024
  84. fragmentSizeLog     dd  ?
  85. blocksPerGroup      dd  ?
  86. fragmentsPerGroup   dd  ?
  87. inodesPerGroup      dd  ?
  88. lastMountTime       dd  ?
  89. lastWriteTime       dd  ?
  90. mountCount          dw  ?
  91. mountMax            dw  ?
  92. magic               dw  ?
  93. state               dw  ?
  94. errorHandling       dw  ?
  95. additionalVersion   dw  ?
  96. lastCheck           dd  ?
  97. checkInterval       dd  ?
  98. creatorOS           dd  ?
  99. dynamicVersionFlag  dd  ?
  100. reservedUID         dw  ?
  101. reservedGID         dw  ?
  102. firstInode          dd  ?
  103. inodeSize           dw  ?
  104. thisBlockGroup      dw  ?
  105. compatibleFlags     dd  ?
  106. incompatibleFlags   dd  ?
  107. RO_compatibleFlags  dd  ?
  108. UUID                rb  16
  109. volumeLabel         rb  16
  110. ends
  111.  
  112. ; ext4 extent tree
  113. struct NODEHEADER       ; tree node header
  114. magic           dw  ?   ; 0xF30A
  115. entriesFolow    dw  ?
  116. entriesMax      dw  ?
  117. currentDepth    dw  ?
  118. generation      dd  ?
  119. ends
  120.  
  121. struct INDEX    ; root/branch
  122. fileBlock       dd  ?
  123. nodeBlock       dd  ?
  124. nodeBlockHigh   dw  ?
  125. reserved        dw  ?
  126. ends
  127.  
  128. struct EXTENT   ; leaf
  129. fileBlock       dd  ?
  130. blocksCount     dw  ?
  131. fsBlockHigh     dw  ?
  132. fsBlock         dd  ?
  133. ends
  134.  
  135. ROOT_INODE = 2
  136. EXTENTS_USED = 80000h
  137. TYPE_MASK = 0F000h
  138. FLAG_FILE = 8000h
  139. DIRECTORY = 4000h
  140. DIR_FLAG_FILE = 1
  141. DIR_DIRECTORY = 2
  142. KOS_HIDDEN = 2
  143. KOS_DIRECTORY = 10h
  144. READ_ONLY = 1
  145.  
  146. ; Implemented "incompatible" features:
  147. ; 2 = have file type in directory entry
  148. ; 40h = extents
  149. ; 200h = flexible block groups
  150. INCOMPATIBLE_SUPPORT = 242h
  151. ; Read only support for "incompatible" features:
  152. INCOMPATIBLE_READ_SUPPORT = 240h
  153.  
  154. ; Implemented "read-only" features:
  155. ; 1 = sparse superblock
  156. ; 2 = 64-bit file size
  157. READ_ONLY_SUPPORT = 3
  158.  
  159. struct EXTFS PARTITION
  160. Lock                MUTEX
  161. mountType           dd  ?
  162. bytesPerBlock       dd  ?
  163. sectorsPerBlock     dd  ?
  164. dwordsPerBlock      dd  ?
  165. dwordsPerBranch     dd  ?   ; dwordsPerBlock ^ 2
  166. mainBlockBuffer     dd  ?
  167. tempBlockBuffer     dd  ?
  168. descriptorTable     dd  ?
  169. descriptorTableEnd  dd  ?
  170. align0  rb  200h-EXTFS.align0
  171. superblock          SUPERBLOCK
  172. align1  rb  400h-EXTFS.align1
  173. rootInodeBuffer     INODE
  174. align2  rb  600h-EXTFS.align2
  175. inodeBuffer         INODE
  176. align3  rb  800h-EXTFS.align3
  177. ends
  178.  
  179. ; mount if it's a valid EXT partition
  180. ext2_create_partition:
  181. ;   in:
  182. ; ebp -> PARTITION structure
  183. ; ebx -> boot sector
  184. ; ebx+512 -> buffer
  185. ;   out:
  186. ; eax -> EXTFS structure, 0 = not EXT
  187.         push    ebx
  188.         cmp     dword [esi+DISK.MediaInfo.SectorSize], 512
  189.         jnz     .fail
  190.         mov     eax, 2
  191.         add     ebx, 512
  192.         call    fs_read32_sys
  193.         test    eax, eax
  194.         jnz     .fail
  195.         cmp     [ebx+SUPERBLOCK.magic], 0xEF53
  196.         jne     .fail
  197.         cmp     [ebx+SUPERBLOCK.state], 1
  198.         ja      .fail
  199.         test    [ebx+SUPERBLOCK.incompatibleFlags], not INCOMPATIBLE_SUPPORT
  200.         jnz     .fail
  201.         cmp     [ebx+SUPERBLOCK.sectorsPerBlockLog], 6  ; 64KB
  202.         ja      .fail
  203.         cmp     [ebx+SUPERBLOCK.inodeSize], 512
  204.         ja      .fail
  205.         cmp     [ebx+SUPERBLOCK.blocksPerGroup], 0
  206.         je      .fail
  207.         cmp     [ebx+SUPERBLOCK.inodesPerGroup], 0
  208.         je      .fail
  209.         movi    eax, sizeof.EXTFS
  210.         call    malloc
  211.         test    eax, eax
  212.         jz      .fail
  213.         mov     ecx, dword [ebp+PARTITION.FirstSector]
  214.         mov     dword [eax+EXTFS.FirstSector], ecx
  215.         mov     ecx, dword [ebp+PARTITION.FirstSector+4]
  216.         mov     dword [eax+EXTFS.FirstSector+4], ecx
  217.         mov     ecx, dword [ebp+PARTITION.Length]
  218.         mov     dword [eax+EXTFS.Length], ecx
  219.         mov     ecx, dword [ebp+PARTITION.Length+4]
  220.         mov     dword [eax+EXTFS.Length+4], ecx
  221.         mov     ecx, [ebp+PARTITION.Disk]
  222.         mov     [eax+EXTFS.Disk], ecx
  223.         mov     [eax+EXTFS.FSUserFunctions], ext_user_functions
  224.  
  225.         push    ebp esi edi
  226.         mov     ebp, eax
  227.         lea     ecx, [eax+EXTFS.Lock]
  228.         call    mutex_init
  229.         mov     esi, ebx
  230.         lea     edi, [ebp+EXTFS.superblock]
  231.         mov     ecx, 512/4
  232.         rep movsd   ; copy superblock
  233.         mov     ecx, [ebx+SUPERBLOCK.sectorsPerBlockLog]
  234.         inc     ecx
  235.         mov     eax, 1
  236.         shl     eax, cl
  237.         mov     [ebp+EXTFS.sectorsPerBlock], eax
  238.         shl     eax, 9
  239.         mov     [ebp+EXTFS.bytesPerBlock], eax
  240.         shl     eax, 1
  241.         push    eax
  242.         shr     eax, 3
  243.         mov     [ebp+EXTFS.dwordsPerBlock], eax
  244.         mul     eax
  245.         mov     [ebp+EXTFS.dwordsPerBranch], eax
  246.         call    kernel_alloc
  247.         test    eax, eax
  248.         jz      .error
  249.         mov     [ebp+EXTFS.mainBlockBuffer], eax
  250.         add     eax, [ebp+EXTFS.bytesPerBlock]
  251.         mov     [ebp+EXTFS.tempBlockBuffer], eax
  252.         mov     [ebp+EXTFS.mountType], 0
  253.         test    [ebx+SUPERBLOCK.RO_compatibleFlags], not READ_ONLY_SUPPORT
  254.         jnz     .read_only
  255.         test    [ebx+SUPERBLOCK.incompatibleFlags], INCOMPATIBLE_READ_SUPPORT
  256.         jz      @f
  257. .read_only:
  258.         or      [ebp+EXTFS.mountType], READ_ONLY
  259. @@:
  260.         mov     eax, [ebx+SUPERBLOCK.inodesTotal]
  261.         dec     eax
  262.         xor     edx, edx
  263.         div     [ebx+SUPERBLOCK.inodesPerGroup]
  264.         inc     eax
  265.         shl     eax, 5
  266.         push    eax eax
  267.         call    kernel_alloc
  268.         pop     ecx
  269.         test    eax, eax
  270.         jz      .error2
  271.         mov     [ebp+EXTFS.descriptorTable], eax
  272.         mov     ebx, eax
  273.         add     eax, ecx
  274.         mov     [ebp+EXTFS.descriptorTableEnd], eax
  275.         mov     eax, [ebp+EXTFS.superblock.firstGroupBlock]
  276.         inc     eax
  277.         mul     [ebp+EXTFS.sectorsPerBlock]
  278.         dec     ecx
  279.         shr     ecx, 9
  280.         inc     ecx
  281.         call    fs_read64_sys
  282.         test    eax, eax
  283.         jnz     @f
  284.         mov     al, ROOT_INODE
  285.         lea     ebx, [ebp+EXTFS.rootInodeBuffer]
  286.         call    readInode
  287.         test    eax, eax
  288.         jnz     @f
  289.         mov     eax, ebp
  290.         pop     edi esi ebp ebx
  291.         ret
  292.  
  293. @@:
  294.         stdcall kernel_free, [ebp+EXTFS.descriptorTable]
  295. .error2:
  296.         stdcall kernel_free, [ebp+EXTFS.mainBlockBuffer]
  297. .error:
  298.         mov     eax, ebp
  299.         call    free
  300.         pop     edi esi ebp
  301. .fail:
  302.         pop     ebx
  303.         xor     eax, eax
  304.         ret
  305.  
  306. ; unmount EXT partition
  307. ext_free:
  308. ; in: eax -> EXTFS structure
  309.         push    eax [eax+EXTFS.mainBlockBuffer]
  310.         stdcall kernel_free, [eax+EXTFS.descriptorTable]
  311.         call    kernel_free
  312.         pop     eax
  313.         jmp     free
  314.  
  315. extfsWriteBlock:
  316.         push    fs_write64_sys
  317.         jmp     @f
  318. ; in: eax = block number, ebx -> buffer
  319. extfsReadBlock:
  320.         push    fs_read64_sys
  321. @@:
  322.         push    ecx edx
  323.         mov     ecx, [ebp+EXTFS.sectorsPerBlock]
  324.         mul     ecx
  325.         call    dword[esp+8]
  326.         pop     edx ecx
  327.         add     esp, 4
  328.         test    eax, eax
  329.         jz      @f
  330.         movi    eax, ERROR_DEVICE
  331.         stc
  332. @@:
  333.         ret
  334.  
  335. extfsWriteDescriptor:
  336. ; in: ebx = block group descriptor
  337.         mov     eax, [ebp+EXTFS.superblock.firstGroupBlock]
  338.         inc     eax
  339.         mul     [ebp+EXTFS.sectorsPerBlock]
  340.         sub     ebx, [ebp+EXTFS.descriptorTable]
  341.         shr     ebx, 9
  342.         add     eax, ebx
  343.         shl     ebx, 9
  344.         add     ebx, [ebp+EXTFS.descriptorTable]
  345.         call    fs_write32_sys
  346.         ret
  347.  
  348. extfsExtentFree:
  349. ; in: eax = first block number, ecx = extent size
  350.         push    ebx edx edi
  351.         sub     eax, [ebp+EXTFS.superblock.firstGroupBlock]
  352.         xor     edx, edx
  353.         mov     ebx, [ebp+EXTFS.superblock.blocksPerGroup]
  354.         div     ebx
  355.         sub     ebx, edx
  356.         sub     ebx, ecx
  357.         jc      .ret
  358.         push    edx
  359.         mov     ebx, [ebp+EXTFS.descriptorTable]
  360.         shl     eax, 5
  361.         add     ebx, eax
  362.         mov     eax, ecx
  363.         mul     [ebp+EXTFS.sectorsPerBlock]
  364.         add     [ebx+BGDESCR.blocksFree], cx
  365.         add     [ebp+EXTFS.superblock.blocksFree], ecx
  366.         sub     [ebp+EXTFS.inodeBuffer.sectorsUsed], eax
  367.         push    [ebx+BGDESCR.blockBitmap]
  368.         call    extfsWriteDescriptor
  369.         pop     eax
  370.         mov     ebx, [ebp+EXTFS.tempBlockBuffer]
  371.         mov     edx, eax
  372.         call    extfsReadBlock
  373.         pop     eax
  374.         jc      .ret
  375.         push    ebx edx
  376.         mov     edi, eax
  377.         shr     edi, 5
  378.         shl     edi, 2
  379.         add     edi, ebx
  380.         mov     edx, ecx
  381.         and     eax, 31
  382.         jz      .aligned
  383.         mov     ecx, 32
  384.         sub     ecx, eax
  385.         sub     edx, ecx
  386.         jnc     @f
  387.         add     ecx, edx
  388.         xor     edx, edx
  389. @@:
  390.         or      ebx, -1
  391.         shl     ebx, cl
  392.         not     ebx
  393.         mov     ecx, eax
  394.         shl     ebx, cl
  395.         not     ebx
  396.         and     [edi], ebx
  397.         add     edi, 4
  398.         xor     eax, eax
  399. .aligned:
  400.         mov     ecx, edx
  401.         shr     ecx, 5
  402.         rep stosd
  403.         and     edx, 31
  404.         jz      @f
  405.         mov     ecx, edx
  406.         not     eax
  407.         shl     eax, cl
  408.         and     [edi], eax
  409. @@:
  410.         pop     eax ebx
  411.         call    extfsWriteBlock
  412. .ret:
  413.         pop     edi edx ebx
  414.         xor     eax, eax
  415.         ret
  416.  
  417. extfsInodeAlloc:
  418. ; in: eax = parent inode number
  419. ; out: ebx = allocated inode number
  420.         push    ecx edx edi
  421.         dec     eax
  422.         xor     edx, edx
  423.         div     [ebp+EXTFS.superblock.inodesPerGroup]
  424.         mov     ebx, [ebp+EXTFS.descriptorTable]
  425.         shl     eax, 5
  426.         add     ebx, eax
  427.         push    ebx
  428. .test_block_group:
  429.         push    ebx
  430.         cmp     [ebx+BGDESCR.blocksFree], 0
  431.         jz      .next
  432.         cmp     [ebx+BGDESCR.inodesFree], 0
  433.         jz      .next
  434.         dec     [ebx+BGDESCR.inodesFree]
  435.         dec     [ebp+EXTFS.superblock.inodesFree]
  436.         push    [ebx+BGDESCR.inodeBitmap]
  437.         call    extfsWriteDescriptor
  438.         pop     eax
  439.         mov     ebx, [ebp+EXTFS.tempBlockBuffer]
  440.         mov     edx, eax
  441.         mov     edi, ebx
  442.         call    extfsReadBlock
  443.         jc      .fail
  444.         mov     ecx, [ebp+EXTFS.superblock.inodesPerGroup]
  445.         or      eax, -1
  446.         shr     ecx, 5
  447.         repz scasd
  448.         jz      .next
  449.         sub     edi, 4
  450.         mov     eax, [edi]
  451.         not     eax
  452.         bsf     eax, eax
  453.         bts     [edi], eax
  454.         sub     edi, [ebp+EXTFS.tempBlockBuffer]
  455.         shl     edi, 3
  456.         add     eax, edi
  457.         mov     ecx, eax
  458.         mov     eax, edx
  459.         call    extfsWriteBlock
  460.         pop     eax
  461.         sub     eax, [ebp+EXTFS.descriptorTable]
  462.         shr     eax, 5
  463.         mul     [ebp+EXTFS.superblock.inodesPerGroup]
  464.         lea     ebx, [eax+ecx+1]
  465.         xor     eax, eax
  466. .ret:
  467.         pop     edi edi edx ecx
  468.         ret
  469.  
  470. .next:      ; search forward, then backward
  471.         pop     ebx
  472.         cmp     ebx, [esp]
  473.         jc      .backward
  474.         add     ebx, 32
  475.         cmp     ebx, [ebp+EXTFS.descriptorTableEnd]
  476.         jc      .test_block_group
  477.         mov     ebx, [esp]
  478. .backward:
  479.         sub     ebx, 32
  480.         cmp     ebx, [ebp+EXTFS.descriptorTable]
  481.         jnc     .test_block_group
  482.         movi    eax, ERROR_DISK_FULL
  483.         push    eax
  484. .fail:
  485.         pop     edi
  486.         jmp     .ret
  487.  
  488. extfsExtentAlloc:
  489. ; in: eax = parent inode number, ecx = blocks max
  490. ; out: ebx = first block number, ecx = blocks allocated
  491.         push    edx esi edi ecx
  492.         dec     eax
  493.         xor     edx, edx
  494.         div     [ebp+EXTFS.superblock.inodesPerGroup]
  495.         mov     ebx, [ebp+EXTFS.descriptorTable]
  496.         shl     eax, 5
  497.         add     ebx, eax
  498.         push    ebx
  499. .test_block_group:
  500.         push    ebx
  501.         cmp     [ebx+BGDESCR.blocksFree], 0
  502.         jz      .next
  503.         mov     eax, [ebx+BGDESCR.blockBitmap]
  504.         mov     ebx, [ebp+EXTFS.tempBlockBuffer]
  505.         mov     edx, eax
  506.         mov     edi, ebx
  507.         call    extfsReadBlock
  508.         jc      .fail
  509.         mov     ecx, [ebp+EXTFS.superblock.blocksPerGroup]
  510.         shr     ecx, 5
  511.         or      eax, -1
  512.         repz scasd
  513.         jz      .next
  514.         mov     esi, edi
  515.         sub     esi, 4
  516.         push    edx ecx
  517.         mov     eax, [esi]
  518.         not     eax
  519.         bsf     ecx, eax
  520.         not     eax
  521.         shr     eax, cl
  522.         shl     eax, cl
  523.         mov     ebx, 32
  524.         bsf     ebx, eax
  525.         sub     ebx, ecx
  526.         mov     eax, [esp+16]
  527.         cmp     ebx, eax
  528.         jc      @f
  529.         mov     ebx, eax
  530. @@:
  531.         or      eax, -1
  532.         cmp     ebx, 32
  533.         jz      @f
  534.         xchg    ebx, ecx
  535.         shl     eax, cl
  536.         not     eax
  537.         xchg    ebx, ecx
  538.         shl     eax, cl
  539. @@:
  540.         or      [esi], eax
  541.         sub     esi, [ebp+EXTFS.tempBlockBuffer]
  542.         shl     esi, 3
  543.         add     esi, ecx
  544.         mov     eax, [esp+16]
  545.         sub     eax, ebx
  546.         mov     [esp+16], ebx
  547.         add     ebx, ecx
  548.         pop     ecx
  549.         test    eax, eax
  550.         jz      .done
  551.         cmp     ebx, 32
  552.         jnz     .done
  553.         jecxz   .done
  554.         mov     ebx, eax
  555.         shr     eax, 5
  556.         inc     eax
  557.         and     ebx, 31
  558.         cmp     ecx, eax
  559.         jnc     @f
  560.         mov     eax, ecx
  561.         mov     bl, 32
  562. @@:
  563.         mov     ecx, eax
  564.         shl     eax, 5
  565.         add     [esp+12], eax
  566.         xor     eax, eax
  567.         push    edi
  568.         repz scasd
  569.         jz      @f
  570.         mov     eax, [edi-4]
  571.         bsf     eax, eax
  572.         xchg    eax, ebx
  573.         test    ecx, ecx
  574.         jnz     @f
  575.         cmp     ebx, eax
  576.         jc      @f
  577.         mov     ebx, eax
  578. @@:
  579.         inc     ecx
  580.         shl     ecx, 5
  581.         sub     ecx, ebx
  582.         sub     [esp+16], ecx
  583.         mov     ecx, edi
  584.         pop     edi
  585.         sub     ecx, edi
  586.         shr     ecx, 2
  587.         dec     ecx
  588.         or      eax, -1
  589.         rep stosd
  590.         mov     ecx, ebx
  591.         jecxz   .done
  592.         neg     ecx
  593.         add     ecx, 32
  594.         shr     eax, cl
  595.         or      [edi], eax
  596. .done:
  597.         pop     eax
  598.         mov     ebx, [ebp+EXTFS.tempBlockBuffer]
  599.         call    extfsWriteBlock
  600.         mov     ebx, [esp]
  601.         mov     ecx, [esp+8]
  602.         sub     [ebx+BGDESCR.blocksFree], cx
  603.         jnc     @f
  604.         mov     [ebx+BGDESCR.blocksFree], 0
  605. @@:
  606.         sub     [ebp+EXTFS.superblock.blocksFree], ecx
  607.         call    extfsWriteDescriptor
  608.         pop     eax ebx
  609.         sub     eax, [ebp+EXTFS.descriptorTable]
  610.         shr     eax, 5
  611.         mul     [ebp+EXTFS.superblock.blocksPerGroup]
  612.         mov     ebx, eax
  613.         add     ebx, esi
  614.         add     ebx, [ebp+EXTFS.superblock.firstGroupBlock]
  615.         pop     ecx
  616.         mov     eax, ecx
  617.         mul     [ebp+EXTFS.sectorsPerBlock]
  618.         add     [ebp+EXTFS.inodeBuffer.sectorsUsed], eax
  619.         xor     eax, eax
  620. .ret:
  621.         pop     edi esi edx
  622.         ret
  623.  
  624. .next:      ; search forward, then backward
  625.         pop     ebx
  626.         cmp     ebx, [esp]
  627.         jc      .backward
  628.         add     ebx, 32
  629.         cmp     ebx, [ebp+EXTFS.descriptorTableEnd]
  630.         jc      .test_block_group
  631.         mov     ebx, [esp]
  632. .backward:
  633.         sub     ebx, 32
  634.         cmp     ebx, [ebp+EXTFS.descriptorTable]
  635.         jnc     .test_block_group
  636.         movi    eax, ERROR_DISK_FULL
  637.         push    eax
  638. .fail:
  639.         add     esp, 12
  640.         xor     ecx, ecx
  641.         stc
  642.         jmp     .ret
  643.  
  644. extfsGetExtent:
  645. ; in: ecx = starting file block
  646. ; out: eax = first block number, ecx = extent size
  647.         push    ebx edx esi
  648.         lea     esi, [ebp+EXTFS.inodeBuffer]
  649.         test    [esi+INODE.featureFlags], EXTENTS_USED
  650.         jz      .listTreeSearch
  651.         add     esi, INODE.blockNumbers
  652. .extentTreeSearch:
  653.         cmp     word [esi+NODEHEADER.magic], 0xF30A
  654.         jne     .fail
  655.         movzx   ebx, [esi+NODEHEADER.entriesFolow]
  656.         add     esi, sizeof.NODEHEADER
  657.         test    ebx, ebx
  658.         jz      .noBlock
  659.         cmp     word [esi-sizeof.NODEHEADER+NODEHEADER.currentDepth], 0
  660.         je      .leaf_block
  661.         dec     ebx
  662.         jz      .end_search_index
  663. @@:
  664.         cmp     ecx, [esi+sizeof.INDEX+INDEX.fileBlock]
  665.         jb      .end_search_index
  666.         add     esi, sizeof.INDEX
  667.         dec     ebx
  668.         jnz     @b
  669. .end_search_index:
  670.         mov     ebx, [ebp+EXTFS.tempBlockBuffer]
  671.         mov     eax, [esi+INDEX.nodeBlock]
  672.         call    extfsReadBlock
  673.         jc      .fail2
  674.         mov     esi, ebx
  675.         jmp     .extentTreeSearch
  676.  
  677. .fail:
  678.         movi    eax, ERROR_FS_FAIL
  679.         jmp     .fail2
  680.  
  681. .leaf_block:
  682.         movzx   edx, [esi+EXTENT.blocksCount]
  683.         add     edx, [esi+EXTENT.fileBlock]
  684.         sub     edx, ecx
  685.         ja      .end_search_extent
  686.         add     esi, sizeof.EXTENT
  687.         dec     ebx
  688.         jnz     .leaf_block
  689. .noBlock:
  690.         movi    eax, ERROR_END_OF_FILE
  691. .fail2:
  692.         pop     esi edx ebx
  693.         stc
  694.         ret
  695.  
  696. .end_search_extent:
  697.         sub     ecx, [esi+EXTENT.fileBlock]
  698.         jc      .fail
  699.         add     ecx, [esi+EXTENT.fsBlock]
  700.         mov     eax, ecx
  701.         mov     ecx, edx
  702.         pop     esi edx ebx
  703.         ret
  704.  
  705. .listTreeSearch:
  706.         cmp     ecx, 12
  707.         jb      .get_direct_block
  708.         sub     ecx, 12
  709.         cmp     ecx, [ebp+EXTFS.dwordsPerBlock]
  710.         jb      .get_indirect_block
  711.         sub     ecx, [ebp+EXTFS.dwordsPerBlock]
  712.         cmp     ecx, [ebp+EXTFS.dwordsPerBranch]
  713.         jb      .get_double_indirect_block
  714. ; triply-indirect blocks
  715.         sub     ecx, [ebp+EXTFS.dwordsPerBranch]
  716.         mov     eax, [esi+INODE.tripleAddress]
  717.         test    eax, eax
  718.         jz      .noBlock
  719.         mov     ebx, [ebp+EXTFS.tempBlockBuffer]
  720.         call    extfsReadBlock
  721.         jc      .fail2
  722.         xor     edx, edx
  723.         mov     eax, ecx
  724.         div     [ebp+EXTFS.dwordsPerBranch]
  725. ; eax = number in triply-indirect block, edx = number in branch
  726.         mov     eax, [ebx+eax*4]
  727.         test    eax, eax
  728.         jz      .noBlock
  729.         call    extfsReadBlock
  730.         jc      .fail2
  731.         mov     eax, edx
  732.         jmp     @f
  733.  
  734. .get_direct_block:
  735.         mov     edx, ecx
  736.         mov     cl, 12
  737.         lea     ebx, [esi+INODE.blockNumbers]
  738.         jmp     .calculateExtent
  739.  
  740. .get_indirect_block:
  741.         mov     eax, [esi+INODE.addressBlock]
  742.         test    eax, eax
  743.         jz      .noBlock
  744.         mov     ebx, [ebp+EXTFS.tempBlockBuffer]
  745.         call    extfsReadBlock
  746.         jc      .fail2
  747.         mov     edx, ecx
  748.         mov     ecx, [ebp+EXTFS.dwordsPerBlock]
  749.         jmp     .calculateExtent
  750.  
  751. .get_double_indirect_block:
  752.         mov     eax, [esi+INODE.doubleAddress]
  753.         test    eax, eax
  754.         jz      .noBlock
  755.         mov     ebx, [ebp+EXTFS.tempBlockBuffer]
  756.         call    extfsReadBlock
  757.         jc      .fail2
  758.         mov     eax, ecx
  759. @@:
  760.         xor     edx, edx
  761.         mov     ecx, [ebp+EXTFS.dwordsPerBlock]
  762.         div     ecx
  763. ; eax = number in doubly-indirect block, edx = number in indirect block
  764.         mov     eax, [ebx+eax*4]
  765.         test    eax, eax
  766.         jz      .noBlock
  767.         call    extfsReadBlock
  768.         jc      .fail2
  769. .calculateExtent:
  770.         lea     esi, [ebx+edx*4]
  771.         lodsd
  772.         test    eax, eax
  773.         jz      .noBlock
  774.         mov     ebx, eax
  775.         sub     ecx, edx
  776.         xor     edx, edx
  777. @@:
  778.         inc     edx
  779.         dec     ecx
  780.         jz      @f
  781.         lodsd
  782.         sub     eax, ebx
  783.         sub     eax, edx
  784.         jz      @b
  785. @@:
  786.         mov     eax, ebx
  787.         mov     ecx, edx
  788.         pop     esi edx ebx
  789.         clc
  790.         ret
  791.  
  792. getInodeLocation:
  793. ; in: eax = inode number
  794. ; out: eax = inode sector, edx = offset in sector
  795.         dec     eax
  796.         xor     edx, edx
  797.         div     [ebp+EXTFS.superblock.inodesPerGroup]
  798.         shl     eax, 5
  799.         add     eax, [ebp+EXTFS.descriptorTable]
  800.         mov     ebx, [eax+BGDESCR.inodeTable]
  801.         imul    ebx, [ebp+EXTFS.sectorsPerBlock]
  802.         movzx   eax, [ebp+EXTFS.superblock.inodeSize]
  803.         mul     edx
  804.         mov     edx, eax
  805.         shr     eax, 9
  806.         and     edx, 511
  807.         add     eax, ebx
  808.         ret
  809.  
  810. writeInode:
  811. ; in: eax = inode number, ebx -> inode data
  812.         push    edx edi esi ecx ebx eax
  813.         mov     edi, ebx
  814.         call    fsGetTime
  815.         add     eax, 978307200
  816.         mov     [edi+INODE.inodeModified], eax
  817.         pop     eax
  818.         cmp     eax, ROOT_INODE
  819.         jnz     @f
  820.         movzx   ecx, [ebp+EXTFS.superblock.inodeSize]
  821.         mov     esi, edi
  822.         lea     edi, [ebp+EXTFS.rootInodeBuffer]
  823.         rep movsb
  824. @@:
  825.         call    getInodeLocation
  826.         mov     ebx, [ebp+EXTFS.tempBlockBuffer]
  827.         mov     ecx, eax
  828.         call    fs_read32_sys
  829.         test    eax, eax
  830.         jnz     @f
  831.         mov     eax, ecx
  832.         movzx   ecx, [ebp+EXTFS.superblock.inodeSize]
  833.         mov     edi, edx
  834.         add     edi, ebx
  835.         mov     esi, [esp]
  836.         rep movsb
  837.         call    fs_write32_sys
  838. .ret:
  839.         pop     ebx ecx esi edi edx
  840.         ret
  841.  
  842. @@:
  843.         movi    eax, ERROR_DEVICE
  844.         stc
  845.         jmp     .ret
  846.  
  847. readInode:
  848. ; in: eax = inode number, ebx -> inode buffer
  849.         push    edx edi esi ecx ebx
  850.         mov     edi, ebx
  851.         call    getInodeLocation
  852.         mov     ebx, [ebp+EXTFS.tempBlockBuffer]
  853.         call    fs_read32_sys
  854.         test    eax, eax
  855.         jnz     @b
  856.         movzx   ecx, [ebp+EXTFS.superblock.inodeSize]
  857.         mov     esi, edx
  858.         add     esi, ebx
  859.         rep movsb
  860.         xor     eax, eax
  861.         pop     ebx ecx esi edi edx
  862.         ret
  863.  
  864. indirectBlockAlloc:
  865. ;   in:
  866. ; edi -> indirect block number
  867. ; ebx = starting extent block
  868. ; ecx = extent size
  869. ; edx = starting file block
  870.         mov     eax, [edi]
  871.         test    eax, eax
  872.         jz      .newBlock
  873.         push    edi ebx ecx
  874.         mov     ebx, [ebp+EXTFS.tempBlockBuffer]
  875.         call    extfsReadBlock
  876.         jc      .err2
  877.         lea     edi, [ebx+edx*4]
  878.         test    edx, edx
  879.         jz      @f
  880.         cmp     dword[edi-4], 0
  881.         jnz     @f
  882.         pop     ecx ebx edi
  883. .err:
  884.         mov     al, ERROR_FS_FAIL
  885.         stc
  886.         ret
  887.  
  888. .err2:
  889.         pop     ecx ebx edi
  890.         ret
  891.  
  892. .newBlock:
  893.         test    edx, edx
  894.         jnz     .err
  895.         mov     [edi], ebx
  896.         inc     ebx
  897.         dec     ecx
  898.         push    edi ebx ecx
  899.         mov     ecx, [ebp+EXTFS.dwordsPerBlock]
  900.         mov     edi, [ebp+EXTFS.tempBlockBuffer]
  901.         push    edi
  902.         rep stosd
  903.         pop     edi
  904. @@:
  905.         mov     ecx, [ebp+EXTFS.dwordsPerBlock]
  906.         sub     ecx, edx
  907.         pop     ebx eax
  908.         sub     ebx, ecx
  909.         jnc     @f
  910.         add     ecx, ebx
  911.         xor     ebx, ebx
  912. @@:
  913.         jecxz   .done
  914.         add     edx, ecx
  915. @@:
  916.         stosd
  917.         inc     eax
  918.         loop    @b
  919. .done:
  920.         pop     edi
  921.         push    eax ebx
  922.         mov     eax, [edi]
  923.         mov     ebx, [ebp+EXTFS.tempBlockBuffer]
  924.         call    extfsWriteBlock
  925.         pop     ecx ebx
  926.         ret
  927.  
  928. doublyIndirectBlockAlloc:
  929. ;   in:
  930. ; edi -> indirect block number
  931. ; edx = starting file block
  932. ; ebx = starting extent block
  933. ; ecx = extent size
  934. ; [esp+4] = rest of size
  935. ; [esp+8] = parent inode number
  936.         mov     eax, [edi]
  937.         test    eax, eax
  938.         jz      .newBlock
  939.         push    edi ecx ebx
  940.         mov     ebx, [ebp+EXTFS.mainBlockBuffer]
  941.         call    extfsReadBlock
  942.         jc      .err2
  943.         mov     eax, edx
  944.         xor     edx, edx
  945.         mov     ecx, [ebp+EXTFS.dwordsPerBlock]
  946.         div     ecx
  947.         lea     edi, [ebx+eax*4]
  948.         pop     ebx
  949.         test    eax, eax
  950.         jz      @f
  951.         cmp     dword[edi-4], 0
  952.         jnz     @f
  953.         pop     ecx edi
  954. .err:
  955.         mov     al, ERROR_FS_FAIL
  956.         stc
  957.         ret
  958.  
  959. .err2:
  960.         pop     ebx ecx edi
  961.         ret
  962.  
  963. .newBlock:
  964.         test    edx, edx
  965.         jnz     .err
  966.         mov     [edi], ebx
  967.         inc     ebx
  968.         dec     ecx
  969.         inc     dword[esp+4]
  970.         push    edi ecx
  971.         mov     ecx, [ebp+EXTFS.dwordsPerBlock]
  972.         mov     edi, [ebp+EXTFS.mainBlockBuffer]
  973.         push    ecx edi
  974.         rep stosd
  975.         pop     edi ecx
  976. @@:
  977.         sub     ecx, eax
  978.         xchg    [esp], ecx
  979. .loop:
  980.         cmp     dword[edi], 0
  981.         jnz     @f
  982.         inc     dword[esp+12]
  983. @@:
  984.         jecxz   .extentAlloc
  985.         call    indirectBlockAlloc
  986.         jc      .end
  987.         cmp     edx, [ebp+EXTFS.dwordsPerBlock]
  988.         jnz     @b
  989.         add     edi, 4
  990.         xor     edx, edx
  991.         dec     dword[esp]
  992.         jnz     .loop
  993. .end:
  994.         pop     edi edi
  995.         push    ebx eax
  996.         mov     eax, [edi]
  997.         mov     ebx, [ebp+EXTFS.mainBlockBuffer]
  998.         call    extfsWriteBlock
  999.         pop     ebx
  1000.         add     eax, ebx
  1001.         xor     ebx, ebx
  1002.         cmp     ebx, eax
  1003.         pop     ebx
  1004.         ret
  1005.  
  1006. .extentAlloc:
  1007.         mov     ecx, [esp+12]
  1008.         xor     eax, eax
  1009.         jecxz   .end
  1010.         mov     eax, [esp+16]
  1011.         call    extfsExtentAlloc
  1012.         jc      .end
  1013.         sub     [esp+12], ecx
  1014.         jmp     @b
  1015.  
  1016. extfsExtendFile:
  1017. ;   in:
  1018. ; [ebp+EXTFS.inodeBuffer] = inode
  1019. ; ecx = inode number
  1020. ; edx:eax = new size
  1021.         push    ebx esi edi ecx
  1022.         lea     esi, [ebp+EXTFS.inodeBuffer]
  1023.         mov     ebx, [esi+INODE.fileSize]
  1024.         mov     ecx, [esi+INODE.fileSizeHigh]
  1025.         cmp     ebx, eax
  1026.         sbb     ecx, edx
  1027.         jnc     .ret
  1028.         mov     ecx, [esi+INODE.fileSizeHigh]
  1029.         mov     [esi+INODE.fileSize], eax
  1030.         mov     [esi+INODE.fileSizeHigh], edx
  1031.         sub     eax, 1
  1032.         sbb     edx, 0
  1033.         div     [ebp+EXTFS.bytesPerBlock]
  1034.         inc     eax
  1035.         xchg    eax, ebx
  1036.         mov     edx, ecx
  1037.         sub     eax, 1
  1038.         sbb     edx, 0
  1039.         jc      @f
  1040.         div     [ebp+EXTFS.bytesPerBlock]
  1041. @@:
  1042.         inc     eax
  1043.         sub     ebx, eax
  1044.         jz      .ret
  1045.         push    ebx
  1046.         mov     edx, eax
  1047. @@:
  1048.         mov     ecx, [esp]
  1049.         mov     eax, [esp+4]
  1050.         test    ecx, ecx
  1051.         jz      .done
  1052.         call    extfsExtentAlloc
  1053.         jc      .errDone
  1054.         sub     [esp], ecx
  1055.         cmp     edx, 12
  1056.         jc      .directBlocks
  1057.         sub     edx, 12
  1058.         cmp     edx, [ebp+EXTFS.dwordsPerBlock]
  1059.         jc      .indirectBlocks
  1060.         sub     edx, [ebp+EXTFS.dwordsPerBlock]
  1061.         cmp     edx, [ebp+EXTFS.dwordsPerBranch]
  1062.         jc      .doublyIndirectBlock
  1063.         sub     edx, [ebp+EXTFS.dwordsPerBranch]
  1064.         jmp     .triplyIndirectBlock
  1065.  
  1066. .newExtent:
  1067.         jmp     @b
  1068.  
  1069. .directBlocks:
  1070.         lea     edi, [esi+INODE.blockNumbers+edx*4]
  1071.         test    edx, edx
  1072.         jz      @f
  1073.         cmp     dword[edi-4], 0
  1074.         jz      .errDone
  1075. @@:
  1076.         mov     eax, ebx
  1077.         mov     ebx, ecx
  1078.         mov     ecx, 12
  1079.         sub     ecx, edx
  1080.         sub     ebx, ecx
  1081.         jnc     @f
  1082.         add     ecx, ebx
  1083.         xor     ebx, ebx
  1084. @@:
  1085.         add     edx, ecx
  1086. @@:
  1087.         stosd
  1088.         inc     eax
  1089.         loop    @b
  1090.         mov     ecx, ebx
  1091.         mov     ebx, eax
  1092.         jecxz   .newExtent
  1093.         xor     edx, edx
  1094. .indirectBlocks:
  1095.         lea     edi, [esi+INODE.addressBlock]
  1096.         cmp     dword[edi], 0
  1097.         jnz     @f
  1098.         inc     dword[esp]
  1099. @@:
  1100.         call    indirectBlockAlloc
  1101.         jc      .errDone
  1102.         add     edx, 12
  1103.         jecxz   .newExtent
  1104.         xor     edx, edx
  1105. .doublyIndirectBlock:
  1106.         lea     edi, [esi+INODE.doubleAddress]
  1107.         call    doublyIndirectBlockAlloc
  1108.         jc      .errDone
  1109.         mov     edx, [ebp+EXTFS.dwordsPerBranch]
  1110.         add     edx, [ebp+EXTFS.dwordsPerBlock]
  1111.         add     edx, 12
  1112.         jecxz   .newExtent
  1113.         xor     edx, edx
  1114. .triplyIndirectBlock:
  1115.         push    ecx ebx edx
  1116.         stdcall kernel_alloc, [ebp+EXTFS.bytesPerBlock]
  1117.         pop     edx
  1118.         mov     esi, eax
  1119.         mov     eax, [ebp+EXTFS.inodeBuffer.tripleAddress]
  1120.         test    eax, eax
  1121.         jz      .newBlock
  1122.         mov     ebx, esi
  1123.         call    extfsReadBlock
  1124.         pop     ebx ecx
  1125.         jc      .errFree
  1126.         mov     eax, edx
  1127.         xor     edx, edx
  1128.         div     [ebp+EXTFS.dwordsPerBranch]
  1129.         lea     edi, [esi+eax*4]
  1130.         test    eax, eax
  1131.         jz      @f
  1132.         cmp     dword[edi-4], 0
  1133.         jnz     @f
  1134.         mov     al, ERROR_FS_FAIL
  1135. .errFree:
  1136.         push    ecx eax
  1137.         stdcall kernel_free, esi
  1138.         pop     eax ecx
  1139. .errDone:
  1140.         imul    ecx, [ebp+EXTFS.sectorsPerBlock]
  1141.         sub     [ebp+EXTFS.inodeBuffer.sectorsUsed], ecx
  1142.         pop     ebx
  1143.         imul    ebx, [ebp+EXTFS.sectorsPerBlock]
  1144.         add     ebx, ecx
  1145.         shl     ebx, 9
  1146.         sub     [ebp+EXTFS.inodeBuffer.fileSize], ebx
  1147.         stc
  1148.         jmp     .ret
  1149.  
  1150. .newBlock:
  1151.         pop     ebx ecx
  1152.         mov     al, ERROR_FS_FAIL
  1153.         test    edx, edx
  1154.         jnz     .errFree
  1155.         mov     [ebp+EXTFS.inodeBuffer.tripleAddress], ebx
  1156.         inc     ebx
  1157.         dec     ecx
  1158.         inc     dword[esp]
  1159.         push    ecx
  1160.         mov     ecx, [ebp+EXTFS.dwordsPerBlock]
  1161.         mov     edi, esi
  1162.         xor     eax, eax
  1163.         rep stosd
  1164.         mov     edi, esi
  1165.         pop     ecx
  1166. @@:
  1167.         jecxz   .extentAlloc
  1168.         call    doublyIndirectBlockAlloc
  1169.         jc      .errSave
  1170.         add     edi, 4
  1171.         jmp     @b
  1172.  
  1173. .extentAlloc:
  1174.         mov     ecx, [esp]
  1175.         mov     eax, [esp+4]
  1176.         jecxz   @f
  1177.         call    extfsExtentAlloc
  1178.         jc      .errSave
  1179.         sub     [esp], ecx
  1180.         jmp     @b
  1181.  
  1182. @@:
  1183.         mov     eax, [ebp+EXTFS.inodeBuffer.tripleAddress]
  1184.         mov     ebx, esi
  1185.         call    extfsWriteBlock
  1186.         stdcall kernel_free, esi
  1187. .done:
  1188.         xor     eax, eax
  1189.         pop     edi
  1190. .ret:
  1191.         pop     edi edi esi ebx
  1192.         ret
  1193.  
  1194. .errSave:
  1195.         push    eax
  1196.         mov     eax, [ebp+EXTFS.inodeBuffer.tripleAddress]
  1197.         mov     ebx, esi
  1198.         call    extfsWriteBlock
  1199.         pop     eax
  1200.         jmp     .errFree
  1201.  
  1202. freeBlockList:
  1203. ; in: edi -> list of blocks, edx = amount of blocks
  1204. ; out: ebx=0 -> end of list
  1205.         mov     ebx, [edi]
  1206.         test    ebx, ebx
  1207.         jz      .ret
  1208.         xor     eax, eax
  1209.         xor     ecx, ecx
  1210. @@:
  1211.         stosd
  1212.         inc     ecx
  1213.         dec     edx
  1214.         jz      @f
  1215.         mov     eax, [edi]
  1216.         sub     eax, ebx
  1217.         sub     eax, ecx
  1218.         jz      @b
  1219. @@:
  1220.         mov     eax, ebx
  1221.         call    extfsExtentFree
  1222.         test    edx, edx
  1223.         jnz     freeBlockList
  1224. .ret:
  1225.         ret
  1226.  
  1227. freeIndirectBlock:
  1228. ; in: edi -> indirect block number, edx = starting block
  1229. ; out: edi = edi+4, eax=0 -> end
  1230.         pushd   ecx 0 edi edx
  1231.         mov     eax, [edi]
  1232.         test    eax, eax
  1233.         jz      .ret
  1234.         mov     ebx, [ebp+EXTFS.mainBlockBuffer]
  1235.         call    extfsReadBlock
  1236.         jc      .ret
  1237.         lea     edi, [ebx+edx*4]
  1238.         neg     edx
  1239.         add     edx, [ebp+EXTFS.dwordsPerBlock]
  1240.         call    freeBlockList
  1241.         test    ebx, ebx
  1242.         jz      @f
  1243.         inc     dword[esp+8]
  1244. @@:
  1245.         pop     edx edi
  1246.         mov     eax, [edi]
  1247.         test    edx, edx
  1248.         jnz     @f
  1249.         xor     ecx, ecx
  1250.         inc     ecx
  1251.         call    extfsExtentFree
  1252.         stosd
  1253.         jmp     .done
  1254.  
  1255. @@:
  1256.         mov     ebx, [ebp+EXTFS.mainBlockBuffer]
  1257.         call    extfsWriteBlock
  1258.         add     edi, 4
  1259. .done:
  1260.         pop     eax ecx
  1261.         xor     edx, edx
  1262.         ret
  1263.  
  1264. .ret:
  1265.         pop     edi edi edx ecx
  1266.         ret
  1267.  
  1268. freeDoublyIndirectBlock:
  1269. ; in: edi -> doubly-indirect block number, edx = starting block
  1270. ; out: edi = edi+4, eax=-1 -> done, eax=0 -> end
  1271.         mov     eax, [edi]
  1272.         test    eax, eax
  1273.         jz      .ret
  1274.         push    ecx eax edx
  1275.         stdcall kernel_alloc, [ebp+EXTFS.bytesPerBlock]
  1276.         mov     ebx, eax
  1277.         pop     edx eax
  1278.         pushd   0 ebx edx
  1279.         call    extfsReadBlock
  1280.         jc      .err
  1281.         mov     eax, edx
  1282.         xor     edx, edx
  1283.         mov     ecx, [ebp+EXTFS.dwordsPerBlock]
  1284.         div     ecx
  1285.         sub     ecx, eax
  1286.         push    edi
  1287.         lea     edi, [ebx+eax*4]
  1288. @@:
  1289.         call    freeIndirectBlock
  1290.         test    eax, eax
  1291.         jz      .end
  1292.         dec     ecx
  1293.         jnz     @b
  1294.         dec     dword[esp+12]
  1295. .end:
  1296.         pop     edi edx
  1297.         mov     eax, [edi]
  1298.         test    edx, edx
  1299.         jnz     @f
  1300.         xor     ecx, ecx
  1301.         inc     ecx
  1302.         call    extfsExtentFree
  1303.         stosd
  1304.         jmp     .done
  1305.  
  1306. @@:
  1307.         mov     ebx, [esp]
  1308.         call    extfsWriteBlock
  1309.         add     edi, 4
  1310.         jmp     .done
  1311.  
  1312. .err:
  1313.         mov     [esp+8], eax
  1314.         pop     eax
  1315. .done:
  1316.         call    kernel_free
  1317.         pop     eax ecx
  1318. .ret:
  1319.         xor     edx, edx
  1320.         ret
  1321.  
  1322. extfsTruncateFile:
  1323. ; in: edx:eax = new size, [ebp+EXTFS.inodeBuffer] = inode
  1324.         lea     esi, [ebp+EXTFS.inodeBuffer]
  1325.         mov     ecx, edx
  1326.         cmp     eax, [esi+INODE.fileSize]
  1327.         sbb     ecx, [esi+INODE.fileSizeHigh]
  1328.         jnc     .ret
  1329.         mov     [esi+INODE.fileSize], eax
  1330.         mov     [esi+INODE.fileSizeHigh], edx
  1331.         sub     eax, 1
  1332.         sbb     edx, 0
  1333.         jc      @f
  1334.         div     [ebp+EXTFS.bytesPerBlock]
  1335. @@:
  1336.         inc     eax
  1337.         mov     edx, eax
  1338.         cmp     edx, 12
  1339.         jc      .directBlocks
  1340.         sub     edx, 12
  1341.         cmp     edx, [ebp+EXTFS.dwordsPerBlock]
  1342.         jc      .indirectBlocks
  1343.         sub     edx, [ebp+EXTFS.dwordsPerBlock]
  1344.         cmp     edx, [ebp+EXTFS.dwordsPerBranch]
  1345.         jc      .doublyIndirectBlock
  1346.         sub     edx, [ebp+EXTFS.dwordsPerBranch]
  1347.         jmp     .triplyIndirectBlock
  1348.  
  1349. .directBlocks:
  1350.         lea     edi, [esi+INODE.blockNumbers+edx*4]
  1351.         neg     edx
  1352.         add     edx, 12
  1353.         call    freeBlockList
  1354.         test    ebx, ebx
  1355.         jz      .ret
  1356. .indirectBlocks:
  1357.         lea     edi, [esi+INODE.addressBlock]
  1358.         call    freeIndirectBlock
  1359.         test    eax, eax
  1360.         jz      .ret
  1361. .doublyIndirectBlock:
  1362.         lea     edi, [esi+INODE.doubleAddress]
  1363.         call    freeDoublyIndirectBlock
  1364.         test    eax, eax
  1365.         jz      .ret
  1366. .triplyIndirectBlock:
  1367.         mov     eax, [esi+INODE.tripleAddress]
  1368.         test    eax, eax
  1369.         jz      .ret
  1370.         push    eax edx
  1371.         stdcall kernel_alloc, [ebp+EXTFS.bytesPerBlock]
  1372.         mov     ebx, eax
  1373.         pop     edx eax
  1374.         push    ebx eax edx
  1375.         call    extfsReadBlock
  1376.         jc      .err
  1377.         mov     eax, edx
  1378.         xor     edx, edx
  1379.         div     [ebp+EXTFS.dwordsPerBranch]
  1380.         mov     ecx, [ebp+EXTFS.dwordsPerBlock]
  1381.         sub     ecx, eax
  1382.         lea     edi, [ebx+eax*4]
  1383. @@:
  1384.         call    freeDoublyIndirectBlock
  1385.         test    eax, eax
  1386.         jz      .end
  1387.         dec     ecx
  1388.         jnz     @b
  1389. .end:
  1390.         pop     edx eax
  1391.         test    edx, edx
  1392.         jnz     @f
  1393.         xor     ecx, ecx
  1394.         inc     ecx
  1395.         call    extfsExtentFree
  1396.         mov     [esi+INODE.tripleAddress], eax
  1397.         jmp     .done
  1398.  
  1399. @@:
  1400.         mov     ebx, [esp]
  1401.         call    extfsWriteBlock
  1402.         jmp     .done
  1403.  
  1404. .err:
  1405.         pop     eax eax
  1406. .done:
  1407.         call    kernel_free
  1408. .ret:
  1409.         ret
  1410.  
  1411. linkInode:
  1412. ;   in:
  1413. ; eax = inode on which to link
  1414. ; ebx = inode to link
  1415. ; esi -> name in UTF-8
  1416. ;  dl = file type
  1417.         push    esi edi ebx ecx eax edx
  1418.         call    strlen
  1419.         push    esi ebx ecx
  1420.         lea     esi, [ebp+EXTFS.inodeBuffer]
  1421.         mov     ebx, esi
  1422.         call    readInode
  1423.         jc      .error_inode_read
  1424.         mov     eax, [esi+INODE.fileSize]
  1425.         xor     edx, edx
  1426.         div     [ebp+EXTFS.bytesPerBlock]
  1427.         xor     ecx, ecx
  1428. .searchBlock:
  1429.         push    eax     ; blocks total
  1430.         push    ecx     ; current file block number
  1431.         cmp     eax, ecx
  1432.         jz      .alloc_block
  1433.         call    extfsGetExtent
  1434.         jc      .error_get_inode_block
  1435.         push    eax
  1436.         mov     ebx, [ebp+EXTFS.tempBlockBuffer]
  1437.         call    extfsReadBlock
  1438.         jc      .error_block_read
  1439.         mov     ecx, [esp+12]
  1440.         add     ecx, 8  ; directory entry size
  1441.         mov     edi, [ebp+EXTFS.tempBlockBuffer]
  1442.         mov     edx, edi
  1443.         add     edx, [ebp+EXTFS.bytesPerBlock]
  1444. .searchSpace:
  1445.         movzx   eax, [edi+DIRENTRY.entryLength]
  1446.         test    eax, eax
  1447.         jz      .zeroLength
  1448.         cmp     [edi+DIRENTRY.inodeNumber], 0
  1449.         je      .unusedEntry
  1450.         movzx   ebx, [edi+DIRENTRY.nameLength]
  1451.         add     ebx, 8+3
  1452.         and     ebx, -4
  1453.         sub     eax, ebx
  1454.         add     edi, ebx
  1455.         cmp     eax, ecx
  1456.         jb      .nextEntry
  1457.         sub     edi, ebx
  1458.         mov     [edi+DIRENTRY.entryLength], bx
  1459.         add     edi, ebx
  1460.         mov     [edi+DIRENTRY.entryLength], ax
  1461.         jmp     .found
  1462.  
  1463. .unusedEntry:
  1464.         cmp     eax, ecx
  1465.         jge     .found
  1466. .nextEntry:
  1467.         add     edi, eax
  1468.         cmp     edi, edx
  1469.         jb      .searchSpace
  1470.         pop     ecx
  1471. @@:
  1472.         pop     ecx eax
  1473.         inc     ecx
  1474.         jmp     .searchBlock
  1475.  
  1476. .zeroLength:
  1477.         mov     eax, edx
  1478.         sub     eax, edi
  1479.         mov     [edi+DIRENTRY.entryLength], ax
  1480.         cmp     eax, ecx
  1481.         jge     .found
  1482.         mov     [edi+DIRENTRY.inodeNumber], 0
  1483.         pop     eax
  1484.         mov     ebx, [ebp+EXTFS.tempBlockBuffer]
  1485.         call    extfsWriteBlock
  1486.         jmp     @b
  1487.  
  1488. .alloc_block:
  1489.         mov     eax, [esi+INODE.fileSize]
  1490.         add     eax, [ebp+EXTFS.bytesPerBlock]
  1491.         xor     edx, edx
  1492.         mov     ecx, [esp+24]
  1493.         call    extfsExtendFile
  1494.         jc      .error_get_inode_block
  1495.         mov     eax, [esp+24]
  1496.         mov     ebx, esi
  1497.         call    writeInode
  1498.         jc      .error_get_inode_block
  1499.         mov     ecx, [esp]
  1500.         call    extfsGetExtent
  1501.         jc      .error_get_inode_block
  1502.         push    eax
  1503.         mov     edi, [ebp+EXTFS.tempBlockBuffer]
  1504.         mov     eax, [ebp+EXTFS.bytesPerBlock]
  1505.         mov     [edi+DIRENTRY.entryLength], ax
  1506. .found:
  1507.         pop     edx ecx ecx ecx ebx esi
  1508.         mov     [edi+DIRENTRY.inodeNumber], ebx
  1509.         mov     word [edi+DIRENTRY.nameLength], cx
  1510.         sub     eax, 8
  1511.         cmp     ecx, eax
  1512.         adc     ecx, 0
  1513.         test    [ebp+EXTFS.superblock.incompatibleFlags], 2
  1514.         jz      @f
  1515.         mov     eax, [esp]
  1516.         mov     [edi+DIRENTRY.fileType], al
  1517. @@:
  1518.         add     edi, 8
  1519.         rep movsb
  1520.         mov     eax, edx
  1521.         mov     ebx, [ebp+EXTFS.tempBlockBuffer]
  1522.         call    extfsWriteBlock
  1523. @@:
  1524.         pop     edx ecx ecx ebx edi esi
  1525.         ret
  1526.  
  1527. .error_block_read:
  1528.         pop     ebx
  1529. .error_get_inode_block:
  1530.         pop     ebx ebx
  1531. .error_inode_read:
  1532.         pop     ebx ebx ebx
  1533.         jmp     @b
  1534.  
  1535. unlinkInode:
  1536. ; in: eax = directory inode number, esi = inode to unlink
  1537.         push    edi
  1538.         lea     ebx, [ebp+EXTFS.inodeBuffer]
  1539.         call    readInode
  1540.         jc      .ret
  1541.         xor     ecx, ecx
  1542. .loop:
  1543.         push    ecx
  1544.         call    extfsGetExtent
  1545.         jc      .fail_loop
  1546.         mov     edi, eax
  1547.         mov     ebx, [ebp+EXTFS.tempBlockBuffer]
  1548.         call    extfsReadBlock
  1549.         jc      .fail_loop
  1550. .first_dir_entry:   ; edi -> block
  1551.         cmp     [ebx+DIRENTRY.inodeNumber], esi
  1552.         jne     @f
  1553.         mov     [ebx+DIRENTRY.inodeNumber], 0
  1554.         mov     word [ebx+DIRENTRY.nameLength], 0   ; fileType = 0
  1555.         jmp     .write_block
  1556.  
  1557. .fail:
  1558.         pop     edi
  1559.         movi    eax, ERROR_FS_FAIL
  1560.         stc
  1561. .fail_loop:
  1562.         pop     edi
  1563.         jmp     .ret
  1564.  
  1565. .next:
  1566.         pop     ecx ecx
  1567.         inc     ecx
  1568.         jmp     .loop
  1569.  
  1570. @@:
  1571.         mov     edx, ebx
  1572.         add     edx, [ebp+EXTFS.bytesPerBlock]
  1573.         push    edx
  1574. @@:
  1575.         movzx   ecx, [ebx+DIRENTRY.entryLength]
  1576.         jecxz   .fail
  1577.         mov     edx, ebx
  1578.         add     ebx, ecx
  1579.         cmp     ebx, [esp]
  1580.         jnc     .next
  1581.         cmp     [ebx+DIRENTRY.inodeNumber], esi
  1582.         jnz     @b
  1583.         mov     cx, [ebx+DIRENTRY.entryLength]
  1584.         add     [edx+DIRENTRY.entryLength], cx
  1585.         pop     eax
  1586. .write_block:
  1587.         pop     eax
  1588.         mov     eax, edi
  1589.         mov     ebx, [ebp+EXTFS.tempBlockBuffer]
  1590.         call    extfsWriteBlock
  1591. .ret:
  1592.         pop     edi
  1593.         ret
  1594.  
  1595. findInode:
  1596. ; in: esi -> path string in UTF-8
  1597. ;   out:
  1598. ; edi -> file name in UTF-8
  1599. ; esi = last inode number
  1600. ; [ebp+EXTFS.inodeBuffer] = last inode
  1601. ; ecx = parent inode number
  1602. ; CF=1 -> file not found, edi=0 -> error
  1603.         push    esi
  1604.         lea     esi, [ebp+EXTFS.rootInodeBuffer]
  1605.         lea     edi, [ebp+EXTFS.inodeBuffer]
  1606.         movzx   ecx, [ebp+EXTFS.superblock.inodeSize]
  1607.         mov     edx, esi
  1608.         rep movsb
  1609.         pop     esi
  1610.         pushd   ebx 0 ROOT_INODE
  1611.         mov     edi, esi
  1612.         cmp     [edx+INODE.fileSize], 0
  1613.         jz      .not_found
  1614.         cmp     byte [esi], 0
  1615.         jnz     .next_path_part
  1616.         xor     eax, eax
  1617.         pop     esi ecx ebx
  1618.         ret
  1619.  
  1620. @@:
  1621.         pop     esi esi
  1622. .error:
  1623.         pop     esi ecx ebx
  1624.         xor     edi, edi
  1625.         stc
  1626.         ret
  1627.  
  1628. .next_path_part:
  1629.         push    [edx+INODE.fileSize]
  1630.         xor     ecx, ecx
  1631. .folder_block_cycle:
  1632.         push    ecx
  1633.         call    extfsGetExtent
  1634.         jc      @b
  1635.         mov     ebx, [ebp+EXTFS.mainBlockBuffer]
  1636.         call    extfsReadBlock
  1637.         jc      @b
  1638.         push    esi edx
  1639.         mov     edx, ebx
  1640.         add     edx, [ebp+EXTFS.bytesPerBlock]
  1641. .start_rec:
  1642.         cmp     [ebx+DIRENTRY.inodeNumber], 0
  1643.         jz      .next_rec
  1644.         push    esi
  1645.         movzx   ecx, [ebx+DIRENTRY.nameLength]
  1646.         lea     edi, [ebx+DIRENTRY.name]
  1647.         repz cmpsb
  1648.         jz      .test_find
  1649. @@: ; doesn't match
  1650.         pop     esi
  1651. .next_rec:
  1652.         movzx   ecx, [ebx+DIRENTRY.entryLength]
  1653.         jecxz   .stop
  1654.         add     ebx, ecx
  1655.         cmp     ebx, edx
  1656.         jb      .start_rec
  1657.         jmp     .stop
  1658.  
  1659. .test_find:
  1660.         cmp     byte [esi], 0
  1661.         je      @f
  1662.         cmp     byte [esi], '/'
  1663.         jne     @b
  1664.         inc     esi
  1665. @@:
  1666.         pop     edx
  1667. .stop:
  1668.         pop     edx edi ecx eax
  1669. ; ebx -> matched directory entry, esi -> name without parent, or not changed
  1670.         cmp     edi, esi
  1671.         jnz     @f
  1672.         sub     eax, [ebp+EXTFS.bytesPerBlock]
  1673.         jle     .not_found
  1674.         push    eax
  1675.         inc     ecx
  1676.         jmp     .folder_block_cycle
  1677.  
  1678. @@:
  1679.         pop     eax
  1680.         mov     [esp], eax
  1681.         mov     eax, [ebx+DIRENTRY.inodeNumber]
  1682.         lea     ebx, [ebp+EXTFS.inodeBuffer]
  1683.         push    eax
  1684.         call    readInode
  1685.         jc      .error
  1686.         cmp     byte [esi], 0
  1687.         je      .ret
  1688.         mov     edx, ebx
  1689.         movzx   eax, [ebx+INODE.accessMode]
  1690.         and     eax, TYPE_MASK
  1691.         cmp     eax, DIRECTORY
  1692.         jz      .next_path_part
  1693.         xor     edi, edi    ; path folder is a file
  1694.         jmp     @f
  1695.  
  1696. .not_found:
  1697.         mov     esi, edi
  1698.         call    strlen
  1699.         mov     al, '/'
  1700.         repnz scasb
  1701.         mov     edi, esi
  1702.         jnz     @f
  1703.         xor     edi, edi    ; path folder not found
  1704. @@:
  1705.         movi    eax, ERROR_FILE_NOT_FOUND
  1706.         stc
  1707. .ret:
  1708.         pop     esi ecx ebx
  1709.         ret
  1710.  
  1711. writeSuperblock:
  1712.         push    ebx
  1713.         mov     eax, 2
  1714.         lea     ebx, [ebp+EXTFS.superblock]
  1715.         call    fs_write32_sys
  1716.         pop     ebx
  1717.         ret
  1718.  
  1719. extfsWritingInit:
  1720.         movi    eax, ERROR_UNSUPPORTED_FS
  1721.         test    [ebp+EXTFS.mountType], READ_ONLY
  1722.         jnz     @f
  1723. ext_lock:
  1724.         lea     ecx, [ebp+EXTFS.Lock]
  1725.         jmp     mutex_lock
  1726.  
  1727. @@:
  1728.         pop     ebx
  1729.         xor     ebx, ebx
  1730.         ret
  1731.  
  1732. ext_unlock:
  1733.         lea     ecx, [ebp+EXTFS.Lock]
  1734.         jmp     mutex_unlock
  1735.  
  1736. ;----------------------------------------------------------------
  1737. ext_ReadFolder:
  1738.         call    ext_lock
  1739.         cmp     byte [esi], 0
  1740.         jz      .root_folder
  1741.         call    findInode
  1742.         jc      .error_ret
  1743.         lea     esi, [ebp+EXTFS.inodeBuffer]
  1744.         test    [esi+INODE.accessMode], FLAG_FILE
  1745.         jnz     .error_not_found
  1746.         jmp     @f
  1747.  
  1748. .root_folder:
  1749.         lea     esi, [ebp+EXTFS.rootInodeBuffer]
  1750.         lea     edi, [ebp+EXTFS.inodeBuffer]
  1751.         movzx   ecx, [ebp+EXTFS.superblock.inodeSize]
  1752.         shr     ecx, 2
  1753.         push    edi
  1754.         rep movsd
  1755.         pop     esi
  1756. @@:
  1757.         cmp     [esi+INODE.fileSize], 0
  1758.         je      .error_empty_dir
  1759.         mov     edx, [ebx+16]
  1760.         push    edx         ; [edi+28] result buffer
  1761.         push    0           ; [edi+24] end of the current block in folder
  1762.         pushd   [ebx+12]    ; [edi+20] files to read
  1763.         pushd   [ebx+4]     ; [edi+16] first wanted file
  1764.         pushd   [ebx+8]     ; [edi+12] flags
  1765.         push    0           ; [edi+8]  read files
  1766.         push    0           ; [edi+4]  files in folder
  1767.         push    0           ; [edi]    current block index
  1768.         mov     edi, esp    ; edi -> local variables
  1769.         add     edx, 32
  1770.         xor     ecx, ecx
  1771.         call    extfsGetExtent
  1772.         jc      .error_get_block
  1773.         mov     ebx, [ebp+EXTFS.mainBlockBuffer]
  1774.         call    extfsReadBlock
  1775.         jc      .error_get_block
  1776.         mov     eax, ebx
  1777.         add     eax, [ebp+EXTFS.bytesPerBlock]
  1778.         mov     [edi+24], eax
  1779.         mov     ecx, [edi+16]
  1780. .find_wanted_start:
  1781.         jecxz   .find_wanted_end
  1782. .find_wanted_cycle:
  1783.         cmp     [ebx+DIRENTRY.inodeNumber], 0
  1784.         jz      @f
  1785.         inc     dword [edi+4]
  1786.         dec     ecx
  1787. @@:
  1788.         movzx   eax, [ebx+DIRENTRY.entryLength]
  1789.         cmp     eax, 12     ; minimum entry length
  1790.         jb      .error_bad_len
  1791.         test    eax, 3      ; length must be aligned
  1792.         jnz     .error_bad_len
  1793.         sub     [esi+INODE.fileSize], eax
  1794.         add     ebx, eax
  1795.         cmp     ebx, [edi+24]
  1796.         jb      .find_wanted_start
  1797.         push    .find_wanted_start
  1798. .end_block: ; read next block
  1799.         cmp     [esi+INODE.fileSize], 0
  1800.         jle     .end_dir
  1801.         inc     dword [edi]
  1802.         push    ecx
  1803.         mov     ecx, [edi]
  1804.         call    extfsGetExtent
  1805.         jc      .error_get_block
  1806.         mov     ebx, [ebp+EXTFS.mainBlockBuffer]
  1807.         call    extfsReadBlock
  1808.         jc      .error_get_block
  1809.         pop     ecx
  1810.         mov     eax, ebx
  1811.         add     eax, [ebp+EXTFS.bytesPerBlock]
  1812.         mov     [edi+24], eax
  1813.         ret
  1814.  
  1815. .wanted_end:
  1816.         loop    .find_wanted_cycle
  1817. .find_wanted_end:
  1818.         mov     ecx, [edi+20]
  1819. .wanted_start:
  1820.         jecxz   .wanted_end
  1821.         cmp     [ebx+DIRENTRY.inodeNumber], 0
  1822.         jz      .empty_rec
  1823.         inc     dword [edi+8]
  1824.         inc     dword [edi+4]
  1825.         push    ebx edi ecx esi edx edi
  1826.         pushd   [edi+12]
  1827.         mov     edi, edx
  1828.         xor     eax, eax
  1829.         mov     ecx, 40 / 4
  1830.         rep stosd
  1831.         popd    [edx+4] edi
  1832.         mov     eax, [ebx+DIRENTRY.inodeNumber]
  1833.         mov     ebx, [ebp+EXTFS.tempBlockBuffer]
  1834.         call    readInode
  1835.         jc      .error_read_subinode
  1836.         mov     esi, ebx
  1837.         lea     edi, [edx+8]
  1838.         mov     eax, [ebx+INODE.inodeModified]
  1839.         sub     eax, 978307200  ; 01.01.1970-01.01.2001 = (365*31+8)*24*60*60
  1840.         call    fsTime2bdfe
  1841.  
  1842.         mov     eax, [esi+INODE.accessedTime]
  1843.         sub     eax, 978307200
  1844.         call    fsTime2bdfe
  1845.  
  1846.         mov     eax, [esi+INODE.dataModified]
  1847.         sub     eax, 978307200
  1848.         call    fsTime2bdfe
  1849.         pop     edx
  1850.         or      dword [edx], KOS_DIRECTORY
  1851.         test    [esi+INODE.accessMode], FLAG_FILE
  1852.         jz      @f
  1853.         xor     dword [edx], KOS_DIRECTORY  ; mark as file
  1854.         mov     eax, [esi+INODE.fileSize]
  1855.         stosd
  1856.         mov     eax, [esi+INODE.fileSizeHigh]
  1857.         stosd
  1858. @@:
  1859.         mov     esi, [esp+12]
  1860.         movzx   ecx, [esi+DIRENTRY.nameLength]
  1861.         lea     esi, [esi+DIRENTRY.name]
  1862.         cmp     byte [esi], '.'
  1863.         jnz     @f
  1864.         or      byte [edx], KOS_HIDDEN
  1865. @@:
  1866.         lea     edi, [edx+40]
  1867.         cmp     byte [edx+4], 3
  1868.         jz      .utf8
  1869.         add     ecx, esi
  1870.         cmp     byte [edx+4], 2
  1871.         jz      .utf16
  1872. @@:
  1873.         call    utf8to16
  1874.         call    uni2ansi_char
  1875.         stosb
  1876.         cmp     esi, ecx
  1877.         jc      @b
  1878.         and     byte [edi], 0
  1879.         add     edx, 40+264
  1880. @@:
  1881.         pop     esi ecx edi ebx
  1882.         dec     ecx
  1883. .empty_rec:
  1884.         movzx   eax, [ebx+DIRENTRY.entryLength]
  1885.         cmp     eax, 12
  1886.         jb      .error_bad_len
  1887.         test    eax, 3
  1888.         jnz     .error_bad_len
  1889.         sub     [esi+INODE.fileSize], eax
  1890.         add     ebx, eax
  1891.         cmp     ebx, [edi+24]
  1892.         jb      .wanted_start
  1893.         push    .wanted_start
  1894.         jmp     .end_block
  1895.  
  1896. .utf8:
  1897.         rep movsb
  1898.         mov     byte [edi], 0
  1899.         add     edx, 40+520
  1900.         jmp     @b
  1901.  
  1902. .utf16:
  1903.         call    utf8to16
  1904.         stosw
  1905.         cmp     esi, ecx
  1906.         jc      .utf16
  1907.         and     word [edi], 0
  1908.         add     edx, 40+520
  1909.         jmp     @b
  1910.  
  1911. .end_dir:
  1912.         call    ext_unlock
  1913.         mov     edx, [edi+28]
  1914.         mov     ebx, [edi+8]
  1915.         mov     ecx, [edi+4]
  1916.         mov     dword [edx], 1  ; version
  1917.         mov     [edx+4], ebx
  1918.         mov     [edx+8], ecx
  1919.         lea     esp, [edi+32]
  1920.         mov     ecx, 20/4
  1921.         lea     edi, [edx+12]
  1922.         xor     eax, eax
  1923.         rep stosd
  1924.         ret
  1925.  
  1926. .error_bad_len:
  1927.         movi    eax, ERROR_FS_FAIL
  1928. .error_read_subinode:
  1929. .error_get_block:
  1930.         lea     esp, [edi+32]
  1931. .error_ret:
  1932.         xor     ebx, ebx
  1933.         push    eax
  1934.         call    ext_unlock
  1935.         pop     eax
  1936.         ret
  1937.  
  1938. .error_empty_dir:
  1939.         movi    eax, ERROR_FS_FAIL
  1940.         jmp     .error_ret
  1941.  
  1942. .error_not_found:
  1943.         movi    eax, ERROR_FILE_NOT_FOUND
  1944.         jmp     .error_ret
  1945.  
  1946. ;----------------------------------------------------------------
  1947. ext_ReadFile:
  1948.         call    ext_lock
  1949.         call    findInode
  1950.         pushd   0 eax
  1951.         jc      .ret
  1952.         lea     esi, [ebp+EXTFS.inodeBuffer]
  1953.         mov     byte [esp], ERROR_ACCESS_DENIED
  1954.         test    [esi+INODE.accessMode], FLAG_FILE
  1955.         jz      .ret    ; not a file
  1956.         mov     byte [esp], ERROR_END_OF_FILE
  1957.         mov     eax, [esi+INODE.fileSize]
  1958.         mov     edx, [esi+INODE.fileSizeHigh]
  1959.         sub     eax, [ebx+4]
  1960.         sbb     edx, [ebx+8]
  1961.         jc      .ret
  1962.         mov     ecx, [ebx+12]
  1963.         sub     eax, ecx
  1964.         sbb     edx, 0
  1965.         jc      @f
  1966.         xor     eax, eax
  1967.         mov     [esp], eax
  1968. @@:
  1969.         add     ecx, eax
  1970.         mov     eax, [ebx+4]
  1971.         mov     edx, [ebx+8]
  1972.         mov     edi, [ebx+16]
  1973.         div     [ebp+EXTFS.bytesPerBlock]
  1974.         test    edx, edx
  1975.         jz      .aligned
  1976. .piece:
  1977.         push    eax ecx
  1978.         mov     esi, edx
  1979.         mov     ecx, eax
  1980.         call    extfsGetExtent
  1981.         jc      .errorGet
  1982.         mov     ecx, [ebp+EXTFS.sectorsPerBlock]
  1983.         mul     ecx
  1984.         mov     ebx, [ebp+EXTFS.mainBlockBuffer]
  1985.         call    fs_read64_sys
  1986.         test    eax, eax
  1987.         jnz     .errorRead
  1988.         pop     eax
  1989.         mov     ecx, [ebp+EXTFS.bytesPerBlock]
  1990.         sub     ecx, esi
  1991.         sub     eax, ecx
  1992.         jnc     @f
  1993.         add     ecx, eax
  1994.         xor     eax, eax
  1995. @@:
  1996.         add     esi, ebx
  1997.         add     [esp+8], ecx
  1998.         rep movsb
  1999.         mov     ecx, eax
  2000.         pop     eax
  2001.         inc     eax
  2002.         xor     edx, edx
  2003.         jecxz   .ret
  2004. .aligned:
  2005.         xchg    eax, ecx
  2006.         div     [ebp+EXTFS.bytesPerBlock]
  2007.         push    edx
  2008.         mov     edx, eax
  2009. .writeExtent:
  2010.         test    edx, edx
  2011.         jz      .end
  2012.         push    ecx
  2013.         call    extfsGetExtent
  2014.         jc      .errorGet
  2015.         sub     edx, ecx
  2016.         jnc     @f
  2017.         add     ecx, edx
  2018.         xor     edx, edx
  2019. @@:
  2020.         add     [esp], ecx
  2021.         imul    ecx, [ebp+EXTFS.sectorsPerBlock]
  2022.         mov     ebx, edi
  2023.         push    edx ecx
  2024.         mul     [ebp+EXTFS.sectorsPerBlock]
  2025.         call    fs_read64_sys
  2026.         pop     ecx edx
  2027.         test    eax, eax
  2028.         jnz     .errorRead
  2029.         shl     ecx, 9
  2030.         add     edi, ecx
  2031.         add     [esp+12], ecx
  2032.         pop     ecx
  2033.         jmp     .writeExtent
  2034.  
  2035. .end:
  2036.         mov     eax, ecx
  2037.         pop     ecx
  2038.         jecxz   .ret
  2039.         jmp     .piece
  2040.  
  2041. .errorRead:
  2042.         movi    eax, ERROR_DEVICE
  2043. .errorGet:
  2044.         pop     ebx ebx
  2045.         mov     [esp], eax
  2046. .ret:
  2047.         call    ext_unlock
  2048.         pop     eax ebx
  2049.         ret
  2050.  
  2051. ;----------------------------------------------------------------
  2052. ext_GetFileInfo:
  2053.         cmp     byte [esi], 0
  2054.         jz      .volume
  2055.         call    ext_lock
  2056.         call    findInode
  2057.         jc      .ret
  2058.         lea     esi, [ebp+EXTFS.inodeBuffer]
  2059.         mov     edx, [ebx+16]
  2060.         mov     bl, [edi]
  2061.         xor     eax, eax
  2062.         mov     edi, edx
  2063.         mov     ecx, 40/4
  2064.         rep stosd
  2065.         cmp     bl, '.'
  2066.         jne     @f
  2067.         or      dword [edx], KOS_HIDDEN
  2068. @@:
  2069.         or      dword [edx], KOS_DIRECTORY
  2070.         test    [esi+INODE.accessMode], FLAG_FILE
  2071.         jz      @f
  2072.         xor     dword [edx], KOS_DIRECTORY  ; mark as file
  2073.         mov     eax, [esi+INODE.fileSize]
  2074.         mov     ebx, [esi+INODE.fileSizeHigh]
  2075.         mov     dword [edx+32], eax
  2076.         mov     dword [edx+36], ebx
  2077. @@:
  2078.         lea     edi, [edx+8]
  2079.         mov     eax, [esi+INODE.inodeModified]
  2080.         sub     eax, 978307200  ; 01.01.1970-01.01.2001 = (365*31+8)*24*60*60
  2081.         call    fsTime2bdfe
  2082.  
  2083.         mov     eax, [esi+INODE.accessedTime]
  2084.         sub     eax, 978307200
  2085.         call    fsTime2bdfe
  2086.  
  2087.         mov     eax, [esi+INODE.dataModified]
  2088.         sub     eax, 978307200
  2089.         call    fsTime2bdfe
  2090.         xor     eax, eax
  2091. .ret:
  2092.         push    eax
  2093.         call    ext_unlock
  2094.         pop     eax
  2095. @@:
  2096.         ret
  2097.  
  2098. .volume:
  2099.         mov     eax, dword[ebp+EXTFS.Length]
  2100.         mov     edx, dword[ebp+EXTFS.Length+4]
  2101.         mov     edi, [ebx+16]
  2102.         shld    edx, eax, 9
  2103.         shl     eax, 9
  2104.         mov     [edi+36], edx
  2105.         mov     [edi+32], eax
  2106.         mov     eax, [ebx+8]
  2107.         mov     byte [edi], 8
  2108.         mov     [edi+4], eax
  2109.         test    eax, eax
  2110.         jz      @b
  2111.         lea     esi, [ebp+EXTFS.superblock.volumeLabel]
  2112.         mov     ecx, 16
  2113.         add     edi, 40
  2114.         cmp     eax, 3
  2115.         jz      .utf8
  2116.         add     ecx, esi
  2117.         cmp     eax, 2
  2118.         jz      .utf16
  2119. @@:
  2120.         call    utf8to16
  2121.         call    uni2ansi_char
  2122.         stosb
  2123.         cmp     esi, ecx
  2124.         jc      @b
  2125.         jmp     @f
  2126.  
  2127. .utf8:
  2128.         rep movsb
  2129.         jmp     @f
  2130.  
  2131. .utf16:
  2132.         call    utf8to16
  2133.         stosw
  2134.         cmp     esi, ecx
  2135.         jc      .utf16
  2136. @@:
  2137.         xor     eax, eax
  2138.         mov     [edi], ax
  2139.         ret
  2140.  
  2141. ;----------------------------------------------------------------
  2142. ext_SetFileInfo:
  2143.         call    extfsWritingInit
  2144.         call    findInode
  2145.         jc      @f
  2146.         push    esi
  2147.         mov     esi, [ebx+16]
  2148.         add     esi, 16
  2149.         lea     edi, [ebp+EXTFS.inodeBuffer]
  2150.         call    fsCalculateTime
  2151.         add     eax, 978307200  ; 01.01.1970-01.01.2001 = (365*31+8)*24*60*60
  2152.         mov     [edi+INODE.accessedTime], eax
  2153.  
  2154.         add     esi, 8
  2155.         call    fsCalculateTime
  2156.         add     eax, 978307200
  2157.         mov     [edi+INODE.dataModified], eax
  2158.         mov     ebx, edi
  2159.         pop     eax
  2160.         call    writeInode
  2161. @@:
  2162.         push    eax
  2163.         jc      @f
  2164.         call    writeSuperblock
  2165.         mov     esi, [ebp+PARTITION.Disk]
  2166.         call    disk_sync
  2167. @@:
  2168.         call    ext_unlock
  2169.         pop     eax
  2170.         ret
  2171.  
  2172. ;----------------------------------------------------------------
  2173. ext_Delete:
  2174.         call    extfsWritingInit
  2175.         call    findInode
  2176.         jc      .error
  2177.         push    ecx
  2178.         movzx   edi, [ebp+EXTFS.inodeBuffer.accessMode]
  2179.         and     edi, TYPE_MASK
  2180.         cmp     edi, DIRECTORY
  2181.         jne     .file
  2182.         xor     ecx, ecx
  2183. .checkDirectory:
  2184.         push    ecx
  2185.         call    extfsGetExtent
  2186.         jc      .empty
  2187.         mov     ebx, [ebp+EXTFS.tempBlockBuffer]
  2188.         call    extfsReadBlock
  2189.         jc      .error8
  2190.         mov     edx, ebx
  2191.         add     edx, [ebp+EXTFS.bytesPerBlock]
  2192. .dir_entry:
  2193.         movzx   ecx, [ebx+DIRENTRY.nameLength]
  2194.         mov     ax, word [ebx+DIRENTRY.name]
  2195.         jecxz   @f
  2196.         cmp     al, '.'
  2197.         jnz     .not_empty
  2198.         dec     ecx
  2199.         jz      @f
  2200.         cmp     al, ah
  2201.         jnz     .not_empty
  2202.         dec     ecx
  2203.         jnz     .not_empty
  2204. @@:
  2205.         mov     cx, [ebx+DIRENTRY.entryLength]
  2206.         jecxz   @f
  2207.         add     ebx, ecx
  2208.         cmp     ebx, edx
  2209.         jb      .dir_entry
  2210. @@:
  2211.         pop     ecx
  2212.         inc     ecx
  2213.         jmp     .checkDirectory
  2214.  
  2215. .not_empty:
  2216.         pop     eax eax
  2217.         push    ERROR_ACCESS_DENIED
  2218.         jmp     .ret
  2219.  
  2220. .error8:
  2221.         pop     ebx
  2222. .error4:
  2223.         pop     ebx
  2224. .error:
  2225.         push    eax
  2226.         jmp     .ret
  2227.  
  2228. .empty:
  2229.         pop     ecx ecx
  2230.         cmp     eax, ERROR_END_OF_FILE
  2231.         jnz     .error
  2232.         push    ecx
  2233. .file:
  2234.         mov     eax, ecx
  2235.         call    unlinkInode
  2236.         jc      .error4
  2237.         pop     eax
  2238.         lea     ebx, [ebp+EXTFS.inodeBuffer]
  2239.         cmp     edi, DIRECTORY
  2240.         jnz     @f
  2241.         dec     [ebx+INODE.linksCount]
  2242.         call    writeInode
  2243. @@:
  2244.         mov     eax, esi
  2245.         call    readInode
  2246.         jc      .error
  2247.         dec     [ebx+INODE.linksCount]
  2248.         jz      @f
  2249.         cmp     edi, DIRECTORY
  2250.         jnz     .hardlinks
  2251. @@:
  2252.         push    esi edi
  2253.         xor     eax, eax
  2254.         xor     edx, edx
  2255.         call    extfsTruncateFile   ; free file's data
  2256.         movzx   ecx, [ebp+EXTFS.superblock.inodeSize]
  2257.         lea     edi, [ebp+EXTFS.inodeBuffer]
  2258.         xor     eax, eax
  2259.         push    edi
  2260.         rep stosb
  2261.         call    fsGetTime
  2262.         pop     ebx edi esi
  2263.         add     eax, 978307200
  2264.         mov     [ebx+INODE.deletedTime], eax
  2265.         mov     eax, esi
  2266.         dec     eax
  2267.         xor     edx, edx
  2268.         div     [ebp+EXTFS.superblock.inodesPerGroup]
  2269.         push    edx
  2270.         mov     ebx, [ebp+EXTFS.descriptorTable]
  2271.         shl     eax, 5
  2272.         add     ebx, eax
  2273.         cmp     edi, DIRECTORY
  2274.         jnz     @f
  2275.         dec     [ebx+BGDESCR.directoriesCount]
  2276. @@:
  2277.         inc     [ebx+BGDESCR.inodesFree]
  2278.         push    [ebx+BGDESCR.inodeBitmap]
  2279.         call    extfsWriteDescriptor
  2280.         pop     eax
  2281.         mov     ebx, [ebp+EXTFS.tempBlockBuffer]
  2282.         mov     ecx, eax
  2283.         call    extfsReadBlock
  2284.         pop     edx
  2285.         jc      .error
  2286.         mov     eax, edx
  2287.         and     edx, 31
  2288.         shr     eax, 5
  2289.         shl     eax, 2
  2290.         add     eax, ebx
  2291.         btr     [eax], edx
  2292.         mov     eax, ecx
  2293.         call    extfsWriteBlock
  2294.         inc     [ebp+EXTFS.superblock.inodesFree]
  2295. .hardlinks:
  2296.         mov     eax, esi
  2297.         lea     ebx, [ebp+EXTFS.inodeBuffer]
  2298.         call    writeInode
  2299.         push    eax
  2300.         call    writeSuperblock
  2301.         mov     esi, [ebp+PARTITION.Disk]
  2302.         call    disk_sync
  2303. .ret:
  2304.         call    ext_unlock
  2305.         xor     ebx, ebx
  2306.         pop     eax
  2307.         ret
  2308.  
  2309. ;----------------------------------------------------------------
  2310. ext_CreateFolder:
  2311.         call    extfsWritingInit
  2312.         call    findInode
  2313.         jnc     .success    ; exist
  2314.         test    edi, edi
  2315.         jz      .error
  2316.         mov     eax, esi
  2317.         call    extfsInodeAlloc
  2318.         jc      .error
  2319.         push    ebx esi edi
  2320.         lea     edi, [ebp+EXTFS.inodeBuffer]
  2321.         movzx   ecx, [ebp+EXTFS.superblock.inodeSize]
  2322.         xor     eax, eax
  2323.         rep stosb
  2324.         call    fsGetTime
  2325.         add     eax, 978307200
  2326.         lea     ebx, [ebp+EXTFS.inodeBuffer]
  2327.         mov     [ebx+INODE.accessedTime], eax
  2328.         mov     [ebx+INODE.dataModified], eax
  2329.         pop     edi esi edx
  2330. ; edx = allocated inode number, edi -> filename, esi = parent inode number
  2331.         mov     [ebx+INODE.accessMode], DIRECTORY or 511
  2332.         mov     byte [ebx+INODE.linksCount], 2
  2333.         mov     eax, edx
  2334.         call    writeInode
  2335.         jc      .error
  2336. ; link to self
  2337.         push    edx esi
  2338.         mov     eax, edx
  2339.         mov     ebx, eax
  2340.         mov     dl, DIR_DIRECTORY
  2341.         mov     esi, self_link
  2342.         call    linkInode
  2343.         pop     esi edx
  2344.         jc      .error
  2345. ; link to parent
  2346.         push    edx esi
  2347.         mov     eax, ebx
  2348.         mov     ebx, esi
  2349.         mov     dl, DIR_DIRECTORY
  2350.         mov     esi, parent_link
  2351.         call    linkInode
  2352.         pop     esi edx
  2353.         jc      .error
  2354. ; link parent to child
  2355.         push    esi
  2356.         mov     eax, esi
  2357.         mov     ebx, edx
  2358.         mov     esi, edi
  2359.         mov     dl, DIR_DIRECTORY
  2360.         call    linkInode
  2361.         pop     edx
  2362.         jc      .error
  2363.         push    ebx
  2364.         lea     ebx, [ebp+EXTFS.inodeBuffer]
  2365.         inc     [ebx+INODE.linksCount]
  2366.         mov     eax, edx
  2367.         call    writeInode
  2368.         pop     ebx
  2369.         jc      .error
  2370.         mov     eax, ebx
  2371.         dec     eax
  2372.         xor     edx, edx
  2373.         div     [ebp+EXTFS.superblock.inodesPerGroup]
  2374.         mov     ebx, [ebp+EXTFS.descriptorTable]
  2375.         shl     eax, 5
  2376.         add     ebx, eax
  2377.         inc     [ebx+BGDESCR.directoriesCount]
  2378.         call    extfsWriteDescriptor
  2379. .success:
  2380. .error:
  2381.         push    eax
  2382.         call    writeSuperblock
  2383.         mov     esi, [ebp+PARTITION.Disk]
  2384.         call    disk_sync
  2385.         call    ext_unlock
  2386.         pop     eax
  2387.         ret
  2388.  
  2389. self_link   db ".", 0
  2390. parent_link db "..", 0
  2391.  
  2392. ;----------------------------------------------------------------
  2393. ext_CreateFile:
  2394.         call    extfsWritingInit
  2395.         pushd   0 0 ebx
  2396.         call    findInode
  2397.         jnc     .exist
  2398.         test    edi, edi
  2399.         jz      .error
  2400.         mov     eax, esi
  2401.         call    extfsInodeAlloc
  2402.         jc      .error
  2403.         push    ebx ebx esi edi
  2404.         lea     edi, [ebp+EXTFS.inodeBuffer]
  2405.         movzx   ecx, [ebp+EXTFS.superblock.inodeSize]
  2406.         xor     eax, eax
  2407.         rep stosb
  2408.         call    fsGetTime
  2409.         add     eax, 978307200
  2410.         lea     ebx, [ebp+EXTFS.inodeBuffer]
  2411.         mov     [ebx+INODE.accessedTime], eax
  2412.         mov     [ebx+INODE.dataModified], eax
  2413.         pop     edi esi edx
  2414. ; edx = allocated inode number, edi -> filename, esi = parent inode number
  2415.         mov     [ebx+INODE.accessMode], FLAG_FILE or 110110110b
  2416.         mov     byte [ebx+INODE.linksCount], 1
  2417.         mov     eax, edx
  2418.         call    writeInode
  2419.         jc      .error2
  2420. ; link parent to child
  2421.         mov     eax, esi
  2422.         mov     ebx, edx
  2423.         mov     esi, edi
  2424.         mov     dl, DIR_FLAG_FILE
  2425.         call    linkInode
  2426.         jc      .error2
  2427.         mov     eax, ebx
  2428.         lea     ebx, [ebp+EXTFS.inodeBuffer]
  2429.         call    readInode
  2430.         jc      .error2
  2431.         pop     esi ebx
  2432.         mov     eax, [ebx+12]
  2433.         xor     edx, edx
  2434.         jmp     ext_WriteFile.start
  2435.  
  2436. .exist:
  2437.         movi    eax, ERROR_ACCESS_DENIED
  2438.         test    [ebp+EXTFS.inodeBuffer.accessMode], FLAG_FILE
  2439.         jz      .error  ; not a file
  2440.         pop     ebx
  2441.         mov     eax, [ebx+12]
  2442.         xor     edx, edx
  2443.         push    eax edx ebx esi
  2444.         call    extfsTruncateFile
  2445.         pop     esi ebx edx eax
  2446.         jmp     ext_WriteFile.start
  2447.  
  2448. .error2:
  2449.         pop     ebx
  2450. .error:
  2451.         push    eax
  2452.         call    ext_unlock
  2453.         pop     eax ebx ebx ebx
  2454.         ret
  2455.  
  2456. ;----------------------------------------------------------------
  2457. ext_WriteFile:
  2458.         call    extfsWritingInit
  2459.         call    findInode
  2460.         pushd   0 eax
  2461.         jc      .ret
  2462.         mov     byte [esp], ERROR_ACCESS_DENIED
  2463.         test    [ebp+EXTFS.inodeBuffer.accessMode], FLAG_FILE
  2464.         jz      .ret    ; not a file
  2465.         mov     byte [esp], 0
  2466.         mov     eax, [ebx+4]
  2467.         mov     edx, [ebx+8]
  2468.         add     eax, [ebx+12]
  2469.         adc     edx, 0
  2470. .start:
  2471.         push    esi
  2472.         mov     ecx, esi
  2473.         call    extfsExtendFile
  2474.         jc      .errorExtend
  2475.         mov     eax, [ebx+4]
  2476.         mov     edx, [ebx+8]
  2477.         mov     ecx, [ebx+12]
  2478.         mov     esi, [ebx+16]
  2479. .write:
  2480.         jecxz   .zero
  2481.         div     [ebp+EXTFS.bytesPerBlock]
  2482.         test    edx, edx
  2483.         jz      .aligned
  2484. .piece:
  2485.         mov     ebx, ecx
  2486.         mov     edi, edx
  2487.         mov     ecx, eax
  2488.         push    eax
  2489.         call    extfsGetExtent
  2490.         jc      .errorGet
  2491.         mov     ecx, [ebp+EXTFS.sectorsPerBlock]
  2492.         mul     ecx
  2493.         push    ecx eax ebx
  2494.         mov     ebx, [ebp+EXTFS.mainBlockBuffer]
  2495.         call    fs_read64_sys
  2496.         test    eax, eax
  2497.         jnz     .errorDevice
  2498.         pop     eax
  2499.         mov     ecx, [ebp+EXTFS.bytesPerBlock]
  2500.         sub     ecx, edi
  2501.         sub     eax, ecx
  2502.         jnc     @f
  2503.         add     ecx, eax
  2504.         xor     eax, eax
  2505. @@:
  2506.         add     edi, ebx
  2507.         add     [esp+20], ecx
  2508.         rep movsb
  2509.         mov     edi, eax
  2510.         pop     eax ecx
  2511.         xor     edx, edx
  2512.         call    fs_write64_sys
  2513.         mov     ecx, edi
  2514.         pop     eax
  2515.         inc     eax
  2516.         xor     edx, edx
  2517. .zero:
  2518.         jecxz   .done
  2519. .aligned:
  2520.         xchg    eax, ecx
  2521.         div     [ebp+EXTFS.bytesPerBlock]
  2522.         push    edx
  2523.         mov     edx, eax
  2524. .writeExtent:
  2525.         test    edx, edx
  2526.         jz      .end
  2527.         push    ecx
  2528.         call    extfsGetExtent
  2529.         jc      .errorGet2
  2530.         sub     edx, ecx
  2531.         jnc     @f
  2532.         add     ecx, edx
  2533.         xor     edx, edx
  2534. @@:
  2535.         add     [esp], ecx
  2536.         imul    ecx, [ebp+EXTFS.sectorsPerBlock]
  2537.         mov     ebx, esi
  2538.         push    edx ecx
  2539.         mul     [ebp+EXTFS.sectorsPerBlock]
  2540.         call    fs_write64_sys
  2541.         test    eax, eax
  2542.         jnz     .errorDevice
  2543.         pop     ebx edx ecx
  2544.         shl     ebx, 9
  2545.         add     esi, ebx
  2546.         add     [esp+12], ebx
  2547.         jmp     .writeExtent
  2548.  
  2549. .end:
  2550.         mov     eax, ecx
  2551.         pop     ecx
  2552.         jecxz   .done
  2553.         jmp     .piece
  2554.  
  2555. .errorDevice:
  2556.         pop     eax eax
  2557.         movi    eax, ERROR_DEVICE
  2558. .errorGet2:
  2559.         pop     ebx
  2560. .errorGet:
  2561.         pop     ebx
  2562. .errorExtend:
  2563.         mov     [esp+4], eax
  2564. .done:
  2565.         lea     ebx, [ebp+EXTFS.inodeBuffer]
  2566.         pop     eax
  2567.         call    writeInode
  2568.         add     [esp], eax
  2569.         call    writeSuperblock
  2570.         mov     esi, [ebp+PARTITION.Disk]
  2571.         call    disk_sync
  2572. .ret:
  2573.         call    ext_unlock
  2574.         pop     eax ebx
  2575.         ret
  2576.  
  2577. .erase:
  2578.         push    eax eax edi
  2579.         mov     eax, ebx
  2580.         jmp     .write
  2581.  
  2582. ;----------------------------------------------------------------
  2583. ext_SetFileEnd:
  2584.         call    extfsWritingInit
  2585.         call    findInode
  2586.         jc      .error2
  2587.         lea     edi, [ebp+EXTFS.inodeBuffer]
  2588.         movi    eax, ERROR_ACCESS_DENIED
  2589.         test    [edi+INODE.accessMode], FLAG_FILE
  2590.         jz      .error2 ; not a file
  2591.         mov     eax, [ebx+4]
  2592.         mov     edx, [ebx+8]
  2593.         mov     ebx, [edi+INODE.fileSize]
  2594.         mov     ecx, [edi+INODE.fileSizeHigh]
  2595.         push    esi ecx
  2596.         cmp     ebx, eax
  2597.         sbb     ecx, edx
  2598.         mov     ecx, esi
  2599.         jnc     @f
  2600.         call    extfsExtendFile
  2601.         pop     esi
  2602.         jc      .error
  2603.         mov     eax, [edi+INODE.fileSize]
  2604.         mov     edx, [edi+INODE.fileSizeHigh]
  2605.         sub     eax, ebx
  2606.         sbb     edx, esi
  2607.         jnz     .done
  2608.         cmp     eax, 1000001h
  2609.         jnc     .done
  2610.         push    eax
  2611.         stdcall kernel_alloc, eax
  2612.         pop     ecx
  2613.         test    eax, eax
  2614.         jz      .error
  2615.         push    ecx
  2616.         add     ecx, 3
  2617.         shr     ecx, 2
  2618.         mov     edx, esi
  2619.         mov     esi, eax
  2620.         mov     edi, eax
  2621.         xor     eax, eax
  2622.         rep stosd
  2623.         pop     ecx edi
  2624.         push    esi
  2625.         call    ext_WriteFile.erase
  2626.         call    kernel_free
  2627.         xor     eax, eax
  2628.         ret
  2629.  
  2630. @@:
  2631.         call    extfsTruncateFile
  2632.         pop     eax
  2633. .done:
  2634.         xor     eax, eax
  2635. .error:
  2636.         xchg    eax, [esp]
  2637.         lea     ebx, [ebp+EXTFS.inodeBuffer]
  2638.         call    writeInode
  2639.         add     [esp], eax
  2640.         call    writeSuperblock
  2641.         mov     esi, [ebp+PARTITION.Disk]
  2642.         call    disk_sync
  2643.         pop     eax
  2644. .error2:
  2645.         push    eax
  2646.         call    ext_unlock
  2647.