Subversion Repositories Kolibri OS

Rev

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