Subversion Repositories Kolibri OS

Rev

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