Subversion Repositories Kolibri OS

Rev

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