Subversion Repositories Kolibri OS

Rev

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