Subversion Repositories Kolibri OS

Rev

Rev 6798 | Rev 6848 | 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: 6809 $
  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.         movzx   eax, [ebp+EXTFS.superblock.inodeSize]
  813.         mul     edx
  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.         cmp     byte [esi], '.'
  1904.         jnz     @f
  1905.         or      byte [edx], KOS_HIDDEN
  1906. @@:
  1907.         lea     edi, [edx+40]
  1908.         cmp     byte [edx+4], 3
  1909.         jz      .utf8
  1910.         add     ecx, esi
  1911.         cmp     byte [edx+4], 2
  1912.         jz      .utf16
  1913. @@:
  1914.         call    utf8to16
  1915.         call    uni2ansi_char
  1916.         stosb
  1917.         cmp     esi, ecx
  1918.         jc      @b
  1919.         and     byte [edi], 0
  1920.         add     edx, 40+264
  1921. @@:
  1922.         pop     esi ecx edi ebx
  1923.         dec     ecx
  1924. .empty_rec:
  1925.         movzx   eax, [ebx+DIRENTRY.entryLength]
  1926.         cmp     eax, 12
  1927.         jb      .error_bad_len
  1928.         test    eax, 3
  1929.         jnz     .error_bad_len
  1930.         sub     [esi+INODE.fileSize], eax
  1931.         add     ebx, eax
  1932.         cmp     ebx, [edi+24]
  1933.         jb      .wanted_start
  1934.         push    .wanted_start
  1935.         jmp     .end_block
  1936.  
  1937. .utf8:
  1938.         rep movsb
  1939.         mov     byte [edi], 0
  1940.         add     edx, 40+520
  1941.         jmp     @b
  1942.  
  1943. .utf16:
  1944.         call    utf8to16
  1945.         stosw
  1946.         cmp     esi, ecx
  1947.         jc      .utf16
  1948.         and     word [edi], 0
  1949.         add     edx, 40+520
  1950.         jmp     @b
  1951.  
  1952. .end_dir:
  1953.         call    ext_unlock
  1954.         mov     edx, [edi+28]
  1955.         mov     ebx, [edi+8]
  1956.         mov     ecx, [edi+4]
  1957.         mov     dword [edx], 1  ; version
  1958.         mov     [edx+4], ebx
  1959.         mov     [edx+8], ecx
  1960.         lea     esp, [edi+32]
  1961.         mov     ecx, 20/4
  1962.         lea     edi, [edx+12]
  1963.         xor     eax, eax
  1964.         rep stosd
  1965.         ret
  1966.  
  1967. .error_bad_len:
  1968.         movi    eax, ERROR_FS_FAIL
  1969. .error_read_subinode:
  1970. .error_get_block:
  1971.         lea     esp, [edi+32]
  1972. .error_ret:
  1973.         or      ebx, -1
  1974.         push    eax
  1975.         call    ext_unlock
  1976.         pop     eax
  1977.         ret
  1978.  
  1979. .error_empty_dir:
  1980.         movi    eax, ERROR_FS_FAIL
  1981.         jmp     .error_ret
  1982.  
  1983. .error_not_found:
  1984.         movi    eax, ERROR_FILE_NOT_FOUND
  1985.         jmp     .error_ret
  1986.  
  1987. ;----------------------------------------------------------------
  1988. ext_ReadFile:
  1989.         call    ext_lock
  1990.         pushd   0 ERROR_ACCESS_DENIED
  1991.         cmp     byte [esi], 0
  1992.         jz      .ret  ; root
  1993.         mov     [esp], ebx
  1994.         call    findInode
  1995.         pop     ebx
  1996.         push    eax
  1997.         jc      .ret
  1998.         lea     esi, [ebp+EXTFS.inodeBuffer]
  1999.         mov     byte [esp], ERROR_ACCESS_DENIED
  2000.         test    [esi+INODE.accessMode], FLAG_FILE
  2001.         jz      .ret    ; not a file
  2002.         mov     byte [esp], ERROR_END_OF_FILE
  2003.         mov     eax, [esi+INODE.fileSize]
  2004.         mov     edx, [esi+INODE.fileSizeHigh]
  2005.         sub     eax, [ebx+4]
  2006.         sbb     edx, [ebx+8]
  2007.         jc      .ret
  2008.         mov     ecx, [ebx+12]
  2009.         sub     eax, ecx
  2010.         sbb     edx, 0
  2011.         jc      @f
  2012.         xor     eax, eax
  2013.         mov     [esp], eax
  2014. @@:
  2015.         add     ecx, eax
  2016.         mov     eax, [ebx+4]
  2017.         mov     edx, [ebx+8]
  2018.         mov     edi, [ebx+16]
  2019.         div     [ebp+EXTFS.bytesPerBlock]
  2020.         test    edx, edx
  2021.         jz      .aligned
  2022. .piece:
  2023.         push    eax ecx
  2024.         mov     esi, edx
  2025.         mov     ecx, eax
  2026.         call    extfsGetExtent
  2027.         jc      .errorGet
  2028.         mov     ecx, [ebp+EXTFS.sectorsPerBlock]
  2029.         mul     ecx
  2030.         mov     ebx, [ebp+EXTFS.mainBlockBuffer]
  2031.         call    fs_read64_sys
  2032.         test    eax, eax
  2033.         jnz     .errorRead
  2034.         pop     eax
  2035.         mov     ecx, [ebp+EXTFS.bytesPerBlock]
  2036.         sub     ecx, esi
  2037.         sub     eax, ecx
  2038.         jnc     @f
  2039.         add     ecx, eax
  2040.         xor     eax, eax
  2041. @@:
  2042.         add     esi, ebx
  2043.         add     [esp+8], ecx
  2044.         rep movsb
  2045.         mov     ecx, eax
  2046.         pop     eax
  2047.         inc     eax
  2048.         xor     edx, edx
  2049.         jecxz   .ret
  2050. .aligned:
  2051.         xchg    eax, ecx
  2052.         div     [ebp+EXTFS.bytesPerBlock]
  2053.         push    edx
  2054.         mov     edx, eax
  2055. .writeExtent:
  2056.         test    edx, edx
  2057.         jz      .end
  2058.         push    ecx
  2059.         call    extfsGetExtent
  2060.         jc      .errorGet
  2061.         sub     edx, ecx
  2062.         jnc     @f
  2063.         add     ecx, edx
  2064.         xor     edx, edx
  2065. @@:
  2066.         add     [esp], ecx
  2067.         imul    ecx, [ebp+EXTFS.sectorsPerBlock]
  2068.         mov     ebx, edi
  2069.         push    edx ecx
  2070.         mul     [ebp+EXTFS.sectorsPerBlock]
  2071.         call    fs_read64_sys
  2072.         pop     ecx edx
  2073.         test    eax, eax
  2074.         jnz     .errorRead
  2075.         shl     ecx, 9
  2076.         add     edi, ecx
  2077.         add     [esp+12], ecx
  2078.         pop     ecx
  2079.         jmp     .writeExtent
  2080.  
  2081. .end:
  2082.         mov     eax, ecx
  2083.         pop     ecx
  2084.         jecxz   .ret
  2085.         jmp     .piece
  2086.  
  2087. .errorRead:
  2088.         movi    eax, ERROR_DEVICE
  2089. .errorGet:
  2090.         pop     ebx ebx
  2091.         mov     [esp], eax
  2092. .ret:
  2093.         call    ext_unlock
  2094.         pop     eax ebx
  2095.         ret
  2096.  
  2097. ;----------------------------------------------------------------
  2098. ext_GetFileInfo:
  2099.         call    ext_lock
  2100.         mov     edx, [ebx+16]
  2101.         cmp     byte [esi], 0
  2102.         jz      .is_root
  2103.         push    edx
  2104.         call    findInode
  2105.         pop     edx
  2106.         lea     esi, [ebp+EXTFS.inodeBuffer]
  2107.         jnc     @f
  2108.         push    eax
  2109.         call    ext_unlock
  2110.         pop     eax
  2111.         ret
  2112.  
  2113. .is_root:
  2114.         mov     edi, esi
  2115.         lea     esi, [ebp+EXTFS.rootInodeBuffer]
  2116. @@:
  2117.         mov     bl, [edi]
  2118.         xor     eax, eax
  2119.         mov     edi, edx
  2120.         mov     ecx, 40/4
  2121.         rep stosd
  2122.         cmp     bl, '.'
  2123.         jne     @f
  2124.         or      dword [edx], KOS_HIDDEN
  2125. @@:
  2126.         or      dword [edx], KOS_DIRECTORY
  2127.         test    [esi+INODE.accessMode], FLAG_FILE
  2128.         jz      @f
  2129.         xor     dword [edx], KOS_DIRECTORY  ; mark as file
  2130.         mov     eax, [esi+INODE.fileSize]
  2131.         mov     ebx, [esi+INODE.fileSizeHigh]
  2132.         mov     dword [edx+32], eax
  2133.         mov     dword [edx+36], ebx
  2134. @@:
  2135.         lea     edi, [edx+8]
  2136.         mov     eax, [esi+INODE.inodeModified]
  2137.         sub     eax, 978307200  ; 01.01.1970-01.01.2001 = (365*31+8)*24*60*60
  2138.         call    fsTime2bdfe
  2139.  
  2140.         mov     eax, [esi+INODE.accessedTime]
  2141.         sub     eax, 978307200
  2142.         call    fsTime2bdfe
  2143.  
  2144.         mov     eax, [esi+INODE.dataModified]
  2145.         sub     eax, 978307200
  2146.         call    fsTime2bdfe
  2147.         call    ext_unlock
  2148.         xor     eax, eax
  2149.         ret
  2150.  
  2151. ;----------------------------------------------------------------
  2152. ext_SetFileInfo:
  2153.         call    extfsWritingInit
  2154.         pushd   [ebx+16]
  2155.         call    findInode
  2156.         pop     edx
  2157.         jc      @f
  2158.         push    esi     ; inode number
  2159.         lea     esi, [edx+16]
  2160.         lea     edi, [ebp+EXTFS.inodeBuffer]
  2161.         call    fsCalculateTime
  2162.         add     eax, 978307200  ; 01.01.1970-01.01.2001 = (365*31+8)*24*60*60
  2163.         mov     [edi+INODE.accessedTime], eax
  2164.  
  2165.         add     esi, 8
  2166.         call    fsCalculateTime
  2167.         add     eax, 978307200
  2168.         mov     [edi+INODE.dataModified], eax
  2169.         mov     ebx, edi
  2170.         pop     eax
  2171.         call    writeInode
  2172. @@:
  2173.         push    eax
  2174.         jc      @f
  2175.         call    writeSuperblock
  2176.         mov     esi, [ebp+PARTITION.Disk]
  2177.         call    disk_sync
  2178. @@:
  2179.         call    ext_unlock
  2180.         pop     eax
  2181.         ret
  2182.  
  2183. ;----------------------------------------------------------------
  2184. ext_Delete:
  2185.         call    extfsWritingInit
  2186.         call    findInode
  2187.         mov     ebx, esi
  2188.         push    eax
  2189.         jc      .ret
  2190.         pop     eax
  2191.         lea     edx, [ebp+EXTFS.inodeBuffer]
  2192.         movzx   edx, [edx+INODE.accessMode]
  2193.         and     edx, TYPE_MASK
  2194.         cmp     edx, DIRECTORY
  2195.         jne     .file
  2196.         push    ebx ecx edx
  2197.         xor     ecx, ecx
  2198. .checkDirectory:
  2199.         push    ecx
  2200.         call    extfsGetExtent
  2201.         jc      .empty
  2202.         mov     ebx, [ebp+EXTFS.tempBlockBuffer]
  2203.         call    extfsReadBlock
  2204.         jc      .not_empty_eax
  2205.         mov     edx, ebx
  2206.         add     edx, [ebp+EXTFS.bytesPerBlock]
  2207.         movzx   ecx, [ebx+DIRENTRY.entryLength]
  2208.         add     ebx, ecx
  2209. .dir_entry:
  2210.         cmp     byte [ebx+DIRENTRY.nameLength], 1
  2211.         jne     @f
  2212.         cmp     byte [ebx+DIRENTRY.name], '.'
  2213.         jne     .not_empty
  2214. @@:
  2215.         cmp     byte [ebx+DIRENTRY.nameLength], 2
  2216.         jne     .not_empty
  2217.         cmp     word [ebx+DIRENTRY.name], '..'
  2218.         jne     .not_empty
  2219.         movzx   ecx, [ebx+DIRENTRY.entryLength]
  2220.         add     ebx, ecx
  2221.         cmp     ebx, edx
  2222.         jb      .dir_entry
  2223.         pop     ecx
  2224.         inc     ecx
  2225.         jmp     .checkDirectory
  2226.  
  2227. .not_empty:
  2228.         pop     eax eax
  2229. .error_stack8:
  2230.         pop     eax eax
  2231.         push    ERROR_ACCESS_DENIED
  2232.         jmp     .ret
  2233.  
  2234. .empty:
  2235.         cmp     eax, ERROR_END_OF_FILE
  2236.         jnz     .not_empty_eax
  2237.         pop     edx edx ecx ebx
  2238. .file:
  2239.         mov     eax, ecx
  2240.         push    ebx ecx
  2241.         call    unlinkInode
  2242.         cmp     eax, -1
  2243.         je      .error_stack8
  2244.         pop     ebx
  2245.         test    eax, eax
  2246.         jz      @f
  2247.         xor     eax, eax
  2248.         cmp     edx, DIRECTORY
  2249.         jnz     .error_stack4_eax   ; hardlinks
  2250.         mov     eax, [esp]
  2251.         call    unlinkInode
  2252. @@:
  2253.         mov     eax, [esp]
  2254.         lea     ebx, [ebp+EXTFS.inodeBuffer]
  2255.         call    readInode
  2256.         jc      .error_stack4_eax
  2257.         xor     ecx, ecx
  2258.         call    extfsTruncateFile   ; free file's data
  2259.         movzx   ecx, [ebp+EXTFS.superblock.inodeSize]
  2260.         lea     edi, [ebp+EXTFS.inodeBuffer]
  2261.         xor     eax, eax
  2262.         push    edx edi
  2263.         rep stosb
  2264.         call    fsGetTime
  2265.         pop     ebx ecx
  2266.         add     eax, 978307200
  2267.         mov     [ebx+INODE.deletedTime], eax
  2268.         mov     eax, [esp]
  2269.         call    writeInode
  2270.         jc      .error_stack4_eax
  2271.         pop     eax
  2272.         dec     eax
  2273.         xor     edx, edx
  2274.         div     [ebp+EXTFS.superblock.inodesPerGroup]
  2275.         push    edx eax
  2276.         call    extfsReadDescriptor
  2277.         jc      .error_stack8_eax
  2278.         cmp     ecx, DIRECTORY
  2279.         jnz     @f
  2280.         dec     [ebx+BGDESCR.directoriesCount]
  2281. @@:
  2282.         inc     [ebx+BGDESCR.inodesFree]
  2283.         mov     ecx, [ebx+BGDESCR.inodeBitmap]
  2284.         pop     eax
  2285.         call    extfsWriteDescriptor
  2286.         mov     eax, ecx
  2287.         mov     ebx, [ebp+EXTFS.tempBlockBuffer]
  2288.         call    extfsReadBlock
  2289.         jc      .error_stack4_eax
  2290.         pop     eax
  2291.         mov     edx, eax
  2292.         and     edx, 31
  2293.         shr     eax, 5
  2294.         shl     eax, 2
  2295.         add     eax, ebx
  2296.         btr     [eax], edx
  2297.         mov     eax, ecx
  2298.         call    extfsWriteBlock
  2299.         inc     [ebp+EXTFS.superblock.inodesFree]
  2300.         push    eax
  2301. .disk_sync:
  2302.         call    writeSuperblock
  2303.         mov     esi, [ebp+PARTITION.Disk]
  2304.         call    disk_sync
  2305. .ret:
  2306.         call    ext_unlock
  2307.         xor     ebx, ebx
  2308.         pop     eax
  2309.         ret
  2310.  
  2311. .not_empty_eax:
  2312.         pop     ebx ebx
  2313. .error_stack8_eax:
  2314.         pop     ebx
  2315. .error_stack4_eax:
  2316.         pop     ebx
  2317.         push    eax
  2318.         jmp     .disk_sync
  2319.  
  2320. ;----------------------------------------------------------------
  2321. ext_CreateFolder:
  2322.         call    extfsWritingInit
  2323.         call    findInode
  2324.         jnc     .success    ; exist
  2325.         test    edi, edi
  2326.         jz      .error
  2327.         mov     eax, esi
  2328.         call    extfsInodeAlloc
  2329.         jc      .error
  2330.         push    ebx esi edi
  2331.         xor     al, al
  2332.         lea     edi, [ebp+EXTFS.inodeBuffer]
  2333.         movzx   ecx, [ebp+EXTFS.superblock.inodeSize]
  2334.         rep stosb
  2335.         lea     edi, [ebp+EXTFS.inodeBuffer]
  2336.         call    fsGetTime
  2337.         add     eax, 978307200
  2338.         mov     [edi+INODE.accessedTime], eax
  2339.         mov     [edi+INODE.dataModified], eax
  2340.         mov     ebx, edi
  2341.         pop     edi esi edx
  2342. ; edx = allocated inode number, edi -> filename, esi = parent inode number
  2343.         mov     [ebx+INODE.accessMode], DIRECTORY or PERMISSIONS
  2344.         mov     eax, edx
  2345.         call    writeInode
  2346.         jc      .error
  2347. ; link to self
  2348.         push    edx esi
  2349.         mov     eax, edx
  2350.         mov     ebx, eax
  2351.         mov     dl, DIR_DIRECTORY
  2352.         mov     esi, self_link
  2353.         call    linkInode
  2354.         pop     esi edx
  2355.         jc      .error
  2356. ; link to parent
  2357.         push    edx esi
  2358.         mov     eax, ebx
  2359.         mov     ebx, esi
  2360.         mov     dl, DIR_DIRECTORY
  2361.         mov     esi, parent_link
  2362.         call    linkInode
  2363.         pop     esi edx
  2364.         jc      .error
  2365. ; link parent to child
  2366.         mov     eax, esi
  2367.         mov     ebx, edx
  2368.         mov     esi, edi
  2369.         mov     dl, DIR_DIRECTORY
  2370.         call    linkInode
  2371.         jc      .error
  2372.         mov     eax, ebx
  2373.         dec     eax
  2374.         xor     edx, edx
  2375.         div     [ebp+EXTFS.superblock.inodesPerGroup]
  2376.         mov     edx, eax
  2377.         call    extfsReadDescriptor
  2378.         jc      .error
  2379.         inc     [ebx+BGDESCR.directoriesCount]
  2380.         mov     eax, edx
  2381.         call    extfsWriteDescriptor
  2382. .success:
  2383. .error:
  2384.         push    eax
  2385.         call    writeSuperblock
  2386.         mov     esi, [ebp+PARTITION.Disk]
  2387.         call    disk_sync
  2388.         call    ext_unlock
  2389.         pop     eax
  2390.         ret
  2391.  
  2392. self_link   db ".", 0
  2393. parent_link db "..", 0
  2394.  
  2395. ;----------------------------------------------------------------
  2396. ext_CreateFile:
  2397.         call    extfsWritingInit
  2398.         pushd   0 0 ebx
  2399.         call    findInode
  2400.         jnc     .exist
  2401.         test    edi, edi
  2402.         jz      .error
  2403.         mov     eax, esi
  2404.         call    extfsInodeAlloc
  2405.         jc      .error
  2406.         push    ebx ebx esi edi
  2407.         xor     al, al
  2408.         lea     edi, [ebp+EXTFS.inodeBuffer]
  2409.         movzx   ecx, [ebp+EXTFS.superblock.inodeSize]
  2410.         rep stosb
  2411.         lea     edi, [ebp+EXTFS.inodeBuffer]
  2412.         call    fsGetTime
  2413.         add     eax, 978307200
  2414.         mov     [edi+INODE.accessedTime], eax
  2415.         mov     [edi+INODE.dataModified], eax
  2416.         mov     ebx, edi
  2417.         pop     edi esi edx
  2418. ; edx = allocated inode number, edi -> filename, esi = parent inode number
  2419.         mov     [ebx+INODE.accessMode], FLAG_FILE or PERMISSIONS
  2420.         mov     eax, edx
  2421.         call    writeInode
  2422.         jc      .error2
  2423. ; link parent to child
  2424.         mov     eax, esi
  2425.         mov     ebx, edx
  2426.         mov     esi, edi
  2427.         mov     dl, DIR_FLAG_FILE
  2428.         call    linkInode
  2429.         jc      .error2
  2430.         pop     esi ebx
  2431.         mov     ecx, [ebx+12]
  2432.         jmp     ext_WriteFile.start
  2433.  
  2434. .exist:
  2435.         movi    eax, ERROR_ACCESS_DENIED
  2436.         test    [ebp+EXTFS.inodeBuffer.accessMode], FLAG_FILE
  2437.         jz      .error  ; not a file
  2438.         pop     ebx
  2439.         mov     ecx, [ebx+12]
  2440.         call    extfsTruncateFile
  2441.         jmp     ext_WriteFile.start
  2442.  
  2443. .error2:
  2444.         pop     ebx
  2445. .error:
  2446.         push    eax
  2447.         call    ext_unlock
  2448.         pop     eax ebx ebx ebx
  2449.         ret
  2450.  
  2451. ;----------------------------------------------------------------
  2452. ext_WriteFile:
  2453.         call    extfsWritingInit
  2454.         push    ebx
  2455.         call    findInode
  2456.         pop     ebx
  2457.         pushd   0 eax
  2458.         jc      .ret
  2459.         mov     byte [esp], ERROR_ACCESS_DENIED
  2460.         test    [ebp+EXTFS.inodeBuffer.accessMode], FLAG_FILE
  2461.         jz      .ret    ; not a file
  2462.         mov     ecx, [ebx+4]
  2463.         add     ecx, [ebx+12]
  2464. .start:
  2465.         push    esi
  2466.         mov     eax, esi
  2467.         call    extfsExtendFile
  2468.         jc      .errorExtend
  2469.         mov     eax, [ebx+4]
  2470.         mov     ecx, [ebx+12]
  2471.         mov     esi, [ebx+16]
  2472. .write:
  2473.         xor     edx, edx
  2474.         div     [ebp+EXTFS.bytesPerBlock]
  2475.         test    edx, edx
  2476.         jz      .aligned
  2477. .piece:
  2478.         mov     ebx, ecx
  2479.         mov     edi, edx
  2480.         mov     ecx, eax
  2481.         push    eax
  2482.         call    extfsGetExtent
  2483.         jc      .errorGet
  2484.         mov     ecx, [ebp+EXTFS.sectorsPerBlock]
  2485.         mul     ecx
  2486.         push    ecx eax ebx
  2487.         mov     ebx, [ebp+EXTFS.mainBlockBuffer]
  2488.         call    fs_read64_sys
  2489.         test    eax, eax
  2490.         jnz     .errorDevice
  2491.         pop     eax
  2492.         mov     ecx, [ebp+EXTFS.bytesPerBlock]
  2493.         sub     ecx, edi
  2494.         sub     eax, ecx
  2495.         jnc     @f
  2496.         add     ecx, eax
  2497.         xor     eax, eax
  2498. @@:
  2499.         add     edi, ebx
  2500.         add     [esp+20], ecx
  2501.         rep movsb
  2502.         mov     edi, eax
  2503.         pop     eax ecx
  2504.         xor     edx, edx
  2505.         call    fs_write64_sys
  2506.         mov     ecx, edi
  2507.         pop     eax
  2508.         inc     eax
  2509.         xor     edx, edx
  2510.         jecxz   .done
  2511. .aligned:
  2512.         xchg    eax, ecx
  2513.         div     [ebp+EXTFS.bytesPerBlock]
  2514.         push    edx
  2515.         mov     edx, eax
  2516. .writeExtent:
  2517.         test    edx, edx
  2518.         jz      .end
  2519.         push    ecx
  2520.         call    extfsGetExtent
  2521.         jc      .errorGet2
  2522.         sub     edx, ecx
  2523.         jnc     @f
  2524.         add     ecx, edx
  2525.         xor     edx, edx
  2526. @@:
  2527.         add     [esp], ecx
  2528.         imul    ecx, [ebp+EXTFS.sectorsPerBlock]
  2529.         mov     ebx, esi
  2530.         push    edx ecx
  2531.         mul     [ebp+EXTFS.sectorsPerBlock]
  2532.         call    fs_write64_sys
  2533.         test    eax, eax
  2534.         jnz     .errorDevice
  2535.         pop     ebx edx ecx
  2536.         shl     ebx, 9
  2537.         add     esi, ebx
  2538.         add     [esp+12], ebx
  2539.         jmp     .writeExtent
  2540.  
  2541. .end:
  2542.         mov     eax, ecx
  2543.         pop     ecx
  2544.         jecxz   .done
  2545.         jmp     .piece
  2546.  
  2547. .errorDevice:
  2548.         pop     eax eax
  2549.         movi    eax, ERROR_DEVICE
  2550. .errorGet2:
  2551.         pop     ebx
  2552. .errorGet:
  2553.         pop     ebx
  2554. .errorExtend:
  2555.         mov     [esp+4], eax
  2556. .done:
  2557.         lea     ebx, [ebp+EXTFS.inodeBuffer]
  2558.         pop     eax
  2559.         call    writeInode
  2560.         add     [esp], eax
  2561.         call    writeSuperblock
  2562.         mov     esi, [ebp+PARTITION.Disk]
  2563.         call    disk_sync
  2564. .ret:
  2565.         call    ext_unlock
  2566.         pop     eax ebx
  2567.         ret
  2568.  
  2569. .erase:
  2570.         push    eax eax edx
  2571.         mov     eax, ebx
  2572.         jmp     .write
  2573.  
  2574. ;----------------------------------------------------------------
  2575. ext_SetFileEnd:
  2576.         call    extfsWritingInit
  2577.         pushd   [ebx+4]
  2578.         call    findInode
  2579.         pop     ecx
  2580.         jc      .error2
  2581.         lea     edi, [ebp+EXTFS.inodeBuffer]
  2582.         movi    eax, ERROR_ACCESS_DENIED
  2583.         test    [edi+INODE.accessMode], FLAG_FILE
  2584.         jz      .error2 ; not a file
  2585.         push    esi
  2586.         mov     ebx, [edi+INODE.fileSize]
  2587.         mov     eax, esi
  2588.         cmp     ebx, ecx
  2589.         jnc     @f
  2590.         call    extfsExtendFile
  2591.         jc      .error
  2592.         sub     ecx, ebx
  2593.         cmp     ecx, 1000001h
  2594.         jnc     .done
  2595.         push    ecx
  2596.         stdcall kernel_alloc, ecx
  2597.         pop     ecx
  2598.         test    eax, eax
  2599.         jz      .error
  2600.         push    ecx
  2601.         add     ecx, 3
  2602.         shr     ecx, 2
  2603.         mov     esi, eax
  2604.         mov     edi, eax
  2605.         xor     eax, eax
  2606.         rep stosd
  2607.         pop     ecx edx
  2608.         push    esi
  2609.         call    ext_WriteFile.erase
  2610.         call    kernel_free
  2611.         xor     eax, eax
  2612.         ret
  2613.  
  2614. @@:
  2615.         call    extfsTruncateFile
  2616. .done:
  2617.         xor     eax, eax
  2618. .error:
  2619.         xchg    eax, [esp]
  2620.         lea     ebx, [ebp+EXTFS.inodeBuffer]
  2621.         call    writeInode
  2622.         add     [esp], eax
  2623.         call    writeSuperblock
  2624.         mov     esi, [ebp+PARTITION.Disk]
  2625.         call    disk_sync
  2626.         pop     eax
  2627. .error2:
  2628.         push    eax
  2629.         call    ext_unlock
  2630.         pop     eax
  2631.         ret
  2632.