Subversion Repositories Kolibri OS

Rev

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