Subversion Repositories Kolibri OS

Rev

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