Subversion Repositories Kolibri OS

Rev

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