Subversion Repositories Kolibri OS

Rev

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