Subversion Repositories Kolibri OS

Rev

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