Subversion Repositories Kolibri OS

Rev

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