Subversion Repositories Kolibri OS

Rev

Rev 6462 | Rev 6471 | 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: 6468 $
  9.  
  10. ; EXT external functions
  11. ;   in:
  12. ; ebx -> parameter structure of sysfunc 70
  13. ; ebp -> EXTFS structure
  14. ; esi -> path string
  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.         jne     .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
  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
  1418. ;   out:
  1419. ; edi -> file name
  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
  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.         sub     esp, 256
  1489.         mov     edx, ebx
  1490.         add     edx, [ebp+EXTFS.bytesPerBlock]
  1491. .start_rec:
  1492.         cmp     [ebx+DIRENTRY.inodeNumber], 0
  1493.         jz      .next_rec
  1494.         mov     edi, esp
  1495.         push    esi
  1496.         movzx   ecx, [ebx+DIRENTRY.nameLength]
  1497.         lea     esi, [ebx+DIRENTRY.name]
  1498.         call    utf8_to_cp866
  1499.         mov     ecx, edi
  1500.         lea     edi, [esp+4]
  1501.         sub     ecx, edi    ; number of bytes in resulting string
  1502.         mov     esi, [esp]
  1503. @@: ; edi -> converted string in stack, ecx = size, esi -> original file path
  1504.         jecxz   .test_find
  1505.         dec     ecx
  1506.         lodsb
  1507.         call    char_toupper
  1508.         mov     ah, [edi]
  1509.         inc     edi
  1510.         xchg    al, ah
  1511.         call    char_toupper
  1512.         cmp     al, ah
  1513.         je      @b
  1514. @@: ; doesn't match
  1515.         pop     esi
  1516. .next_rec:
  1517.         movzx   eax, [ebx+DIRENTRY.entryLength]
  1518.         add     ebx, eax
  1519.         cmp     ebx, edx
  1520.         jb      .start_rec
  1521.         push    eax
  1522.         jmp     @f
  1523.  
  1524. .test_find:
  1525.         cmp     byte [esi], 0
  1526.         je      @f
  1527.         cmp     byte [esi], '/'
  1528.         jne     @b
  1529.         inc     esi
  1530. @@:
  1531.         add     esp, 256+4
  1532.         pop     edx edi ecx
  1533. ; ebx -> matched directory entry, esi -> name without parent, or not changed
  1534.         cmp     edi, esi
  1535.         je      .next_folder_block
  1536.         cmp     byte [esi], 0
  1537.         je      .get_inode_ret
  1538.         mov     eax, [ebx+DIRENTRY.inodeNumber]
  1539.         lea     ebx, [ebp+EXTFS.mainInodeBuffer]
  1540.         call    readInode
  1541.         jc      .error_get_inode
  1542.         movzx   eax, [ebx+INODE.accessMode]
  1543.         and     eax, TYPE_MASK
  1544.         cmp     eax, DIRECTORY
  1545.         jne     .not_found      ; path folder is a file
  1546.         pop     ecx
  1547.         mov     edx, ebx
  1548.         jmp     .next_path_part
  1549.  
  1550. .next_folder_block:
  1551.         pop     eax
  1552.         sub     eax, [ebp+EXTFS.sectorsPerBlock]
  1553.         jle     .not_found
  1554.         push    eax
  1555.         inc     ecx
  1556.         jmp     .folder_block_cycle
  1557.  
  1558. .get_inode_ret:
  1559.         pop     eax
  1560.         mov     dl, [ebx+DIRENTRY.name]
  1561.         mov     eax, [ebx+DIRENTRY.inodeNumber]
  1562.         lea     ebx, [ebp+EXTFS.mainInodeBuffer]
  1563.         mov     esi, eax
  1564.         call    readInode
  1565.         ret
  1566.  
  1567. .not_found:
  1568.         movi    eax, ERROR_FILE_NOT_FOUND
  1569.         stc
  1570.         ret
  1571.  
  1572. .error_get_block:
  1573.         pop     ebx
  1574. .error_get_inode:
  1575.         pop     ebx
  1576.         ret
  1577.  
  1578. writeSuperblock:
  1579.         push    ebx
  1580.         mov     eax, 2
  1581.         lea     ebx, [ebp+EXTFS.superblock]
  1582.         call    fs_write32_sys
  1583.         pop     ebx
  1584.         ret
  1585.  
  1586. extfsWritingInit:
  1587.         movi    eax, ERROR_ACCESS_DENIED
  1588.         cmp     byte [esi], 0
  1589.         jz      @f
  1590.         movi    eax, ERROR_UNSUPPORTED_FS
  1591.         test    [ebp+EXTFS.mountType], READ_ONLY
  1592.         jnz     @f
  1593. ext_lock:
  1594.         lea     ecx, [ebp+EXTFS.Lock]
  1595.         jmp     mutex_lock
  1596.  
  1597. @@:
  1598.         pop     ebx
  1599.         xor     ebx, ebx
  1600.         ret
  1601.  
  1602. ext_unlock:
  1603.         lea     ecx, [ebp+EXTFS.Lock]
  1604.         jmp     mutex_unlock
  1605.  
  1606. ;----------------------------------------------------------------
  1607. ext_ReadFolder:
  1608.         call    ext_lock
  1609.         cmp     byte [esi], 0
  1610.         jz      .root_folder
  1611.         push    ebx
  1612.         call    findInode
  1613.         pop     ebx
  1614.         jc      .error_ret
  1615.         lea     esi, [ebp+EXTFS.mainInodeBuffer]
  1616.         test    [esi+INODE.accessMode], DIRECTORY
  1617.         jz      .error_not_found
  1618.         jmp     @f
  1619.  
  1620. .root_folder:
  1621.         lea     esi, [ebp+EXTFS.rootInodeBuffer]
  1622.         lea     edi, [ebp+EXTFS.mainInodeBuffer]
  1623.         movzx   ecx, [ebp+EXTFS.superblock.inodeSize]
  1624.         shr     ecx, 2
  1625.         push    edi
  1626.         rep movsd
  1627.         pop     esi
  1628. @@:
  1629.         cmp     [esi+INODE.fileSize], 0
  1630.         je      .error_empty_dir
  1631.         mov     edx, [ebx+16]
  1632.         push    edx         ; [edi+28] result buffer
  1633.         push    0           ; [edi+24] end of the current block in folder
  1634.         pushd   [ebx+12]    ; [edi+20] files to read
  1635.         pushd   [ebx+4]     ; [edi+16] first wanted file
  1636.         pushd   [ebx+8]     ; [edi+12] flags
  1637.         push    0           ; [edi+8]  read files
  1638.         push    0           ; [edi+4]  files in folder
  1639.         push    0           ; [edi]    current block index
  1640.         mov     edi, esp    ; edi -> local variables
  1641.         add     edx, 32
  1642.         xor     ecx, ecx
  1643.         call    extfsGetFileBlock
  1644.         jc      .error_get_block
  1645.         mov     eax, ecx
  1646.         mov     ebx, [ebp+EXTFS.mainBlockBuffer]
  1647.         call    extfsReadBlock
  1648.         jc      .error_get_block
  1649.         mov     eax, ebx
  1650.         add     eax, [ebp+EXTFS.bytesPerBlock]
  1651.         mov     [edi+24], eax
  1652.         mov     ecx, [edi+16]
  1653. .find_wanted_start:
  1654.         jecxz   .find_wanted_end
  1655. .find_wanted_cycle:
  1656.         cmp     [ebx+DIRENTRY.inodeNumber], 0
  1657.         jz      @f
  1658.         inc     dword [edi+4]
  1659.         dec     ecx
  1660. @@:
  1661.         movzx   eax, [ebx+DIRENTRY.entryLength]
  1662.         cmp     eax, 12     ; minimum entry length
  1663.         jb      .error_bad_len
  1664.         test    eax, 3      ; length must be aligned
  1665.         jnz     .error_bad_len
  1666.         sub     [esi+INODE.fileSize], eax
  1667.         add     ebx, eax
  1668.         cmp     ebx, [edi+24]
  1669.         jb      .find_wanted_start
  1670.         push    .find_wanted_start
  1671. .end_block: ; read next block
  1672.         cmp     [esi+INODE.fileSize], 0
  1673.         jle     .end_dir
  1674.         inc     dword [edi]
  1675.         push    ecx
  1676.         mov     ecx, [edi]
  1677.         call    extfsGetFileBlock
  1678.         jc      .error_get_block
  1679.         mov     eax, ecx
  1680.         mov     ebx, [ebp+EXTFS.mainBlockBuffer]
  1681.         call    extfsReadBlock
  1682.         jc      .error_get_block
  1683.         pop     ecx
  1684.         mov     eax, ebx
  1685.         add     eax, [ebp+EXTFS.bytesPerBlock]
  1686.         mov     [edi+24], eax
  1687.         ret
  1688.  
  1689. .wanted_end:
  1690.         loop    .find_wanted_cycle
  1691. .find_wanted_end:
  1692.         mov     ecx, [edi+20]
  1693. .wanted_start:
  1694.         jecxz   .wanted_end
  1695.         cmp     [ebx+DIRENTRY.inodeNumber], 0
  1696.         jz      .empty_rec
  1697.         inc     dword [edi+8]
  1698.         inc     dword [edi+4]
  1699.         push    ebx edi ecx esi edx
  1700.         mov     edi, edx
  1701.         xor     eax, eax
  1702.         mov     ecx, 40 / 4
  1703.         rep stosd
  1704.         mov     eax, [ebx+DIRENTRY.inodeNumber]
  1705.         lea     ebx, [ebp+EXTFS.tempInodeBuffer]
  1706.         call    readInode
  1707.         jc      .error_read_subinode
  1708.         mov     esi, ebx
  1709.         lea     edi, [edx+8]
  1710.         mov     eax, [ebx+INODE.inodeModified]
  1711.         sub     eax, 978307200  ; 01.01.1970-01.01.2001 = (365*31+8)*24*60*60
  1712.         call    fsTime2bdfe
  1713.  
  1714.         mov     eax, [esi+INODE.accessedTime]
  1715.         sub     eax, 978307200
  1716.         call    fsTime2bdfe
  1717.  
  1718.         mov     eax, [esi+INODE.dataModified]
  1719.         sub     eax, 978307200
  1720.         call    fsTime2bdfe
  1721.         pop     edx
  1722.         or      dword [edx], KOS_DIRECTORY
  1723.         test    [esi+INODE.accessMode], DIRECTORY
  1724.         jnz     @f
  1725.         xor     dword [edx], KOS_DIRECTORY  ; mark as file
  1726.         mov     eax, [esi+INODE.fileSize]
  1727.         stosd
  1728.         mov     eax, [esi+INODE.fileSizeHigh]
  1729.         stosd
  1730. @@:
  1731.         mov     esi, [esp+12]
  1732.         movzx   ecx, [esi+DIRENTRY.nameLength]
  1733.         lea     edi, [edx+40]
  1734.         lea     esi, [esi+DIRENTRY.name]
  1735.         call    utf8_to_cp866
  1736.         and     byte [edi], 0
  1737.         pop     esi ecx edi ebx
  1738.         cmp     byte [edx+40], '.'
  1739.         jne     @f
  1740.         or      dword [edx], KOS_HIDDEN
  1741. @@:
  1742.         add     edx, 40+264 ; go to the next record
  1743.         dec     ecx
  1744. .empty_rec:
  1745.         movzx   eax, [ebx+DIRENTRY.entryLength]
  1746.         cmp     eax, 12
  1747.         jb      .error_bad_len
  1748.         test    eax, 3
  1749.         jnz     .error_bad_len
  1750.         sub     [esi+INODE.fileSize], eax
  1751.         add     ebx, eax
  1752.         cmp     ebx, [edi+24]
  1753.         jb      .wanted_start
  1754.         push    .wanted_start
  1755.         jmp     .end_block
  1756.  
  1757. .end_dir:
  1758.         call    ext_unlock
  1759.         mov     edx, [edi+28]
  1760.         mov     ebx, [edi+8]
  1761.         mov     ecx, [edi+4]
  1762.         mov     dword [edx], 1  ; version
  1763.         mov     [edx+4], ebx
  1764.         mov     [edx+8], ecx
  1765.         lea     esp, [edi+32]
  1766.         mov     ecx, 20/4
  1767.         lea     edi, [edx+12]
  1768.         xor     eax, eax
  1769.         rep stosd
  1770.         ret
  1771.  
  1772. .error_bad_len:
  1773.         movi    eax, ERROR_FS_FAIL
  1774. .error_read_subinode:
  1775. .error_get_block:
  1776.         lea     esp, [edi+32]
  1777. .error_ret:
  1778.         or      ebx, -1
  1779.         push    eax
  1780.         call    ext_unlock
  1781.         pop     eax
  1782.         ret
  1783.  
  1784. .error_empty_dir:
  1785.         movi    eax, ERROR_FS_FAIL
  1786.         jmp     .error_ret
  1787.  
  1788. .error_not_found:
  1789.         movi    eax, ERROR_FILE_NOT_FOUND
  1790.         jmp     .error_ret
  1791.  
  1792. ;----------------------------------------------------------------
  1793. ext_ReadFile:
  1794.         call    ext_lock
  1795.         push    ERROR_ACCESS_DENIED
  1796.         cmp     byte [esi], 0
  1797.         jz      .error  ; root
  1798.         mov     [esp], ebx
  1799.         call    findInode
  1800.         pop     ebx
  1801.         jc      .error_eax
  1802.         push    ERROR_ACCESS_DENIED
  1803.         lea     esi, [ebp+EXTFS.mainInodeBuffer]
  1804.         mov     ax, [esi+INODE.accessMode]
  1805.         and     ax, TYPE_MASK
  1806.         cmp     ax, FLAG_FILE
  1807.         jnz     .error  ; not a file
  1808.         pop     eax
  1809.         mov     edi, [ebx+16]
  1810.         mov     ecx, [ebx+12]
  1811.         mov     eax, [ebx+4]
  1812.         mov     edx, [ebx+8]
  1813.         push    ERROR_END_OF_FILE
  1814.         cmp     [esi+INODE.fileSizeHigh], edx
  1815.         ja      @f
  1816.         jb      .error
  1817.         cmp     [esi+INODE.fileSize], eax
  1818.         jna     .error
  1819. @@:
  1820.         add     esp, 4
  1821.         add     eax, ecx
  1822.         adc     edx, 0
  1823.         cmp     [esi+INODE.fileSizeHigh], edx
  1824.         ja      .read_till_requested
  1825.         jb      .read_whole_file
  1826.         cmp     [esi+INODE.fileSize], eax
  1827.         jae     .read_till_requested
  1828. .read_whole_file:
  1829.         push    1   ; read till the end of file
  1830.         mov     ecx, [esi+INODE.fileSize]
  1831.         sub     ecx, [ebx+4]
  1832.         jmp     @f
  1833.  
  1834. .read_till_requested:
  1835.         push    0   ; read as much as requested
  1836. @@: ; ecx = bytes to read, edi -> buffer
  1837.         push    ecx
  1838. ; read part of the first block
  1839.         mov     edx, [ebx+8]
  1840.         mov     eax, [ebx+4]
  1841.         div     [ebp+EXTFS.bytesPerBlock]
  1842.         push    eax
  1843.         push    ecx
  1844.         mov     ecx, eax
  1845.         call    extfsGetFileBlock
  1846.         jc      .error_at_first_block
  1847.         mov     ebx, [ebp+EXTFS.mainBlockBuffer]
  1848.         mov     eax, ecx
  1849.         call    extfsReadBlock
  1850.         jc      .error_at_first_block
  1851.         pop     ecx
  1852.         add     ebx, edx
  1853.         neg     edx
  1854.         add     edx, [ebp+EXTFS.bytesPerBlock]
  1855.         cmp     ecx, edx
  1856.         jbe     .only_one_block
  1857.         mov     eax, ecx
  1858.         sub     eax, edx    ; bytes to read
  1859.         mov     ecx, edx
  1860.         push    esi
  1861.         mov     esi, ebx
  1862.         rep movsb
  1863.         pop     esi
  1864.         mov     ebx, edi
  1865.         xor     edx, edx
  1866.         div     [ebp+EXTFS.bytesPerBlock]
  1867.         mov     edi, eax
  1868. @@:
  1869.         test    edi, edi
  1870.         jz      .finish_block
  1871.         inc     dword [esp]
  1872.         mov     ecx, [esp]
  1873.         call    extfsGetFileBlock
  1874.         jc      .error_at_read_cycle
  1875.         mov     eax, ecx
  1876.         call    extfsReadBlock
  1877.         jc      .error_at_read_cycle
  1878.         add     ebx, [ebp+EXTFS.bytesPerBlock]
  1879.         dec     edi
  1880.         jmp     @b
  1881.  
  1882. .finish_block:  ; edx = number of bytes in the last block
  1883.         test    edx, edx
  1884.         jz      .end_read
  1885.         pop     ecx     ; block counter
  1886.         inc     ecx
  1887.         call    extfsGetFileBlock
  1888.         jc      .error_at_finish_block
  1889.         mov     edi, ebx
  1890.         mov     eax, ecx
  1891.         mov     ebx, [ebp+EXTFS.mainBlockBuffer]
  1892.         call    extfsReadBlock
  1893.         jc      .error_at_finish_block
  1894.         push    eax
  1895.         mov     ecx, edx
  1896. .only_one_block:
  1897.         mov     esi, ebx
  1898.         rep movsb
  1899. .end_read:
  1900.         call    ext_unlock
  1901.         pop     eax ebx eax
  1902.         test    eax, eax
  1903.         jz      @f
  1904.         movi    eax, ERROR_END_OF_FILE
  1905. @@:
  1906.         ret
  1907.  
  1908. .error_at_first_block:
  1909.         pop     ebx
  1910. .error_at_read_cycle:
  1911.         pop     ebx
  1912. .error_at_finish_block:
  1913.         pop     ebx ebx
  1914. .error_eax:
  1915.         push    eax
  1916. .error:
  1917.         call    ext_unlock
  1918.         xor     ebx, ebx
  1919.         pop     eax
  1920.         ret
  1921.  
  1922. ;----------------------------------------------------------------
  1923. ext_GetFileInfo:
  1924.         call    ext_lock
  1925.         mov     edx, [ebx+16]
  1926.         cmp     byte [esi], 0
  1927.         jz      .is_root
  1928.         push    edx
  1929.         call    findInode
  1930.         mov     ebx, edx
  1931.         pop     edx
  1932.         lea     esi, [ebp+EXTFS.mainInodeBuffer]
  1933.         jnc     @f
  1934.         push    eax
  1935.         call    ext_unlock
  1936.         pop     eax
  1937.         ret
  1938.  
  1939. .is_root:
  1940.         xor     ebx, ebx
  1941.         lea     esi, [ebp+EXTFS.rootInodeBuffer]
  1942. @@:
  1943.         xor     eax, eax
  1944.         mov     edi, edx
  1945.         mov     ecx, 40/4
  1946.         rep stosd
  1947.         cmp     bl, '.'
  1948.         jne     @f
  1949.         or      dword [edx], KOS_HIDDEN
  1950. @@:
  1951.         or      dword [edx], KOS_DIRECTORY
  1952.         test    [esi+INODE.accessMode], DIRECTORY
  1953.         jnz     @f
  1954.         xor     dword [edx], KOS_DIRECTORY  ; mark as file
  1955.         mov     eax, [esi+INODE.fileSize]
  1956.         mov     ebx, [esi+INODE.fileSizeHigh]
  1957.         mov     dword [edx+32], eax
  1958.         mov     dword [edx+36], ebx
  1959. @@:
  1960.         lea     edi, [edx+8]
  1961.         mov     eax, [esi+INODE.inodeModified]
  1962.         sub     eax, 978307200  ; 01.01.1970-01.01.2001 = (365*31+8)*24*60*60
  1963.         call    fsTime2bdfe
  1964.  
  1965.         mov     eax, [esi+INODE.accessedTime]
  1966.         sub     eax, 978307200
  1967.         call    fsTime2bdfe
  1968.  
  1969.         mov     eax, [esi+INODE.dataModified]
  1970.         sub     eax, 978307200
  1971.         call    fsTime2bdfe
  1972.         call    ext_unlock
  1973.         xor     eax, eax
  1974.         ret
  1975.  
  1976. ;----------------------------------------------------------------
  1977. ext_SetFileInfo:
  1978.         call    extfsWritingInit
  1979.         pushd   [ebx+16]
  1980.         call    findInode
  1981.         pop     edx
  1982.         jc      @f
  1983.         push    esi     ; inode number
  1984.         lea     esi, [edx+16]
  1985.         lea     edi, [ebp+EXTFS.mainInodeBuffer]
  1986.         call    fsCalculateTime
  1987.         add     eax, 978307200  ; 01.01.1970-01.01.2001 = (365*31+8)*24*60*60
  1988.         mov     [edi+INODE.accessedTime], eax
  1989.  
  1990.         add     esi, 8
  1991.         call    fsCalculateTime
  1992.         add     eax, 978307200
  1993.         mov     [edi+INODE.dataModified], eax
  1994.         mov     ebx, edi
  1995.         pop     eax
  1996.         call    writeInode
  1997. @@:
  1998.         push    eax
  1999.         jc      @f
  2000.         call    writeSuperblock
  2001.         mov     esi, [ebp+PARTITION.Disk]
  2002.         call    disk_sync
  2003. @@:
  2004.         call    ext_unlock
  2005.         pop     eax
  2006.         ret
  2007.  
  2008. ;----------------------------------------------------------------
  2009. ext_Delete:
  2010.         call    extfsWritingInit
  2011.         push    esi
  2012.         call    findInode
  2013.         mov     ebx, esi
  2014.         pop     esi
  2015.         push    eax
  2016.         jc      .ret
  2017.         pop     eax
  2018.         lea     edx, [ebp+EXTFS.mainInodeBuffer]
  2019.         movzx   edx, [edx+INODE.accessMode]
  2020.         and     edx, TYPE_MASK
  2021.         cmp     edx, DIRECTORY
  2022.         jne     .file
  2023.         push    esi ebx edx 0
  2024.         lea     esi, [ebp+EXTFS.mainInodeBuffer]
  2025. .checkDirectory:
  2026.         mov     ecx, [esp]
  2027.         call    extfsGetFileBlock
  2028.         jc      .not_empty_eax
  2029.         test    ecx, ecx
  2030.         jz      .empty
  2031.         mov     eax, ecx
  2032.         mov     ebx, [ebp+EXTFS.tempBlockBuffer]
  2033.         call    extfsReadBlock
  2034.         jc      .not_empty_eax
  2035.         mov     edx, ebx
  2036.         add     edx, [ebp+EXTFS.bytesPerBlock]
  2037.         movzx   ecx, [ebx+DIRENTRY.entryLength]
  2038.         add     ebx, ecx
  2039. .dir_entry:
  2040.         cmp     byte [ebx+DIRENTRY.nameLength], 1
  2041.         jne     @f
  2042.         cmp     byte [ebx+DIRENTRY.name], '.'
  2043.         jne     .not_empty
  2044. @@:
  2045.         cmp     byte [ebx+DIRENTRY.nameLength], 2
  2046.         jne     .not_empty
  2047.         cmp     word [ebx+DIRENTRY.name], '..'
  2048.         jne     .not_empty
  2049.         movzx   ecx, [ebx+DIRENTRY.entryLength]
  2050.         add     ebx, ecx
  2051.         cmp     ebx, edx
  2052.         jb      .dir_entry
  2053.         inc     dword[esp]
  2054.         jmp     .checkDirectory
  2055.  
  2056. .empty:
  2057.         pop     edx edx ebx esi
  2058. .file:
  2059.         call    findInode_parent
  2060.         jc      .error
  2061.         mov     eax, esi
  2062. ; save file/folder's and parent's inode
  2063.         push    ebx eax
  2064.         cmp     edx, DIRECTORY
  2065.         jne     @f
  2066. ; Unlink '.'
  2067.         mov     eax, [esp+4]
  2068.         call    unlinkInode
  2069.         cmp     eax, -1
  2070.         je      .error_stack8
  2071. ; Unlink '..'
  2072.         mov     eax, [esp+4]
  2073.         mov     ebx, [esp]
  2074.         call    unlinkInode
  2075.         cmp     eax, -1
  2076.         je      .error_stack8
  2077. @@:
  2078.         pop     eax
  2079.         mov     ebx, [esp]
  2080.         call    unlinkInode
  2081.         cmp     eax, -1
  2082.         je      .error_stack4
  2083.         test    eax, eax
  2084.         jz      @f
  2085. ; has hardlinks
  2086.         xor     eax, eax
  2087.         mov     [esp], eax
  2088.         jmp     .disk_sync
  2089.  
  2090. @@:
  2091.         mov     eax, [esp]
  2092.         lea     ebx, [ebp+EXTFS.mainInodeBuffer]
  2093.         call    readInode
  2094.         jc      .error_stack4_eax
  2095. ; free file's data
  2096.         lea     esi, [ebp+EXTFS.mainInodeBuffer]
  2097.         xor     ecx, ecx
  2098. @@:
  2099.         push    ecx
  2100.         call    extfsGetFileBlock
  2101.         jc      .error_stack8_eax
  2102.         mov     eax, ecx
  2103.         test    eax, eax
  2104.         jz      @f
  2105.         xor     ecx, ecx
  2106.         call    extfsResourceFree
  2107.         pop     ecx
  2108.         inc     ecx
  2109.         jmp     @b
  2110.  
  2111. @@: ; free indirect blocks
  2112.         pop     ecx
  2113.         push    edx
  2114.         lea     edi, [ebp+EXTFS.mainInodeBuffer]
  2115.         mov     eax, [edi+INODE.addressBlock]
  2116.         test    eax, eax
  2117.         jz      .success
  2118.         xor     ecx, ecx
  2119.         call    extfsResourceFree
  2120.         mov     eax, [edi+INODE.doubleAddress]
  2121.         call    freeDoublyIndirectBlock
  2122.         cmp     eax, 1
  2123.         je      .success
  2124.         mov     eax, [edi+INODE.tripleAddress]
  2125.         test    eax, eax
  2126.         jz      .success
  2127.         push    eax
  2128.         mov     ebx, [ebp+EXTFS.tempBlockBuffer]
  2129.         call    extfsReadBlock
  2130.         pop     ecx
  2131.         jc      .error_stack8_eax
  2132.         mov     eax, ecx
  2133.         xor     ecx, ecx
  2134.         call    extfsResourceFree
  2135.         mov     edx, ebx
  2136.         add     edx, [ebp+EXTFS.bytesPerBlock]
  2137. @@:
  2138.         mov     eax, [ebx]
  2139.         test    eax, eax
  2140.         jz      .success
  2141.         push    ebx edx
  2142.         call    freeDoublyIndirectBlock
  2143.         pop     edx ebx
  2144.         cmp     eax, 1
  2145.         je      .success
  2146.         add     ebx, 4
  2147.         cmp     ebx, edx
  2148.         jb      @b
  2149. .success:   ; clear the inode, and add deletion time
  2150.         xor     eax, eax
  2151.         movzx   ecx, [ebp+EXTFS.superblock.inodeSize]
  2152.         rep stosb
  2153.         lea     edi, [ebp+EXTFS.mainInodeBuffer]
  2154.         call    fsGetTime
  2155.         pop     edx
  2156.         add     eax, 978307200
  2157.         mov     [edi+INODE.deletedTime], eax
  2158.         mov     eax, [esp]
  2159.         mov     ebx, edi
  2160.         call    writeInode
  2161.         jc      .error_stack4_eax
  2162.         cmp     edx, DIRECTORY
  2163.         jne     @f
  2164.         mov     eax, [esp]
  2165.         dec     eax
  2166.         xor     edx, edx
  2167.         div     [ebp+EXTFS.superblock.inodesPerGroup]
  2168.         push    eax
  2169.         call    extfsReadDescriptor
  2170.         jc      .error_stack8
  2171.         dec     [eax+BGDESCR.directoriesCount]
  2172.         pop     eax
  2173.         call    extfsWriteDescriptor
  2174. @@: ; free inode
  2175.         pop     eax
  2176.         dec     eax
  2177.         xor     ecx, ecx
  2178.         inc     ecx
  2179.         call    extfsResourceFree
  2180.         push    eax
  2181. .disk_sync:
  2182.         call    writeSuperblock
  2183.         mov     esi, [ebp+PARTITION.Disk]
  2184.         call    disk_sync
  2185. .ret:
  2186.         call    ext_unlock
  2187.         xor     ebx, ebx
  2188.         pop     eax
  2189.         ret
  2190.  
  2191. .not_empty:
  2192.         pop     eax
  2193. .error_stack8:
  2194.         pop     eax
  2195. .error_stack4:
  2196.         pop     eax
  2197.         push    ERROR_ACCESS_DENIED
  2198.         jmp     .disk_sync
  2199.  
  2200. .not_empty_eax:
  2201.         pop     ebx
  2202. .error_stack8_eax:
  2203.         pop     ebx
  2204. .error_stack4_eax:
  2205.         pop     ebx
  2206. .error:
  2207.         push    eax
  2208.         jmp     .disk_sync
  2209.  
  2210. ;----------------------------------------------------------------
  2211. ext_CreateFolder:
  2212.         call    extfsWritingInit
  2213.         push    esi
  2214.         call    findInode
  2215.         pop     esi
  2216.         jnc     .success    ; exist
  2217.         call    findInode_parent
  2218.         jc      .error
  2219.         mov     eax, esi
  2220.         xor     ebx, ebx
  2221.         inc     ebx
  2222.         call    extfsResourceAlloc
  2223.         jc      .error
  2224.         inc     ebx
  2225.         push    ebx esi edi
  2226.         xor     al, al
  2227.         lea     edi, [ebp+EXTFS.tempInodeBuffer]
  2228.         movzx   ecx, [ebp+EXTFS.superblock.inodeSize]
  2229.         rep stosb
  2230.         lea     edi, [ebp+EXTFS.tempInodeBuffer]
  2231.         call    fsGetTime
  2232.         add     eax, 978307200
  2233.         mov     [edi+INODE.accessedTime], eax
  2234.         mov     [edi+INODE.dataModified], eax
  2235.         mov     ebx, edi
  2236.         pop     edi esi edx
  2237. ; edx = allocated inode number, edi -> filename, esi = parent inode number
  2238.         mov     [ebx+INODE.accessMode], DIRECTORY or PERMISSIONS
  2239.         mov     eax, edx
  2240.         call    writeInode
  2241.         jc      .error
  2242. ; link to self
  2243.         push    edx esi
  2244.         mov     eax, edx
  2245.         mov     ebx, eax
  2246.         mov     dl, DIR_DIRECTORY
  2247.         mov     esi, self_link
  2248.         call    linkInode
  2249.         pop     esi edx
  2250.         jc      .error
  2251. ; link to parent
  2252.         push    edx esi
  2253.         mov     eax, ebx
  2254.         mov     ebx, esi
  2255.         mov     dl, DIR_DIRECTORY
  2256.         mov     esi, parent_link
  2257.         call    linkInode
  2258.         pop     esi edx
  2259.         jc      .error
  2260. ; link parent to child
  2261.         mov     eax, esi
  2262.         mov     ebx, edx
  2263.         mov     esi, edi
  2264.         mov     dl, DIR_DIRECTORY
  2265.         call    linkInode
  2266.         jc      .error
  2267.         mov     eax, ebx
  2268.         dec     eax
  2269.         xor     edx, edx
  2270.         div     [ebp+EXTFS.superblock.inodesPerGroup]
  2271.         mov     edx, eax
  2272.         call    extfsReadDescriptor
  2273.         jc      @f
  2274.         inc     [eax+BGDESCR.directoriesCount]
  2275.         mov     eax, edx
  2276.         call    extfsWriteDescriptor
  2277. .success:
  2278. .error:
  2279.         push    eax
  2280.         call    writeSuperblock
  2281.         mov     esi, [ebp+PARTITION.Disk]
  2282.         call    disk_sync
  2283.         call    ext_unlock
  2284.         pop     eax
  2285.         ret
  2286.  
  2287. @@:
  2288.         movi    eax, ERROR_DEVICE
  2289.         jmp     .error
  2290.  
  2291. self_link   db ".", 0
  2292. parent_link db "..", 0
  2293.  
  2294. ;----------------------------------------------------------------
  2295. ext_CreateFile:
  2296.         call    extfsWritingInit
  2297.         push    ebx esi
  2298.         call    findInode
  2299.         mov     esi, [esp]
  2300.         jc      @f
  2301.         call    ext_unlock
  2302.         call    ext_Delete
  2303.         push    eax
  2304.         call    ext_lock
  2305.         pop     eax
  2306.         test    eax, eax
  2307.         jnz     .error
  2308.         mov     esi, [esp]
  2309. @@:
  2310.         call    findInode_parent
  2311.         jc      .error
  2312.         mov     eax, esi
  2313.         xor     ebx, ebx
  2314.         inc     ebx
  2315.         call    extfsResourceAlloc
  2316.         jc      .error
  2317.         inc     ebx
  2318.         push    ebx esi edi
  2319.         xor     al, al
  2320.         lea     edi, [ebp+EXTFS.tempInodeBuffer]
  2321.         movzx   ecx, [ebp+EXTFS.superblock.inodeSize]
  2322.         rep stosb
  2323.         lea     edi, [ebp+EXTFS.tempInodeBuffer]
  2324.         call    fsGetTime
  2325.         add     eax, 978307200
  2326.         mov     [edi+INODE.accessedTime], eax
  2327.         mov     [edi+INODE.dataModified], eax
  2328.         mov     ebx, edi
  2329.         pop     edi esi edx
  2330. ; edx = allocated inode number, edi -> filename, esi = parent inode number
  2331.         mov     [ebx+INODE.accessMode], FLAG_FILE or PERMISSIONS
  2332.         mov     eax, edx
  2333.         call    writeInode
  2334.         jc      .error
  2335. ; link parent to child
  2336.         mov     eax, esi
  2337.         mov     ebx, edx
  2338.         mov     esi, edi
  2339.         mov     dl, DIR_FLAG_FILE
  2340.         call    linkInode
  2341.         jc      .error
  2342.         pop     esi ebx
  2343.         call    ext_unlock
  2344.         jmp     ext_WriteFile
  2345.  
  2346. .error:
  2347.         push    eax
  2348.         call    ext_unlock
  2349.         pop     eax ebx ebx
  2350.         xor     ebx, ebx
  2351.         ret
  2352.  
  2353. ;----------------------------------------------------------------
  2354. ext_WriteFile:
  2355.         call    extfsWritingInit
  2356.         push    0 ebx
  2357.         call    findInode
  2358.         jc      .error
  2359.         lea     edx, [ebp+EXTFS.mainInodeBuffer]
  2360.         movi    eax, ERROR_ACCESS_DENIED
  2361.         test    [edx+INODE.accessMode], FLAG_FILE
  2362.         jz      .error  ; not a file
  2363.         mov     ebx, [esp]
  2364.         push    esi     ; inode number
  2365.         mov     eax, esi
  2366.         mov     ecx, [ebx+4]
  2367.         call    extfsExtendFile
  2368.         jc      .error2
  2369.         mov     ecx, [ebx+12]
  2370.         mov     esi, [ebx+16]
  2371.         mov     eax, [edx+INODE.fileSize]
  2372.         push    eax
  2373.         xor     edx, edx
  2374.         div     [ebp+EXTFS.bytesPerBlock]
  2375.         test    edx, edx
  2376.         jz      .start_aligned
  2377.         mov     ebx, [ebp+EXTFS.bytesPerBlock]
  2378.         sub     ebx, edx
  2379.         cmp     ebx, ecx
  2380.         jbe     @f
  2381.         mov     ebx, ecx
  2382. @@:
  2383.         push    eax
  2384.         call    extfsReadFileBlock
  2385.         pop     edi
  2386.         jc      .error_inode_size
  2387.         mov     eax, edi
  2388.         push    ecx
  2389.         mov     ecx, ebx
  2390.         mov     edi, ebx
  2391.         add     edi, edx
  2392.         rep movsb
  2393.         pop     ecx
  2394.         call    extfsWriteFileBlock
  2395.         jc      .error_inode_size
  2396.         add     [esp], ebx
  2397.         sub     ecx, ebx
  2398.         jz      .write_inode
  2399. .start_aligned:
  2400.         cmp     ecx, [ebp+EXTFS.bytesPerBlock]
  2401.         jb      @f
  2402.         mov     eax, [esp]
  2403.         xor     edx, edx
  2404.         div     [ebp+EXTFS.bytesPerBlock]
  2405.         mov     edx, [esp+4]
  2406.         push    eax
  2407.         call    extfsEraseFileBlock
  2408.         pop     edi
  2409.         jc      .error_inode_size
  2410.         mov     eax, edi
  2411.         push    ecx
  2412.         mov     ecx, [ebp+EXTFS.bytesPerBlock]
  2413.         mov     edi, [ebp+EXTFS.mainBlockBuffer]
  2414.         rep movsb
  2415.         pop     ecx
  2416.         call    extfsWriteFileBlock
  2417.         jc      .error_inode_size
  2418.         mov     eax, [ebp+EXTFS.bytesPerBlock]
  2419.         sub     ecx, eax
  2420.         add     [esp], eax
  2421.         jmp     .start_aligned
  2422. @@:         ; Handle the remaining bytes.
  2423.         test    ecx, ecx
  2424.         jz      .write_inode
  2425.         mov     eax, [esp]
  2426.         xor     edx, edx
  2427.         div     [ebp+EXTFS.bytesPerBlock]
  2428.         push    eax
  2429.         call    extfsReadFileBlock
  2430.         pop     eax
  2431.         jnc     @f
  2432.         mov     edx, [esp+4]
  2433.         push    eax
  2434.         call    extfsEraseFileBlock
  2435.         pop     edi
  2436.         jc      .error_inode_size
  2437.         mov     eax, edi
  2438. @@:
  2439.         push    ecx
  2440.         mov     edi, [ebp+EXTFS.mainBlockBuffer]
  2441.         rep movsb
  2442.         pop     ecx
  2443.         call    extfsWriteFileBlock
  2444.         jc      .error_inode_size
  2445.         add     [esp], ecx
  2446.         xor     ecx, ecx
  2447. .error_inode_size:
  2448.         mov     [esp+12], eax
  2449. .write_inode:
  2450.         lea     ebx, [ebp+EXTFS.tempInodeBuffer]
  2451.         pop     [ebx+INODE.fileSize]
  2452.         pop     eax
  2453.         call    writeInode
  2454.         pop     ebx
  2455.         mov     ebx, [ebx+12]
  2456.         sub     ebx, ecx
  2457.         test    eax, eax
  2458.         jz      @f
  2459.         mov     [esp], eax
  2460. @@:
  2461.         call    writeSuperblock
  2462.         mov     esi, [ebp+PARTITION.Disk]
  2463.         call    disk_sync
  2464. @@:
  2465.         call    ext_unlock
  2466.         pop     eax
  2467.         ret
  2468.  
  2469. .error2:
  2470.         pop     ebx
  2471. .error:
  2472.         pop     ebx ebx
  2473.         push    eax
  2474.         jmp     @b
  2475.  
  2476. ;----------------------------------------------------------------
  2477. ext_SetFileEnd:
  2478.         call    extfsWritingInit
  2479.         pushd   [ebx+4]
  2480.         call    findInode
  2481.         pop     ecx
  2482.         jc      @f
  2483.         lea     edx, [ebp+EXTFS.mainInodeBuffer]
  2484.         movi    eax, ERROR_ACCESS_DENIED
  2485.         cmp     [edx+INODE.accessMode], FLAG_FILE
  2486.         jnz     @f      ; not a file
  2487.         mov     eax, esi
  2488.         call    extfsExtendFile
  2489.         jc      @f
  2490.         mov     eax, esi
  2491.         call    extfsTruncateFile
  2492.         jc      @f
  2493.         mov     eax, esi
  2494.         lea     ebx, [ebp+EXTFS.tempInodeBuffer]
  2495.         call    writeInode
  2496. @@:
  2497.         push    eax
  2498.         call    writeSuperblock
  2499.         mov     esi, [ebp+PARTITION.Disk]
  2500.         call    disk_sync
  2501.         call    ext_unlock
  2502.         pop     eax
  2503.         ret
  2504.