Subversion Repositories Kolibri OS

Rev

Rev 6462 | Rev 6471 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2. ;;                                                              ;;
  3. ;; Copyright (C) KolibriOS team 2004-2016. All rights reserved. ;;
  4. ;;  Distributed under terms of the GNU General Public License.  ;;
  5. ;;                                                              ;;
  6. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  7.  
  8. $Revision: 6468 $
  9.  
  10. ; NTFS external functions
  11. ;   in:
  12. ; ebx -> parameter structure of sysfunc 70
  13. ; ebp -> NTFS structure
  14. ; esi -> path string
  15. ;   out:
  16. ; eax, ebx = return values for sysfunc 70
  17. iglobal
  18. align 4
  19. ntfs_user_functions:
  20.         dd      ntfs_free
  21.         dd      (ntfs_user_functions_end - ntfs_user_functions - 4) / 4
  22.         dd      ntfs_ReadFile
  23.         dd      ntfs_ReadFolder
  24.         dd      ntfs_CreateFile
  25.         dd      ntfs_WriteFile
  26.         dd      ntfs_SetFileEnd
  27.         dd      ntfs_GetFileInfo
  28.         dd      ntfs_SetFileInfo
  29.         dd      0
  30.         dd      ntfs_Delete
  31.         dd      ntfs_CreateFolder
  32. ntfs_user_functions_end:
  33. endg
  34.  
  35. ; Basic concepts:
  36. ; File is a FileRecord in the $MFT.
  37. ; $MFT is a file, that consists of FileRecords and starts with FileRecord of itself.
  38. ; FileRecord (FILE) consists of a header and attributes.
  39. ; Attribute consists of a header and a body.
  40. ; Attribute's body can be inside (resident) or outside of FileRecord.
  41. ; File's data is a body of $Data (80h) attribute.
  42. ; FileRecords is a data of the $MFT file.
  43. ; Directory is a file, that consists of index nodes.
  44. ; Resident index node is always located in a body of $IndexRoot (90h) attribute.
  45. ; Body of $IndexAllocation (A0h) attribute is always non resident
  46. ;  and consists of IndexRecords.
  47. ; IndexRecord (INDX) consists of a header and an index node.
  48. ; Index node consists of a header and indexes.
  49. ; Index consists of a header and a copy of indexed attribute's body.
  50. ; Directories index $Filename (30h) attribute of all existing files.
  51. ; $IndexRoot and $IndexAllocation attributes of a directory has a name — $I30.
  52.  
  53. ; Offsets:
  54.     ; record header
  55. magic = 0
  56. updateSequenceOffset = 4
  57. updateSequenceSize = 6
  58.     ; FileRecord header
  59. reuseCounter = 16
  60. hardLinkCounter = 12h
  61. attributeOffset = 14h
  62. recordFlags = 16h
  63. recordRealSize = 18h
  64. recordAllocatedSize = 1ch
  65. baseRecordReference = 20h       ; for auxiliary records
  66. baseRecordReuse = 26h
  67. newAttributeID = 28h
  68.     ; attribute header
  69. attributeType = 0
  70. sizeWithHeader = 4
  71. nonResidentFlag = 8
  72. nameLength = 9
  73. nameOffset = 10
  74. attributeFlags = 12
  75. attributeID = 14
  76.     ; resident attribute header
  77. sizeWithoutHeader = 10h
  78. attributeOffset = 14h
  79. indexedFlag = 16h
  80.     ; non resident attribute header
  81. firstVCN = 10h
  82. lastVCN = 18h
  83. dataRunsOffset = 20h
  84. attributeAllocatedSize = 28h
  85. attributeRealSize = 30h
  86. initialDataSize = 38h
  87.     ; $IndexRoot
  88. indexedAttributesType = 0
  89. collationRule = 4
  90. indexRecordSize = 8
  91. indexRecordSizeClus = 12        ; in sectors if less than one cluster
  92. rootNode = 16
  93.     ; IndexRecord header
  94. recordVCN = 16
  95. recordNode = 18h
  96.     ; node header
  97. indexOffset = 0
  98. nodeRealSize = 4
  99. nodeAllocatedSize = 8
  100. nonLeafFlag = 12
  101.     ; $Filename index
  102. fileRecordReference = 0
  103. fileReferenceReuse = 6
  104. indexAllocatedSize = 8
  105. indexRawSize = 10
  106. indexFlags = 12
  107. directoryRecordReference = 16
  108. directoryReferenceReuse = 16h
  109. fileCreated = 18h
  110. fileModified = 20h
  111. recordModified = 28h
  112. fileAccessed = 30h
  113. fileAllocatedSize = 38h
  114. fileRealSize = 40h
  115. fileFlags = 48h
  116. fileNameLength = 50h
  117. namespace = 51h
  118. fileName = 52h
  119.  
  120. struct NTFS PARTITION
  121. Lock                MUTEX   ; Currently operations with one partition
  122. ; can not be executed in parallel since the legacy code is not ready.
  123. sectors_per_cluster dd  ?
  124. mft_cluster         dd  ?   ; location
  125. mftmirr_cluster     dd  ?   ; location
  126. frs_size            dd  ?   ; in bytes
  127. frs_buffer          dd  ?   ; MFT fileRecord buffer
  128. mft_retrieval_end   dd  ?
  129. mftSize             dd  ?   ; in sectors
  130. cur_index_size      dd  ?   ; in sectors
  131. cur_index_buf       dd  ?   ; index node buffer
  132. secondIndexBuffer   dd  ?
  133. BitmapBuffer        dd  ?
  134. BitmapTotalSize     dd  ?   ; bytes reserved
  135. BitmapSize          dd  ?   ; bytes readen
  136. BitmapLocation      dd  ?   ; starting sector
  137. BitmapStart         dd  ?   ; first byte after area, reserved for MFT
  138. mftBitmapBuffer     dd  ?   ; one cluster
  139. mftBitmapSize       dd  ?   ; bytes readen
  140. mftBitmapLocation   dd  ?   ; starting sector
  141.  
  142. attr_size           dq  ?
  143. attr_offs           dd  ?
  144. attr_list           dd  ?
  145. attr_iBaseRecord    dd  ?
  146. cur_attr            dd  ?   ; attribute type
  147. cur_iRecord         dd  ?   ; number of fileRecord in MFT
  148. cur_offs            dd  ?   ; attribute VCN in sectors
  149. cur_size            dd  ?   ; max sectors to read
  150. cur_buf             dd  ?
  151. cur_read            dd  ?   ; bytes readen
  152. cur_tail            dd  ?
  153. cur_subnode_size    dd  ?
  154. LastRead            dd  ?   ; last readen block of sectors
  155. mftLastRead         dd  ?
  156. rootLastRead        dd  ?
  157. nodeLastRead        dd  ?
  158. indexRoot           dd  ?
  159. indexPointer        dd  ?
  160. newRecord           dd  ?
  161. fileDataStart       dd  ?   ; starting cluster
  162. fileDataSize        dd  ?   ; in clusters
  163. fileDataBuffer      dd  ?
  164. fileRealSize        dd  ?   ; in bytes
  165. fragmentCount       db  ?
  166. bCanContinue        db  ?
  167. bFolder             db  ?
  168. bWriteAttr          db  ?   ; Warning: Don't forget to turn off!!!
  169.  
  170. align 256
  171. mft_retrieval       rb  768
  172. attrlist_buf        rb  1024
  173. attrlist_mft_buf    rb  1024
  174. bitmap_buf          rb  1024
  175. ends
  176.  
  177. ntfs_test_bootsec:
  178. ; in: ebx -> buffer, edx = size of partition
  179. ; out: CF=1 -> invalid
  180. ; 1. Name=='NTFS    '
  181.         cmp     dword [ebx+3], 'NTFS'
  182.         jnz     .no
  183.         cmp     dword [ebx+7], '    '
  184.         jnz     .no
  185. ; 2. Number of bytes per sector is the same as for physical device
  186. ; (that is, 0x200 for hard disk)
  187.         cmp     word [ebx+11], 0x200
  188.         jnz     .no
  189. ; 3. Number of sectors per cluster must be power of 2
  190.         movzx   eax, byte [ebx+13]
  191.         dec     eax
  192.         js      .no
  193.         test    al, [ebx+13]
  194.         jnz     .no
  195. ; 4. FAT parameters must be zero
  196.         cmp     word [ebx+14], 0
  197.         jnz     .no
  198.         cmp     dword [ebx+16], 0
  199.         jnz     .no
  200.         cmp     byte [ebx+20], 0
  201.         jnz     .no
  202.         cmp     word [ebx+22], 0
  203.         jnz     .no
  204.         cmp     dword [ebx+32], 0
  205.         jnz     .no
  206. ; 5. Number of sectors <= partition size
  207.         cmp     dword [ebx+0x2C], 0
  208.         ja      .no
  209.         cmp     [ebx+0x28], edx
  210.         ja      .no
  211. ; 6. $MFT and $MFTMirr clusters must be within partition
  212.         cmp     dword [ebx+0x34], 0
  213.         ja      .no
  214.         push    edx
  215.         movzx   eax, byte [ebx+13]
  216.         mul     dword [ebx+0x30]
  217.         test    edx, edx
  218.         pop     edx
  219.         jnz     .no
  220.         cmp     eax, edx
  221.         ja      .no
  222.         cmp     dword [ebx+0x3C], 0
  223.         ja      .no
  224.         push    edx
  225.         movzx   eax, byte [ebx+13]
  226.         mul     dword [ebx+0x38]
  227.         test    edx, edx
  228.         pop     edx
  229.         jnz     .no
  230.         cmp     eax, edx
  231.         ja      .no
  232. ; 7. Clusters per FRS must be either power of 2 or between -31 and -9
  233.         movsx   eax, byte [ebx+0x40]
  234.         cmp     al, -31
  235.         jl      .no
  236.         cmp     al, -9
  237.         jle     @f
  238.         dec     eax
  239.         js      .no
  240.         test    [ebx+0x40], al
  241.         jnz     .no
  242. @@:         ; 8. Same for clusters per IndexAllocationBuffer
  243.         movsx   eax, byte [ebx+0x44]
  244.         cmp     al, -31
  245.         jl      .no
  246.         cmp     al, -9
  247.         jle     @f
  248.         dec     eax
  249.         js      .no
  250.         test    [ebx+0x44], al
  251.         jnz     .no
  252. @@:         ; OK, this is correct NTFS bootsector
  253.         clc
  254.         ret
  255. .no:        ; No, this bootsector isn't NTFS
  256.         stc
  257.         ret
  258.  
  259. ; Mount if it's a valid NTFS partition.
  260. ntfs_create_partition:
  261. ;   in:
  262. ; ebp -> PARTITION structure
  263. ; ebx -> boot sector
  264. ; ebx+512 -> buffer
  265. ;   out:
  266. ; eax -> NTFS structure, 0 = not NTFS
  267.         cmp     dword [esi+DISK.MediaInfo.SectorSize], 512
  268.         jnz     .nope
  269.         mov     edx, dword [ebp+PARTITION.Length]
  270.         cmp     dword [esp+4], 0
  271.         jz      .boot_read_ok
  272.         add     ebx, 512
  273.         lea     eax, [edx-1]
  274.         call    fs_read32_sys
  275.         test    eax, eax
  276.         jnz     @f
  277.         call    ntfs_test_bootsec
  278.         jnc     .ntfs_setup
  279. @@:
  280.         mov     eax, edx
  281.         shr     eax, 1
  282.         call    fs_read32_sys
  283.         test    eax, eax
  284.         jnz     .nope
  285. .boot_read_ok:
  286.         call    ntfs_test_bootsec
  287.         jnc     .ntfs_setup
  288. .nope:
  289.         xor     eax, eax
  290.         jmp     .exit
  291.  
  292. .ntfs_setup:    ; By given bootsector, initialize some NTFS variables
  293.         stdcall kernel_alloc, 1000h
  294.         test    eax, eax
  295.         jz      .exit
  296.         mov     ecx, dword [ebp+PARTITION.FirstSector]
  297.         mov     dword [eax+NTFS.FirstSector], ecx
  298.         mov     ecx, dword [ebp+PARTITION.FirstSector+4]
  299.         mov     dword [eax+NTFS.FirstSector+4], ecx
  300.         mov     ecx, [ebp+PARTITION.Disk]
  301.         mov     [eax+NTFS.Disk], ecx
  302.         mov     [eax+NTFS.FSUserFunctions], ntfs_user_functions
  303.         mov     [eax+NTFS.bWriteAttr], 0
  304.  
  305.         push    ebx ebp esi
  306.         mov     ebp, eax
  307.         lea     ecx, [ebp+NTFS.Lock]
  308.         call    mutex_init
  309.         movzx   eax, byte [ebx+13]
  310.         mov     [ebp+NTFS.sectors_per_cluster], eax
  311.         mov     eax, [ebx+0x28]
  312.         mov     dword [ebp+NTFS.Length], eax
  313.         and     dword [ebp+NTFS.Length+4], 0
  314.         mov     eax, [ebx+0x30]
  315.         mov     [ebp+NTFS.mft_cluster], eax
  316.         mov     eax, [ebx+0x38]
  317.         mov     [ebp+NTFS.mftmirr_cluster], eax
  318.         movsx   eax, byte [ebx+0x40]
  319.         test    eax, eax
  320.         js      @f
  321.         mul     [ebp+NTFS.sectors_per_cluster]
  322.         shl     eax, 9
  323.         jmp     .1
  324.  
  325. @@:
  326.         neg     eax
  327.         mov     ecx, eax
  328.         mov     eax, 1
  329.         shl     eax, cl
  330. .1:
  331.         mov     [ebp+NTFS.frs_size], eax
  332.         stdcall kernel_alloc, eax
  333.         test    eax, eax
  334.         jz      .fail_free
  335.         mov     [ebp+NTFS.frs_buffer], eax
  336. ; read $MFT disposition
  337.         mov     eax, [ebp+NTFS.mft_cluster]
  338.         mul     [ebp+NTFS.sectors_per_cluster]
  339.         mov     ecx, [ebp+NTFS.frs_size]
  340.         shr     ecx, 9
  341.         mov     ebx, [ebp+NTFS.frs_buffer]
  342.         call    fs_read64_sys
  343.         test    eax, eax
  344.         jnz     .usemirr
  345.         cmp     dword [ebx], 'FILE'
  346.         jnz     .usemirr
  347.         call    ntfs_restore_usa_frs
  348.         jnc     .mftok
  349. .usemirr:
  350.         mov     eax, [ebp+NTFS.mftmirr_cluster]
  351.         mul     [ebp+NTFS.sectors_per_cluster]
  352.         mov     ecx, [ebp+NTFS.frs_size]
  353.         shr     ecx, 9
  354.         mov     ebx, [ebp+NTFS.frs_buffer]
  355.         call    fs_read64_sys
  356.         test    eax, eax
  357.         jnz     .fail_free_frs
  358.         cmp     dword [ebx], 'FILE'
  359.         jnz     .fail_free_frs
  360.         call    ntfs_restore_usa_frs
  361.         jc      .fail_free_frs
  362. .mftok:     ; prepare $MFT retrieval information
  363. ; search for unnamed non-resident $DATA attribute
  364.         movzx   eax, word [ebx+attributeOffset]
  365.         add     eax, ebx
  366. .scandata:
  367.         cmp     dword [eax], -1
  368.         jz      .fail_free_frs
  369.         cmp     dword [eax], 0x80
  370.         jnz     @f
  371.         cmp     byte [eax+nameLength], 0
  372.         jz      .founddata
  373. @@:
  374.         add     eax, [eax+sizeWithHeader]
  375.         jmp     .scandata
  376.  
  377. .founddata:
  378.         cmp     byte [eax+nonResidentFlag], 0
  379.         jz      .fail_free_frs
  380.         movzx   esi, word [eax+dataRunsOffset]
  381.         add     esi, eax
  382.         mov     edx, [eax+attributeAllocatedSize+4]
  383.         mov     eax, [eax+attributeAllocatedSize]
  384.         shrd    eax, edx, 9
  385.         mov     [ebp+NTFS.mftSize], eax
  386.         sub     esp, 10h
  387.         lea     ecx, [ebp+NTFS.mft_retrieval]
  388.         xor     edx, edx
  389. .scanmcb:   ; load descriptions of fragments
  390.         call    ntfs_decode_mcb_entry
  391.         jnc     .scanmcbend
  392.         mov     eax, [esp]      ; block length
  393.         mov     [ecx], eax
  394.         add     edx, [esp+8]    ; block addr
  395.         mov     [ecx+4], edx
  396.         add     ecx, 8
  397.         jmp     .scanmcb
  398.  
  399. .scanmcbend:
  400.         add     esp, 10h
  401.         lea     eax, [ebp+NTFS.attrlist_buf]
  402.         cmp     eax, ecx
  403.         jc      @f
  404.         mov     eax, ecx
  405. @@:
  406.         mov     [ebp+NTFS.mft_retrieval_end], eax
  407. ; allocate index buffers
  408.         stdcall kernel_alloc, 2000h
  409.         test    eax, eax
  410.         jz      .fail_free_frs
  411.         mov     [ebp+NTFS.cur_index_buf], eax
  412.         add     eax, 1000h
  413.         mov     [ebp+NTFS.secondIndexBuffer], eax
  414.         mov     [ebp+NTFS.cur_index_size], 8
  415. ; reserve adress space for bitmap buffer and load some part of bitmap
  416.         mov     eax, dword [ebp+NTFS.Length]
  417.         xor     edx, edx
  418.         div     [ebp+NTFS.sectors_per_cluster]
  419.         shr     eax, 3
  420.         mov     [ebp+NTFS.BitmapTotalSize], eax
  421.         add     eax, 7FFFh
  422.         and     eax, not 7FFFh
  423.         push    eax
  424.         call    alloc_kernel_space
  425.         test    eax, eax
  426.         jz      .failFreeIndex
  427.         mov     [ebp+NTFS.BitmapBuffer], eax
  428.         mov     [ebp+NTFS.cur_buf], eax
  429.         mov     eax, [ebp+NTFS.BitmapTotalSize]
  430.         add     eax, [ebp+NTFS.mft_cluster]
  431.         shr     eax, 3+2        ; reserve 1/8 of partition for $MFT
  432.         shl     eax, 2
  433.         mov     [ebp+NTFS.BitmapStart], eax
  434.         shr     eax, 15
  435.         inc     eax
  436.         shl     eax, 3
  437.         push    eax
  438.         push    eax
  439.         shl     eax, 3
  440.         mov     [ebp+NTFS.cur_size], eax
  441.         call    alloc_pages
  442.         test    eax, eax
  443.         pop     ecx
  444.         jz      .failFreeBitmap
  445.         add     eax, 3
  446.         mov     ebx, [ebp+NTFS.BitmapBuffer]
  447.         call    commit_pages
  448.         mov     [ebp+NTFS.cur_iRecord], 6
  449.         mov     [ebp+NTFS.cur_attr], 0x80
  450.         mov     [ebp+NTFS.cur_offs], 0
  451.         call    ntfs_read_attr
  452.         jc      .failFreeBitmap
  453.         mov     eax, [ebp+NTFS.cur_read]
  454.         mov     [ebp+NTFS.BitmapSize], eax
  455.         mov     eax, [ebp+NTFS.LastRead]
  456.         mov     [ebp+NTFS.BitmapLocation], eax
  457. ; read MFT $BITMAP attribute
  458.         mov     eax, [ebp+NTFS.sectors_per_cluster]
  459.         mov     [ebp+NTFS.cur_size], eax
  460.         shl     eax, 9
  461.         stdcall kernel_alloc, eax
  462.         test    eax, eax
  463.         jz      .failFreeBitmap
  464.         mov     [ebp+NTFS.mftBitmapBuffer], eax
  465.         mov     [ebp+NTFS.cur_buf], eax
  466.         mov     [ebp+NTFS.cur_iRecord], 0
  467.         mov     [ebp+NTFS.cur_attr], 0xB0
  468.         mov     [ebp+NTFS.cur_offs], 0
  469.         call    ntfs_read_attr
  470.         mov     eax, [ebp+NTFS.cur_read]
  471.         cmp     eax, 4
  472.         jc      .failFreeBitmapMFT
  473.         mov     ecx, [ebp+NTFS.attr_offs]
  474.         cmp     byte [ecx+nonResidentFlag], 1
  475.         jnz     .failFreeBitmapMFT
  476.         mov     [ebp+NTFS.mftBitmapSize], eax
  477.         mov     eax, [ebp+NTFS.LastRead]
  478.         mov     [ebp+NTFS.mftBitmapLocation], eax
  479.  
  480.         mov     eax, ebp
  481. .pop_exit:
  482.         pop     esi ebp ebx
  483. .exit:
  484.         cmp     dword [esp+4], 0
  485.         jz      @f
  486.         sub     ebx, 512
  487. @@:
  488.         ret
  489.  
  490. .failFreeBitmapMFT:
  491.         stdcall kernel_free, [ebp+NTFS.mftBitmapBuffer]
  492. .failFreeBitmap:
  493.         stdcall kernel_free, [ebp+NTFS.BitmapBuffer]
  494. .failFreeIndex:
  495.         mov     eax, [ebp+NTFS.cur_index_buf]
  496.         cmp     eax, [ebp+NTFS.secondIndexBuffer]
  497.         jc      @f
  498.         mov     eax, [ebp+NTFS.secondIndexBuffer]
  499. @@:
  500.         stdcall kernel_free, eax
  501. .fail_free_frs:
  502.         stdcall kernel_free, [ebp+NTFS.frs_buffer]
  503. .fail_free:
  504.         stdcall kernel_free, ebp
  505.         xor     eax, eax
  506.         jmp     .pop_exit
  507.  
  508. ntfs_free:
  509.         push    ebx
  510.         mov     ebx, eax
  511.         stdcall kernel_free, [ebx+NTFS.frs_buffer]
  512.         stdcall kernel_free, [ebx+NTFS.mftBitmapBuffer]
  513.         stdcall kernel_free, [ebx+NTFS.BitmapBuffer]
  514.         mov     eax, [ebx+NTFS.cur_index_buf]
  515.         cmp     eax, [ebx+NTFS.secondIndexBuffer]
  516.         jc      @f
  517.         mov     eax, [ebx+NTFS.secondIndexBuffer]
  518. @@:
  519.         stdcall kernel_free, eax
  520.         stdcall kernel_free, ebx
  521.         pop     ebx
  522.         ret
  523.  
  524. ntfs_lock:
  525.         lea     ecx, [ebp+NTFS.Lock]
  526.         jmp     mutex_lock
  527.  
  528. ntfs_unlock:
  529.         lea     ecx, [ebp+NTFS.Lock]
  530.         jmp     mutex_unlock
  531.  
  532. ntfs_read_attr:
  533. ; [ebp+NTFS.bWriteAttr]=1 -> write attribute
  534. ;   in:
  535. ; [ebp+NTFS.cur_iRecord] = number of fileRecord
  536. ; [ebp+NTFS.cur_attr] = attribute type
  537. ; [ebp+NTFS.cur_offs] = attribute VCN in sectors
  538. ; [ebp+NTFS.cur_buf] -> buffer for data
  539. ; [ebp+NTFS.cur_size] = max sectors to read
  540. ;   out:
  541. ; [ebp+NTFS.cur_read] = bytes readen
  542. ; CF=1 -> failed, eax = disk error code, eax=0 -> something with FS
  543.         xor     eax, eax
  544.         pushad
  545.         and     [ebp+NTFS.cur_read], 0
  546.         cmp     [ebp+NTFS.cur_iRecord], 0
  547.         jnz     .nomft
  548.         cmp     [ebp+NTFS.cur_attr], 0x80
  549.         jnz     .nomft
  550. ; precalculated part of $Mft $DATA
  551.         mov     eax, [ebp+NTFS.cur_offs]
  552.         xor     edx, edx
  553.         div     [ebp+NTFS.sectors_per_cluster]
  554.         mov     ebx, edx
  555.         mov     [ebp+NTFS.fragmentCount], 0
  556. ; eax = VCN, ebx = offset in sectors from beginning of cluster
  557.         lea     esi, [ebp+NTFS.mft_retrieval]
  558.         sub     esi, 8
  559. .mftscan:
  560.         add     esi, 8
  561.         cmp     esi, [ebp+NTFS.mft_retrieval_end]
  562.         jz      .nomft
  563.         mov     ecx, [esi+4]
  564.         sub     eax, [esi]
  565.         jnc     .mftscan
  566.         add     ecx, eax
  567.         add     ecx, [esi]
  568.         neg     eax
  569.         mul     [ebp+NTFS.sectors_per_cluster]
  570.         xchg    eax, ecx
  571.         mul     [ebp+NTFS.sectors_per_cluster]
  572.         sub     ecx, ebx
  573.         add     eax, ebx
  574.         mov     ebx, [ebp+NTFS.cur_buf]
  575.         cmp     ecx, [ebp+NTFS.cur_size]
  576.         jb      @f
  577.         mov     ecx, [ebp+NTFS.cur_size]
  578. @@:
  579.         mov     [ebp+NTFS.LastRead], eax
  580.         mov     edi, ecx
  581.         call    fs_read64_sys
  582.         test    eax, eax
  583.         jnz     .errret
  584.         sub     [ebp+NTFS.cur_size], edi
  585.         add     [ebp+NTFS.cur_offs], edi
  586.         shl     edi, 9
  587.         add     [ebp+NTFS.cur_read], edi
  588.         add     [ebp+NTFS.cur_buf], edi
  589.         inc     [ebp+NTFS.fragmentCount]
  590.         xor     eax, eax
  591.         xor     ebx, ebx
  592.         cmp     [ebp+NTFS.cur_size], eax
  593.         jz      @f
  594.         jmp     .mftscan
  595.  
  596. .errret2_pop:
  597.         xor     eax, eax
  598. .errret_pop:
  599.         pop     ecx
  600.         pop     ecx
  601. .errret:
  602.         mov     [esp+28], eax
  603.         stc
  604. @@:
  605.         popad
  606.         ret
  607.  
  608. .nomft:
  609. ; 1. Read file record.
  610. ; N.B. This will do recursive call of read_attr for $MFT::$Data.
  611.         mov     eax, [ebp+NTFS.cur_iRecord]
  612.         and     [ebp+NTFS.attr_list], 0
  613.         or      dword [ebp+NTFS.attr_size+4], -1
  614.         or      [ebp+NTFS.attr_iBaseRecord], -1
  615.         call    ntfs_read_file_record
  616.         jc      .errret
  617. ; 2. Find required attribute.
  618.         mov     eax, [ebp+NTFS.frs_buffer]
  619. ; a) For auxiliary records, read base record.
  620. ; If base record is present, base iRecord may be 0 (for $Mft),
  621. ; but SequenceNumber is nonzero.
  622.         cmp     word [eax+baseRecordReuse], 0
  623.         jz      @f
  624.         mov     eax, [eax+baseRecordReference]
  625. .beginfindattr:
  626.         call    ntfs_read_file_record
  627.         jc      .errret
  628.         jmp     @f
  629.  
  630. .newAttribute:
  631.         pushad
  632.         and     [ebp+NTFS.cur_read], 0
  633. @@:
  634. ; b) Scan for required attribute and for $ATTR_LIST
  635.         mov     eax, [ebp+NTFS.frs_buffer]
  636.         movzx   ecx, word [eax+attributeOffset]
  637.         add     eax, ecx
  638.         mov     ecx, [ebp+NTFS.cur_attr]
  639.         and     [ebp+NTFS.attr_offs], 0
  640. .scanattr:
  641.         cmp     dword [eax], -1
  642.         jz      .scandone
  643.         cmp     dword [eax], ecx
  644.         jz      .okattr
  645.         cmp     [ebp+NTFS.attr_iBaseRecord], -1
  646.         jnz     .scancont
  647.         cmp     dword [eax], 0x20       ; $ATTR_LIST
  648.         jnz     .scancont
  649.         mov     [ebp+NTFS.attr_list], eax
  650.         jmp     .scancont
  651.  
  652. .okattr:
  653. ; ignore named $DATA attributes (aka NTFS streams)
  654.         cmp     ecx, 0x80
  655.         jnz     @f
  656.         cmp     byte [eax+nameLength], 0
  657.         jnz     .scancont
  658. @@:
  659.         mov     [ebp+NTFS.attr_offs], eax
  660. .scancont:
  661.         add     eax, [eax+sizeWithHeader]
  662.         jmp     .scanattr
  663.  
  664. .continue:
  665.         pushad
  666.         and     [ebp+NTFS.cur_read], 0
  667. .scandone:
  668. ; c) Check for required offset and length
  669.         mov     ecx, [ebp+NTFS.attr_offs]
  670.         jecxz   .noattr
  671.         push    [ebp+NTFS.cur_size]
  672.         push    [ebp+NTFS.cur_read]
  673.         call    .doreadattr
  674.         pop     edx
  675.         pop     ecx
  676.         jc      .ret
  677.         cmp     [ebp+NTFS.bCanContinue], 0
  678.         jz      .ret
  679.         sub     edx, [ebp+NTFS.cur_read]
  680.         neg     edx
  681.         shr     edx, 9
  682.         sub     ecx, edx
  683.         mov     [ebp+NTFS.cur_size], ecx
  684.         jz      .ret
  685. .noattr:
  686.         cmp     [ebp+NTFS.cur_attr], 0x20
  687.         jz      @f
  688.         mov     ecx, [ebp+NTFS.attr_list]
  689.         test    ecx, ecx
  690.         jnz     .lookattr
  691.         and     dword [esp+28], 0
  692.         cmp     [ebp+NTFS.attr_offs], 1     ; define CF
  693. .ret:
  694.         popad
  695.         ret
  696.  
  697. .lookattr:
  698. ; required attribute or required offset was not found in base record;
  699. ; it may be present in auxiliary records;
  700. ; scan $ATTR_LIST
  701.         mov     eax, [ebp+NTFS.attr_iBaseRecord]
  702.         cmp     eax, -1
  703.         jz      @f
  704.         call    ntfs_read_file_record
  705.         jc      .errret
  706.         or      [ebp+NTFS.attr_iBaseRecord], -1
  707. @@:
  708.         push    [ebp+NTFS.cur_offs]
  709.         push    [ebp+NTFS.cur_size]
  710.         push    [ebp+NTFS.cur_read]
  711.         push    [ebp+NTFS.cur_buf]
  712.         push    dword [ebp+NTFS.attr_size]
  713.         push    dword [ebp+NTFS.attr_size+4]
  714.         or      dword [ebp+NTFS.attr_size+4], -1
  715.         and     [ebp+NTFS.cur_offs], 0
  716.         mov     [ebp+NTFS.cur_size], 2
  717.         and     [ebp+NTFS.cur_read], 0
  718.         lea     eax, [ebp+NTFS.attrlist_buf]
  719.         cmp     [ebp+NTFS.cur_iRecord], 0
  720.         jnz     @f
  721.         lea     eax, [ebp+NTFS.attrlist_mft_buf]
  722. @@:
  723.         mov     [ebp+NTFS.cur_buf], eax
  724.         push    eax
  725.         call    .doreadattr
  726.         pop     esi
  727.         mov     edx, 1
  728.         pop     dword [ebp+NTFS.attr_size+4]
  729.         pop     dword [ebp+NTFS.attr_size]
  730.         mov     ecx, [ebp+NTFS.cur_read]
  731.         pop     [ebp+NTFS.cur_buf]
  732.         pop     [ebp+NTFS.cur_read]
  733.         pop     [ebp+NTFS.cur_size]
  734.         pop     [ebp+NTFS.cur_offs]
  735.         jc      .errret
  736.         or      edi, -1
  737.         lea     ecx, [ecx+esi-1Ah]
  738. .scanliststart:
  739.         push    ecx
  740.         mov     eax, [ebp+NTFS.cur_attr]
  741. .scanlist:
  742.         cmp     esi, [esp]
  743.         jae     .scanlistdone
  744.         cmp     eax, [esi]
  745.         jz      @f
  746. .scanlistcont:
  747.         movzx   ecx, word [esi+4]
  748.         add     esi, ecx
  749.         jmp     .scanlist
  750.  
  751. @@:
  752. ; ignore named $DATA attributes (aka NTFS streams)
  753.         cmp     eax, 0x80
  754.         jnz     @f
  755.         cmp     byte [esi+6], 0
  756.         jnz     .scanlistcont
  757. @@:
  758.         push    eax
  759.         mov     eax, [esi+8]
  760.         test    eax, eax
  761.         jnz     .testf
  762.         cmp     dword [ebp+NTFS.attr_size+4], -1
  763.         jnz     .testfz
  764. ; if attribute is in auxiliary records, its size is defined only in first
  765.         mov     eax, [esi+10h]
  766.         call    ntfs_read_file_record
  767.         jc      .errret_pop
  768.         mov     eax, [ebp+NTFS.frs_buffer]
  769.         movzx   ecx, word [eax+14h]
  770.         add     eax, ecx
  771.         mov     ecx, [ebp+NTFS.cur_attr]
  772. @@:
  773.         cmp     dword [eax], -1
  774.         jz      .errret2_pop
  775.         cmp     dword [eax], ecx
  776.         jz      @f
  777. .l1:
  778.         add     eax, [eax+4]
  779.         jmp     @b
  780.  
  781. @@:
  782.         cmp     eax, 0x80
  783.         jnz     @f
  784.         cmp     byte [eax+9], 0
  785.         jnz     .l1
  786. @@:
  787.         cmp     byte [eax+8], 0
  788.         jnz     .sdnores
  789.         mov     eax, [eax+10h]
  790.         mov     dword [ebp+NTFS.attr_size], eax
  791.         and     dword [ebp+NTFS.attr_size+4], 0
  792.         jmp     .testfz
  793.  
  794. .sdnores:
  795.         mov     ecx, [eax+30h]
  796.         mov     dword [ebp+NTFS.attr_size], ecx
  797.         mov     ecx, [eax+34h]
  798.         mov     dword [ebp+NTFS.attr_size+4], ecx
  799. .testfz:
  800.         xor     eax, eax
  801. .testf:
  802.         imul    eax, [ebp+NTFS.sectors_per_cluster]
  803.         cmp     eax, [ebp+NTFS.cur_offs]
  804.         pop     eax
  805.         ja      @f
  806.         mov     edi, [esi+10h]  ; keep previous iRecord
  807.         jmp     .scanlistcont
  808.  
  809. @@:
  810.         pop     ecx
  811. .scanlistfound:
  812.         cmp     edi, -1
  813.         jz      .ret
  814.         mov     eax, [ebp+NTFS.cur_iRecord]
  815.         mov     [ebp+NTFS.attr_iBaseRecord], eax
  816.         mov     eax, edi
  817.         jmp     .beginfindattr
  818.  
  819. .scanlistdone:
  820.         pop     ecx
  821.         sub     ecx, ebp
  822.         sub     ecx, NTFS.attrlist_buf-1Ah
  823.         cmp     [ebp+NTFS.cur_iRecord], 0
  824.         jnz     @f
  825.         sub     ecx, NTFS.attrlist_mft_buf-NTFS.attrlist_buf
  826. @@:
  827.         cmp     ecx, 0x400
  828.         jnz     .scanlistfound
  829.         inc     edx
  830.         push    esi edi
  831.         lea     esi, [ebp+NTFS.attrlist_buf+0x200]
  832.         lea     edi, [ebp+NTFS.attrlist_buf]
  833.         cmp     [ebp+NTFS.cur_iRecord], 0
  834.         jnz     @f
  835.         lea     esi, [ebp+NTFS.attrlist_mft_buf+0x200]
  836.         lea     edi, [ebp+NTFS.attrlist_mft_buf]
  837. @@:
  838.         mov     ecx, 0x200/4
  839.         rep movsd
  840.         mov     eax, edi
  841.         pop     edi esi
  842.         sub     esi, 0x200
  843.         push    [ebp+NTFS.cur_offs]
  844.         push    [ebp+NTFS.cur_size]
  845.         push    [ebp+NTFS.cur_read]
  846.         push    [ebp+NTFS.cur_buf]
  847.         push    dword [ebp+NTFS.attr_size]
  848.         push    dword [ebp+NTFS.attr_size+4]
  849.         or      dword [ebp+NTFS.attr_size+4], -1
  850.         mov     [ebp+NTFS.cur_offs], edx
  851.         mov     [ebp+NTFS.cur_size], 1
  852.         and     [ebp+NTFS.cur_read], 0
  853.         mov     [ebp+NTFS.cur_buf], eax
  854.         mov     ecx, [ebp+NTFS.attr_list]
  855.         push    esi edx edi
  856.         call    .doreadattr
  857.         pop     edi edx esi
  858.         mov     ecx, [ebp+NTFS.cur_read]
  859.         pop     dword [ebp+NTFS.attr_size+4]
  860.         pop     dword [ebp+NTFS.attr_size]
  861.         pop     [ebp+NTFS.cur_buf]
  862.         pop     [ebp+NTFS.cur_read]
  863.         pop     [ebp+NTFS.cur_size]
  864.         pop     [ebp+NTFS.cur_offs]
  865.         jc      .errret
  866.         lea     ecx, [ecx+ebp+NTFS.attrlist_buf+0x200-0x1A]
  867.         cmp     [ebp+NTFS.cur_iRecord], 0
  868.         jnz     .scanliststart
  869.         add     ecx, NTFS.attrlist_mft_buf-NTFS.attrlist_buf
  870.         jmp     .scanliststart
  871.  
  872. .doreadattr:
  873.         mov     [ebp+NTFS.bCanContinue], 0
  874.         cmp     byte [ecx+nonResidentFlag], 0
  875.         jnz     .nonresident
  876.         mov     eax, [ecx+sizeWithoutHeader]
  877.         mov     esi, eax
  878.         mov     edx, [ebp+NTFS.cur_offs]
  879.         shr     eax, 9
  880.         cmp     eax, edx
  881.         jb      .okret
  882.         shl     edx, 9
  883.         sub     esi, edx
  884.         movzx   eax, word [ecx+attributeOffset]
  885.         add     edx, eax
  886.         add     edx, ecx        ; edx -> data
  887.         mov     eax, [ebp+NTFS.cur_size]
  888.         cmp     eax, (0xFFFFFFFF shr 9)+1
  889.         jbe     @f
  890.         mov     eax, (0xFFFFFFFF shr 9)+1
  891. @@:
  892.         shl     eax, 9
  893.         cmp     eax, esi
  894.         jbe     @f
  895.         mov     eax, esi
  896. @@:
  897. ; eax = length, edx -> data
  898.         mov     [ebp+NTFS.cur_read], eax
  899.         mov     ecx, eax
  900.         mov     eax, edx
  901.         mov     ebx, [ebp+NTFS.cur_buf]
  902.         call    memmove
  903.         and     [ebp+NTFS.cur_size], 0      ; CF=0
  904.         ret
  905.  
  906. .nonresident:
  907. ; Not all auxiliary records contain correct FileSize info
  908.         mov     eax, dword [ebp+NTFS.attr_size]
  909.         mov     edx, dword [ebp+NTFS.attr_size+4]
  910.         cmp     edx, -1
  911.         jnz     @f
  912.         mov     eax, [ecx+attributeRealSize]
  913.         mov     edx, [ecx+attributeRealSize+4]
  914.         mov     dword [ebp+NTFS.attr_size], eax
  915.         mov     dword [ebp+NTFS.attr_size+4], edx
  916. @@:
  917.         add     eax, 0x1FF
  918.         adc     edx, 0
  919.         shrd    eax, edx, 9
  920.         sub     eax, [ebp+NTFS.cur_offs]
  921.         ja      @f
  922. ; return with nothing read
  923.         and     [ebp+NTFS.cur_size], 0
  924. .okret:
  925.         clc
  926.         ret
  927.  
  928. @@:
  929. ; reduce read length
  930.         and     [ebp+NTFS.cur_tail], 0
  931.         cmp     [ebp+NTFS.cur_size], eax
  932.         jb      @f
  933.         mov     [ebp+NTFS.cur_size], eax
  934.         mov     eax, dword [ebp+NTFS.attr_size]
  935.         and     eax, 0x1FF
  936.         mov     [ebp+NTFS.cur_tail], eax
  937. @@:
  938.         mov     eax, [ebp+NTFS.cur_offs]
  939.         xor     edx, edx
  940.         div     [ebp+NTFS.sectors_per_cluster]
  941.         sub     eax, [ecx+firstVCN]
  942.         jb      .okret
  943.         mov     ebx, edx
  944. ; eax = starting cluster, ebx = sector in the cluster
  945.         cmp     [ebp+NTFS.cur_attr], 0x80
  946.         jnz     .sys
  947.         cmp     [ebp+NTFS.cur_iRecord], 0
  948.         jz      .sys
  949.         push    fs_read64_app
  950.         cmp     [ebp+NTFS.bWriteAttr], 1
  951.         jnz     @f
  952.         mov     dword[esp], fs_write64_app
  953.         jmp     @f
  954.  
  955. .sys:
  956.         push    fs_read64_sys
  957. @@:
  958.         sub     esp, 10h
  959.         movzx   esi, word [ecx+dataRunsOffset]
  960.         add     esi, ecx
  961.         xor     edi, edi
  962.         mov     [ebp+NTFS.fragmentCount], 0
  963. .readloop:
  964.         call    ntfs_decode_mcb_entry
  965.         jnc     .break
  966.         add     edi, [esp+8]
  967.         sub     eax, [esp]
  968.         jae     .readloop
  969.         mov     ecx, edi
  970.         add     ecx, eax
  971.         add     ecx, [esp]
  972.         neg     eax
  973.         mul     [ebp+NTFS.sectors_per_cluster]
  974.         xchg    eax, ecx
  975.         mul     [ebp+NTFS.sectors_per_cluster]
  976.         sub     ecx, ebx
  977.         add     eax, ebx
  978.         mov     ebx, [ebp+NTFS.cur_buf]
  979.         cmp     ecx, [ebp+NTFS.cur_size]
  980.         jb      @f
  981.         mov     ecx, [ebp+NTFS.cur_size]
  982. @@:
  983.         mov     [ebp+NTFS.LastRead], eax
  984.         push    ecx
  985.         call    dword[esp+14h]
  986.         pop     ecx
  987.         test    eax, eax
  988.         jnz     .errread2
  989.         sub     [ebp+NTFS.cur_size], ecx
  990.         add     [ebp+NTFS.cur_offs], ecx
  991.         shl     ecx, 9
  992.         add     [ebp+NTFS.cur_read], ecx
  993.         add     [ebp+NTFS.cur_buf], ecx
  994.         inc     [ebp+NTFS.fragmentCount]
  995.         xor     eax, eax
  996.         xor     ebx, ebx
  997.         cmp     [ebp+NTFS.cur_size], 0
  998.         jnz     .readloop
  999.         add     esp, 14h
  1000.         mov     eax, [ebp+NTFS.cur_tail]
  1001.         test    eax, eax
  1002.         jz      @f
  1003.         sub     eax, 0x200
  1004.         add     [ebp+NTFS.cur_read], eax
  1005. @@:
  1006.         clc
  1007.         ret
  1008.  
  1009. .errread2:
  1010.         add     esp, 14h
  1011.         stc
  1012.         ret
  1013.  
  1014. .break:
  1015.         add     esp, 14h        ; CF=0
  1016.         mov     [ebp+NTFS.bCanContinue], 1
  1017.         ret
  1018.  
  1019. ntfs_read_file_record:
  1020. ; in: eax = iRecord
  1021. ; out: [ebp+NTFS.frs_buffer] -> file record
  1022. ; CF=1 -> failed, eax = disk error code, eax=0 -> something with FS
  1023.     ; Read attr $DATA of $Mft, starting from eax*[ebp+NTFS.frs_size]
  1024.         push    ecx edx
  1025.         mov     ecx, [ebp+NTFS.frs_size]
  1026.         mul     ecx
  1027.         shrd    eax, edx, 9
  1028.         shr     edx, 9
  1029.         jnz     .errret
  1030.         push    [ebp+NTFS.attr_iBaseRecord]
  1031.         push    [ebp+NTFS.attr_offs]
  1032.         push    [ebp+NTFS.attr_list]
  1033.         push    dword [ebp+NTFS.attr_size+4]
  1034.         push    dword [ebp+NTFS.attr_size]
  1035.         push    [ebp+NTFS.cur_iRecord]
  1036.         push    [ebp+NTFS.cur_attr]
  1037.         push    [ebp+NTFS.cur_offs]
  1038.         push    [ebp+NTFS.cur_size]
  1039.         push    [ebp+NTFS.cur_buf]
  1040.         push    [ebp+NTFS.cur_read]
  1041.         mov     [ebp+NTFS.cur_attr], 0x80   ; $DATA
  1042.         and     [ebp+NTFS.cur_iRecord], 0   ; $Mft
  1043.         mov     [ebp+NTFS.cur_offs], eax
  1044.         shr     ecx, 9
  1045.         mov     [ebp+NTFS.cur_size], ecx
  1046.         mov     eax, [ebp+NTFS.frs_buffer]
  1047.         mov     [ebp+NTFS.cur_buf], eax
  1048.         call    ntfs_read_attr
  1049.         mov     edx, [ebp+NTFS.cur_read]
  1050.         pop     [ebp+NTFS.cur_read]
  1051.         pop     [ebp+NTFS.cur_buf]
  1052.         pop     [ebp+NTFS.cur_size]
  1053.         pop     [ebp+NTFS.cur_offs]
  1054.         pop     [ebp+NTFS.cur_attr]
  1055.         pop     [ebp+NTFS.cur_iRecord]
  1056.         pop     dword [ebp+NTFS.attr_size]
  1057.         pop     dword [ebp+NTFS.attr_size+4]
  1058.         pop     [ebp+NTFS.attr_list]
  1059.         pop     [ebp+NTFS.attr_offs]
  1060.         pop     [ebp+NTFS.attr_iBaseRecord]
  1061.         jc      .ret
  1062.         cmp     edx, [ebp+NTFS.frs_size]
  1063.         jnz     .errret
  1064.         mov     eax, [ebp+NTFS.LastRead]
  1065.         mov     [ebp+NTFS.mftLastRead], eax
  1066.         mov     eax, [ebp+NTFS.frs_buffer]
  1067.         cmp     dword [eax], 'FILE'
  1068.         jnz     .errret
  1069.         push    ebx
  1070.         mov     ebx, eax
  1071.         call    ntfs_restore_usa_frs
  1072.         pop     ebx
  1073.         jc      .errret
  1074. .ret:
  1075.         pop     edx ecx
  1076.         ret
  1077.  
  1078. .errret:
  1079.         pop     edx ecx
  1080.         xor     eax, eax
  1081.         stc
  1082.         ret
  1083.  
  1084. ntfs_restore_usa_frs:
  1085.         mov     eax, [ebp+NTFS.frs_size]
  1086. ntfs_restore_usa:
  1087. ;   in:
  1088. ; ebx -> record
  1089. ; eax = size in bytes
  1090.         pushad
  1091.         shr     eax, 9
  1092.         mov     ecx, eax
  1093.         inc     eax
  1094.         cmp     [ebx+updateSequenceSize], ax
  1095.         jnz     .err
  1096.         movzx   eax, word [ebx+updateSequenceOffset]
  1097.         lea     esi, [eax+ebx]
  1098.         lodsw
  1099.         mov     edx, eax
  1100.         lea     edi, [ebx+0x1FE]
  1101. @@:
  1102.         cmp     [edi], dx
  1103.         jnz     .err
  1104.         lodsw
  1105.         stosw
  1106.         add     edi, 0x1FE
  1107.         loop    @b
  1108.         popad
  1109.         clc
  1110.         ret
  1111.  
  1112. .err:
  1113.         popad
  1114.         stc
  1115.         ret
  1116.  
  1117. ntfs_decode_mcb_entry:
  1118. ;   in:
  1119. ; esi -> MCB entry
  1120. ; esp -> buffer (16 bytes)
  1121. ;   out:
  1122. ; esi -> next MCB entry
  1123. ; esp -> data run size
  1124. ; esp+8 -> cluster (delta)
  1125. ; CF=0 -> MCB end
  1126.         push    eax ecx edi
  1127.         lea     edi, [esp+16]
  1128.         xor     eax, eax
  1129.         lodsb
  1130.         test    al, al
  1131.         jz      .end
  1132.         mov     ecx, eax
  1133.         and     ecx, 0xF
  1134.         cmp     ecx, 8
  1135.         ja      .end
  1136.         push    ecx
  1137.         rep movsb
  1138.         pop     ecx
  1139.         sub     ecx, 8
  1140.         neg     ecx
  1141.         cmp     byte [esi-1], 80h
  1142.         jae     .end
  1143.         push    eax
  1144.         xor     eax, eax
  1145.         rep stosb
  1146.         pop     ecx
  1147.         shr     ecx, 4
  1148.         cmp     ecx, 8
  1149.         ja      .end
  1150.         push    ecx
  1151.         rep movsb
  1152.         pop     ecx
  1153.         sub     ecx, 8
  1154.         neg     ecx
  1155.         cmp     byte [esi-1], 80h
  1156.         cmc
  1157.         sbb     eax, eax
  1158.         rep stosb
  1159.         stc
  1160. .end:
  1161.         pop     edi ecx eax
  1162.         ret
  1163.  
  1164. unichar_toupper:
  1165.         push    eax
  1166.         call    uni2ansi_char
  1167.         cmp     al, '_'
  1168.         jz      .unk
  1169.         add     esp, 4
  1170.         call    char_toupper
  1171.         jmp     ansi2uni_char
  1172. .unk:
  1173.         pop     eax
  1174.         ret
  1175.  
  1176. ntfs_find_lfn:
  1177. ; in: esi -> path string
  1178. ;   out:
  1179. ; [ebp+NTFS.cur_iRecord] = target fileRecord
  1180. ; eax -> target index in the node
  1181. ; [ebp+NTFS.LastRead] = target node location
  1182. ; [ebp+NTFS.indexPointer] -> index, that points the target subnode
  1183. ; [ebp+NTFS.nodeLastRead] = branch node location
  1184. ; [ebp+NTFS.indexRoot] -> attribute
  1185. ; [ebp+NTFS.rootLastRead] = directory fileRecord location
  1186. ; [ebp+NTFS.cur_size] = index record size in sectors
  1187. ; [ebp+NTFS.cur_subnode_size] = index record size in clusters or sectors
  1188. ; CF=1 -> file not found, eax=0 -> error
  1189.         mov     [ebp+NTFS.cur_iRecord], 5   ; start from root directory
  1190. .doit2:
  1191.         mov     [ebp+NTFS.cur_attr], 0x90   ; $INDEX_ROOT
  1192.         and     [ebp+NTFS.cur_offs], 0
  1193.         mov     eax, [ebp+NTFS.cur_index_size]
  1194.         mov     [ebp+NTFS.cur_size], eax
  1195.         mov     eax, [ebp+NTFS.cur_index_buf]
  1196.         mov     [ebp+NTFS.cur_buf], eax
  1197.         call    ntfs_read_attr
  1198.         mov     eax, 0
  1199.         jc      .ret
  1200.         cmp     [ebp+NTFS.cur_read], 0x20
  1201.         jc      .ret
  1202.         push    esi
  1203.         pushad
  1204.         mov     esi, [ebp+NTFS.cur_index_buf]
  1205.         mov     eax, [esi+indexRecordSize]
  1206.         shr     eax, 9
  1207.         cmp     [ebp+NTFS.cur_index_size], eax
  1208.         jc      .realloc
  1209.         mov     [ebp+NTFS.cur_size], eax
  1210.         mov     al, [esi+indexRecordSizeClus]
  1211.         mov     [ebp+NTFS.cur_subnode_size], eax
  1212.         add     esi, rootNode
  1213.         mov     eax, [esi+nodeRealSize]
  1214.         add     eax, rootNode
  1215.         cmp     [ebp+NTFS.cur_read], eax
  1216.         jc      .err
  1217.         mov     edi, [esp+4]
  1218.         mov     eax, [ebp+NTFS.mftLastRead]
  1219.         mov     [ebp+NTFS.rootLastRead], eax
  1220.         mov     eax, [ebp+NTFS.attr_offs]
  1221.         mov     [ebp+NTFS.indexRoot], eax
  1222. ; edi -> name, esi -> current index node
  1223. .scanloop:
  1224.         add     esi, [esi+indexOffset]
  1225. .scanloopint:
  1226.         test    byte [esi+indexFlags], 2
  1227.         jnz     .subnode
  1228.         push    esi
  1229.         movzx   ecx, byte [esi+fileNameLength]
  1230.         add     esi, fileName
  1231.         push    edi
  1232. @@:
  1233.         lodsw
  1234.         call    unichar_toupper
  1235.         push    eax
  1236.         mov     al, [edi]
  1237.         inc     edi
  1238.         cmp     al, '/'
  1239.         jz      .slash
  1240.         call    char_toupper
  1241.         call    ansi2uni_char
  1242.         cmp     ax, [esp]
  1243.         pop     eax
  1244.         loopz   @b
  1245.         jz      .found
  1246.         pop     edi
  1247.         pop     esi
  1248.         jb      .subnode
  1249. .scanloopcont:
  1250.         movzx   eax, word [esi+indexAllocatedSize]
  1251.         add     esi, eax
  1252.         jmp     .scanloopint
  1253.  
  1254. .realloc:
  1255.         mov     edi, eax
  1256.         mov     eax, [esi+indexRecordSize]
  1257.         shl     eax, 1
  1258.         stdcall kernel_alloc, eax
  1259.         test    eax, eax
  1260.         jz      .err
  1261.         mov     edx, [ebp+NTFS.cur_index_buf]
  1262.         cmp     edx, [ebp+NTFS.secondIndexBuffer]
  1263.         jc      @f
  1264.         mov     edx, [ebp+NTFS.secondIndexBuffer]
  1265. @@:
  1266.         mov     [ebp+NTFS.cur_index_buf], eax
  1267.         add     eax, [esi+indexRecordSize]
  1268.         mov     [ebp+NTFS.secondIndexBuffer], eax
  1269.         mov     [ebp+NTFS.cur_index_size], edi
  1270.         stdcall kernel_free, edx
  1271.         popad
  1272.         pop     eax
  1273.         jmp     .doit2
  1274.  
  1275. .notfound:
  1276.         mov     [esp+1Ch], esi
  1277. .err:
  1278.         popad
  1279.         stc
  1280. .ret2:
  1281.         pop     esi
  1282. .ret:
  1283.         ret
  1284.  
  1285. .slash:
  1286.         pop     eax
  1287.         pop     edi
  1288.         pop     esi
  1289. .subnode:
  1290.         test    byte [esi+indexFlags], 1
  1291.         jz      .notfound
  1292.         mov     eax, [ebp+NTFS.LastRead]
  1293.         mov     [ebp+NTFS.nodeLastRead], eax
  1294.         mov     [ebp+NTFS.indexPointer], esi
  1295.         movzx   eax, word [esi+indexAllocatedSize]
  1296.         mov     eax, [esi+eax-8]
  1297.         mov     edx, [ebp+NTFS.cur_size]
  1298.         push    edx
  1299.         cmp     edx, [ebp+NTFS.cur_subnode_size]
  1300.         jz      @f
  1301.         mul     [ebp+NTFS.sectors_per_cluster]
  1302. @@:
  1303.         mov     esi, [ebp+NTFS.cur_index_buf]
  1304.         xchg    [ebp+NTFS.secondIndexBuffer], esi
  1305.         mov     [ebp+NTFS.cur_index_buf], esi
  1306.         mov     [ebp+NTFS.cur_buf], esi
  1307.         mov     [ebp+NTFS.cur_attr], 0xA0   ; $INDEX_ALLOCATION
  1308.         mov     [ebp+NTFS.cur_offs], eax
  1309.         call    ntfs_read_attr.newAttribute
  1310.         pop     eax
  1311.         mov     [ebp+NTFS.cur_size], eax
  1312.         shl     eax, 9
  1313.         cmp     [ebp+NTFS.cur_read], eax
  1314.         jnz     .err
  1315.         cmp     dword [esi], 'INDX'
  1316.         jnz     .err
  1317.         mov     ebx, esi
  1318.         call    ntfs_restore_usa
  1319.         jc      .err
  1320.         add     esi, recordNode
  1321.         jmp     .scanloop
  1322.  
  1323. .found:
  1324.         cmp     byte [edi], 0
  1325.         jz      @f
  1326.         cmp     byte [edi], '/'
  1327.         jz      @f
  1328.         pop     edi
  1329.         pop     esi
  1330.         jmp     .scanloopcont
  1331.  
  1332. @@:
  1333.         pop     esi
  1334.         pop     esi
  1335.         mov     eax, [esi]
  1336.         mov     [ebp+NTFS.cur_iRecord], eax
  1337.         mov     [esp+1Ch], esi
  1338.         mov     [esp+4], edi
  1339.         popad
  1340.         cmp     byte [esi], 0
  1341.         jz      .ret2
  1342.         inc     esi
  1343.         pop     eax
  1344.         jmp     .doit2
  1345.  
  1346. ;----------------------------------------------------------------
  1347. ntfs_ReadFile:
  1348.         cmp     byte [esi], 0
  1349.         jnz     @f
  1350.         or      ebx, -1
  1351.         movi    eax, ERROR_ACCESS_DENIED
  1352.         ret
  1353.  
  1354. @@:
  1355.         call    ntfs_lock
  1356.         call    ntfs_find_lfn
  1357.         jnc     .found
  1358.         call    ntfs_unlock
  1359.         or      ebx, -1
  1360.         movi    eax, ERROR_FILE_NOT_FOUND
  1361.         ret
  1362.  
  1363. .found:
  1364.         mov     [ebp+NTFS.cur_attr], 0x80   ; $DATA
  1365.         and     [ebp+NTFS.cur_offs], 0
  1366.         and     [ebp+NTFS.cur_size], 0
  1367.         call    ntfs_read_attr
  1368.         jnc     @f
  1369.         call    ntfs_unlock
  1370.         or      ebx, -1
  1371.         movi    eax, ERROR_ACCESS_DENIED
  1372.         ret
  1373.  
  1374. @@:
  1375.         pushad
  1376.         and     dword [esp+10h], 0
  1377.         xor     eax, eax
  1378.         cmp     dword [ebx+8], 0x200
  1379.         jb      @f
  1380. .eof0:
  1381.         popad
  1382.         xor     ebx, ebx
  1383. .eof:
  1384.         call    ntfs_unlock
  1385.         movi    eax, ERROR_END_OF_FILE
  1386.         ret
  1387.  
  1388. @@:
  1389.         mov     ecx, [ebx+12]
  1390.         mov     edx, [ebx+16]
  1391.         mov     eax, [ebx+4]
  1392.         test    eax, 0x1FF
  1393.         jz      .alignedstart
  1394.         push    edx
  1395.         mov     edx, [ebx+8]
  1396.         shrd    eax, edx, 9
  1397.         pop     edx
  1398.         mov     [ebp+NTFS.cur_offs], eax
  1399.         mov     [ebp+NTFS.cur_size], 1
  1400.         lea     eax, [ebp+NTFS.bitmap_buf]
  1401.         mov     [ebp+NTFS.cur_buf], eax
  1402.         call    ntfs_read_attr.continue
  1403.         mov     eax, [ebx+4]
  1404.         and     eax, 0x1FF
  1405.         lea     esi, [ebp+NTFS.bitmap_buf+eax]
  1406.         sub     eax, [ebp+NTFS.cur_read]
  1407.         jae     .eof0
  1408.         neg     eax
  1409.         push    ecx
  1410.         cmp     ecx, eax
  1411.         jb      @f
  1412.         mov     ecx, eax
  1413. @@:
  1414.         mov     [esp+10h+4], ecx
  1415.         mov     edi, edx
  1416.         rep movsb
  1417.         mov     edx, edi
  1418.         pop     ecx
  1419.         sub     ecx, [esp+10h]
  1420.         jnz     @f
  1421. .retok:
  1422.         popad
  1423.         call    ntfs_unlock
  1424.         xor     eax, eax
  1425.         ret
  1426.  
  1427. @@:
  1428.         cmp     [ebp+NTFS.cur_read], 0x200
  1429.         jz      .alignedstart
  1430. .eof_ebx:
  1431.         popad
  1432.         jmp     .eof
  1433.  
  1434. .alignedstart:
  1435.         mov     eax, [ebx+4]
  1436.         push    edx
  1437.         mov     edx, [ebx+8]
  1438.         add     eax, 511
  1439.         adc     edx, 0
  1440.         shrd    eax, edx, 9
  1441.         pop     edx
  1442.         mov     [ebp+NTFS.cur_offs], eax
  1443.         mov     [ebp+NTFS.cur_buf], edx
  1444.         mov     eax, ecx
  1445.         shr     eax, 9
  1446.         mov     [ebp+NTFS.cur_size], eax
  1447.         add     eax, [ebp+NTFS.cur_offs]
  1448.         push    eax
  1449.         call    ntfs_read_attr.continue
  1450.         pop     [ebp+NTFS.cur_offs]
  1451.         mov     eax, [ebp+NTFS.cur_read]
  1452.         add     [esp+10h], eax
  1453.         mov     eax, ecx
  1454.         and     eax, not 0x1FF
  1455.         cmp     [ebp+NTFS.cur_read], eax
  1456.         jnz     .eof_ebx
  1457.         and     ecx, 0x1FF
  1458.         jz      .retok
  1459.         add     edx, [ebp+NTFS.cur_read]
  1460.         mov     [ebp+NTFS.cur_size], 1
  1461.         lea     eax, [ebp+NTFS.bitmap_buf]
  1462.         mov     [ebp+NTFS.cur_buf], eax
  1463.         call    ntfs_read_attr.continue
  1464.         cmp     [ebp+NTFS.cur_read], ecx
  1465.         jb      @f
  1466.         mov     [ebp+NTFS.cur_read], ecx
  1467. @@:
  1468.         xchg    ecx, [ebp+NTFS.cur_read]
  1469.         push    ecx
  1470.         mov     edi, edx
  1471.         lea     esi, [ebp+NTFS.bitmap_buf]
  1472.         add     [esp+10h+4], ecx
  1473.         rep movsb
  1474.         pop     ecx
  1475.         xor     eax, eax
  1476.         cmp     ecx, [ebp+NTFS.cur_read]
  1477.         jz      @f
  1478.         mov     al, ERROR_END_OF_FILE
  1479. @@:
  1480.         mov     [esp+1Ch], eax
  1481.         call    ntfs_unlock
  1482.         popad
  1483.         ret
  1484.  
  1485. ;----------------------------------------------------------------
  1486. ntfs_ReadFolder:
  1487.         call    ntfs_lock
  1488.         mov     [ebp+NTFS.cur_iRecord], 5   ; root directory
  1489.         cmp     byte [esi], 0
  1490.         jz      @f
  1491.         call    ntfs_find_lfn
  1492.         jc      ntfsNotFound
  1493. @@:
  1494.         mov     [ebp+NTFS.cur_attr], 0x10   ; $STANDARD_INFORMATION
  1495.         and     [ebp+NTFS.cur_offs], 0
  1496.         mov     [ebp+NTFS.cur_size], 1
  1497.         lea     eax, [ebp+NTFS.bitmap_buf]
  1498.         mov     [ebp+NTFS.cur_buf], eax
  1499.         call    ntfs_read_attr
  1500.         jc      ntfsFail
  1501.         mov     [ebp+NTFS.cur_attr], 0x90   ; $INDEX_ROOT
  1502. .doit:
  1503.         mov     eax, [ebp+NTFS.cur_index_size]
  1504.         mov     [ebp+NTFS.cur_size], eax
  1505.         mov     eax, [ebp+NTFS.cur_index_buf]
  1506.         mov     [ebp+NTFS.cur_buf], eax
  1507.         call    ntfs_read_attr.newAttribute
  1508.         jc      ntfsFail
  1509.         cmp     [ebp+NTFS.cur_read], 0x20
  1510.         jc      ntfsFail
  1511.         mov     esi, [ebp+NTFS.cur_index_buf]
  1512.         mov     eax, [esi+indexRecordSize]
  1513.         shr     eax, 9
  1514.         cmp     [ebp+NTFS.cur_index_size], eax
  1515.         jc      .realloc
  1516.         mov     [ebp+NTFS.cur_subnode_size], eax
  1517.         add     esi, rootNode
  1518.         mov     eax, [esi+nodeRealSize]
  1519.         add     eax, rootNode
  1520.         cmp     [ebp+NTFS.cur_read], eax
  1521.         jc      ntfsFail
  1522.         mov     edi, [ebx+16]
  1523.         mov     ecx, [ebx+12]
  1524.         pushd   [ebx]
  1525.         pushd   [ebx+8]     ; read ANSI/UNICODE name
  1526.         push    edi
  1527.         mov     edx, esp
  1528.         mov     ebx, [ebx+4]
  1529. ; init header
  1530.         xor     eax, eax
  1531.         mov     [edi+8], eax
  1532.         mov     [edi+4], eax
  1533.         inc     eax
  1534.         mov     [edi], eax      ; version
  1535.         add     edi, 32
  1536. ; edi -> BDFE, esi -> current index data, ebx = first wanted block,
  1537. ; ecx = number of blocks to read
  1538. ; edx -> parameters block: dd <output>, dd <flags>
  1539.         cmp     [ebp+NTFS.cur_iRecord], 5
  1540.         jz      .skip_specials
  1541. ; dot and dotdot entries
  1542.         push    esi
  1543.         xor     esi, esi
  1544.         call    .add_special_entry
  1545.         inc     esi
  1546.         call    .add_special_entry
  1547.         pop     esi
  1548. .skip_specials:
  1549. ; at first, dump index root
  1550.         add     esi, [esi+indexOffset]
  1551. .dump_root:
  1552.         test    byte [esi+indexFlags], 2
  1553.         jnz     .dump_root_done
  1554.         call    .add_entry
  1555.         movzx   eax, word [esi+indexAllocatedSize]
  1556.         add     esi, eax
  1557.         jmp     .dump_root
  1558.  
  1559. .realloc:
  1560.         mov     edi, eax
  1561.         mov     eax, [esi+indexRecordSize]
  1562.         shl     eax, 1
  1563.         stdcall kernel_alloc, eax
  1564.         test    eax, eax
  1565.         jz      ntfsFail
  1566.         mov     edx, [ebp+NTFS.cur_index_buf]
  1567.         cmp     edx, [ebp+NTFS.secondIndexBuffer]
  1568.         jc      @f
  1569.         mov     edx, [ebp+NTFS.secondIndexBuffer]
  1570. @@:
  1571.         mov     [ebp+NTFS.cur_index_buf], eax
  1572.         add     eax, [esi+indexRecordSize]
  1573.         mov     [ebp+NTFS.secondIndexBuffer], eax
  1574.         mov     [ebp+NTFS.cur_index_size], edi
  1575.         stdcall kernel_free, edx
  1576.         jmp     .doit
  1577.  
  1578. .dump_root_done:
  1579. ; now dump all subnodes
  1580.         push    ecx edi
  1581.         lea     edi, [ebp+NTFS.bitmap_buf]
  1582.         mov     [ebp+NTFS.cur_buf], edi
  1583.         mov     ecx, 0x400/4
  1584.         xor     eax, eax
  1585.         rep stosd
  1586.         mov     [ebp+NTFS.cur_attr], 0xB0   ; $BITMAP
  1587.         and     [ebp+NTFS.cur_offs], 0
  1588.         mov     [ebp+NTFS.cur_size], 2
  1589.         call    ntfs_read_attr.newAttribute
  1590.         pop     edi ecx
  1591.         push    0       ; save offset in $BITMAP attribute
  1592.         and     [ebp+NTFS.cur_offs], 0
  1593. .dumploop:
  1594.         mov     [ebp+NTFS.cur_attr], 0xA0
  1595.         mov     eax, [ebp+NTFS.cur_subnode_size]
  1596.         mov     [ebp+NTFS.cur_size], eax
  1597.         mov     esi, [ebp+NTFS.cur_index_buf]
  1598.         mov     [ebp+NTFS.cur_buf], esi
  1599.         mov     eax, [ebp+NTFS.cur_offs]
  1600.         push    eax
  1601.         imul    eax, [ebp+NTFS.cur_subnode_size]
  1602.         mov     [ebp+NTFS.cur_offs], eax
  1603.         call    ntfs_read_attr.newAttribute
  1604.         pop     [ebp+NTFS.cur_offs]
  1605.         mov     eax, [ebp+NTFS.cur_subnode_size]
  1606.         shl     eax, 9
  1607.         cmp     [ebp+NTFS.cur_read], eax
  1608.         jnz     .done
  1609.         push    eax
  1610.         mov     eax, [ebp+NTFS.cur_offs]
  1611.         and     eax, 0x400*8-1
  1612.         bt      dword [ebp+NTFS.bitmap_buf], eax
  1613.         pop     eax
  1614.         jnc     .dump_subnode_done
  1615.         cmp     dword [esi], 'INDX'
  1616.         jnz     .dump_subnode_done
  1617.         push    ebx
  1618.         mov     ebx, esi
  1619.         call    ntfs_restore_usa
  1620.         pop     ebx
  1621.         jc      .dump_subnode_done
  1622.         add     esi, recordNode
  1623.         add     esi, [esi+indexOffset]
  1624. .dump_subnode:
  1625.         test    byte [esi+indexFlags], 2
  1626.         jnz     .dump_subnode_done
  1627.         call    .add_entry
  1628.         movzx   eax, word [esi+indexAllocatedSize]
  1629.         add     esi, eax
  1630.         jmp     .dump_subnode
  1631.  
  1632. .dump_subnode_done:
  1633.         inc     [ebp+NTFS.cur_offs]
  1634.         test    [ebp+NTFS.cur_offs], 0x400*8-1
  1635.         jnz     .dumploop
  1636.         mov     [ebp+NTFS.cur_attr], 0xB0
  1637.         push    ecx edi
  1638.         lea     edi, [ebp+NTFS.bitmap_buf]
  1639.         mov     [ebp+NTFS.cur_buf], edi
  1640.         mov     ecx, 0x400/4
  1641.         xor     eax, eax
  1642.         rep stosd
  1643.         pop     edi ecx
  1644.         pop     eax
  1645.         push    [ebp+NTFS.cur_offs]
  1646.         inc     eax
  1647.         mov     [ebp+NTFS.cur_offs], eax
  1648.         mov     [ebp+NTFS.cur_size], 2
  1649.         push    eax
  1650.         call    ntfs_read_attr.newAttribute
  1651.         pop     eax
  1652.         pop     [ebp+NTFS.cur_offs]
  1653.         push    eax
  1654.         jmp     .dumploop
  1655.  
  1656. .done:
  1657.         pop     eax
  1658.         pop     eax
  1659.         mov     ebx, [eax+4]
  1660.         pop     eax
  1661.         pop     eax
  1662.         test    eax, eax
  1663.         jz      .ret
  1664.         xor     eax, eax
  1665.         dec     ecx
  1666.         js      @f
  1667.         mov     al, ERROR_END_OF_FILE
  1668. @@:
  1669.         push    eax
  1670.         call    ntfs_unlock
  1671.         pop     eax
  1672.         ret
  1673.  
  1674. .add_special_entry:
  1675.         mov     eax, [edx]
  1676.         inc     dword [eax+8]   ; new file found
  1677.         dec     ebx
  1678.         jns     .ret
  1679.         dec     ecx
  1680.         js      .ret
  1681.         inc     dword [eax+4]   ; new file block copied
  1682.         mov     eax, [edx+4]
  1683.         mov     [edi+4], eax
  1684.         mov     eax, 0x10
  1685.         stosd
  1686.         scasd
  1687.         push    ebx ecx edx
  1688.         mov     eax, dword [ebp+NTFS.bitmap_buf]
  1689.         mov     edx, dword [ebp+NTFS.bitmap_buf+4]
  1690.         call    ntfs_datetime_to_bdfe
  1691.         mov     eax, dword [ebp+NTFS.bitmap_buf+0x18]
  1692.         mov     edx, dword [ebp+NTFS.bitmap_buf+0x1C]
  1693.         call    ntfs_datetime_to_bdfe
  1694.         mov     eax, dword [ebp+NTFS.bitmap_buf+8]
  1695.         mov     edx, dword [ebp+NTFS.bitmap_buf+0xC]
  1696.         call    ntfs_datetime_to_bdfe
  1697.         pop     edx ecx ebx
  1698.         xor     eax, eax
  1699.         stosd
  1700.         stosd
  1701.         mov     al, '.'
  1702.         push    edi ecx
  1703.         lea     ecx, [esi+1]
  1704.         test    byte [edi-0x24], 1
  1705.         jz      @f
  1706.         rep stosw
  1707.         pop     ecx
  1708.         xor     eax, eax
  1709.         stosw
  1710.         pop     edi
  1711.         add     edi, 520
  1712.         ret
  1713.  
  1714. @@:
  1715.         rep stosb
  1716.         pop     ecx
  1717.         xor     eax, eax
  1718.         stosb
  1719.         pop     edi
  1720.         add     edi, 264
  1721. .ret:
  1722.         ret
  1723.  
  1724. .add_entry:
  1725. ; do not return DOS 8.3 names
  1726.         cmp     byte [esi+namespace], 2
  1727.         jz      .ret
  1728. ; do not return system files
  1729. ; ... note that there will be no bad effects if system files also were reported ...
  1730.         cmp     dword [esi+fileRecordReference], 0x10
  1731.         jb      .ret
  1732.         mov     eax, [edx]
  1733.         inc     dword [eax+8]   ; new file found
  1734.         dec     ebx
  1735.         jns     .ret
  1736.         dec     ecx
  1737.         js      .ret
  1738.         inc     dword [eax+4]   ; new file block copied
  1739.         mov     eax, [edx+4]    ; flags
  1740.         call    ntfs_direntry_to_bdfe
  1741.         push    ecx esi edi
  1742.         movzx   ecx, byte [esi+fileNameLength]
  1743.         add     esi, fileName
  1744.         test    byte [edi-0x24], 1
  1745.         jz      .ansi
  1746.         shr     ecx, 1
  1747.         rep movsd
  1748.         adc     ecx, ecx
  1749.         rep movsw
  1750.         and     word [edi], 0
  1751.         pop     edi
  1752.         add     edi, 520
  1753.         pop     esi ecx
  1754.         ret
  1755.  
  1756. .ansi:
  1757.         jecxz   .skip
  1758. @@:
  1759.         lodsw
  1760.         call    uni2ansi_char
  1761.         stosb
  1762.         loop    @b
  1763. .skip:
  1764.         xor     al, al
  1765.         stosb
  1766.         pop     edi
  1767.         add     edi, 264
  1768.         pop     esi ecx
  1769.         ret
  1770.  
  1771. ntfs_direntry_to_bdfe:
  1772.         mov     [edi+4], eax    ; ANSI/UNICODE name
  1773.         mov     eax, [esi+fileFlags]
  1774.         test    eax, 0x10000000
  1775.         jz      @f
  1776.         and     eax, not 0x10000000
  1777.         or      al, 0x10
  1778. @@:
  1779.         stosd
  1780.         scasd
  1781.         push    ebx ecx edx
  1782.         mov     eax, [esi+fileCreated]
  1783.         mov     edx, [esi+fileCreated+4]
  1784.         call    ntfs_datetime_to_bdfe
  1785.         mov     eax, [esi+fileAccessed]
  1786.         mov     edx, [esi+fileAccessed+4]
  1787.         call    ntfs_datetime_to_bdfe
  1788.         mov     eax, [esi+fileModified]
  1789.         mov     edx, [esi+fileModified+4]
  1790.         call    ntfs_datetime_to_bdfe
  1791.         pop     edx ecx ebx
  1792.         mov     eax, [esi+fileRealSize]
  1793.         stosd
  1794.         mov     eax, [esi+fileRealSize+4]
  1795.         stosd
  1796.         ret
  1797.  
  1798. ntfs_datetime_to_bdfe:
  1799. ; in: edx:eax = seconds since 01.01.1601 x10000000
  1800. ; edi -> data block
  1801. ; out: edi = edi+8
  1802.         sub     eax, 3365781504
  1803.         sbb     edx, 29389701
  1804.         mov     ecx, 10000000
  1805.         cmp     edx, ecx
  1806.         jc      @f
  1807.         xor     edx, edx
  1808. @@:
  1809.         div     ecx
  1810.         jmp     fsTime2bdfe
  1811.  
  1812. ;----------------------------------------------------------------
  1813. ntfs_GetFileInfo:
  1814.         call    ntfs_lock
  1815.         mov     edi, [ebx+16]
  1816.         cmp     byte [esi], 0
  1817.         jz      .volume
  1818.         call    ntfs_find_lfn
  1819.         jnc     .found
  1820.         test    eax, eax
  1821.         jz      ntfsFail
  1822.         jmp     ntfsNotFound
  1823.  
  1824. .found:
  1825.         mov     esi, eax
  1826.         xor     eax, eax
  1827.         call    ntfs_direntry_to_bdfe
  1828. .end:
  1829.         call    ntfs_unlock
  1830.         xor     eax, eax
  1831.         ret
  1832.  
  1833. .volume:
  1834.         mov     byte [edi], 8
  1835.         mov     eax, [ebx+8]
  1836.         mov     [edi+4], eax
  1837.         mov     eax, dword [ebp+NTFS.Length]
  1838.         mov     edx, dword [ebp+NTFS.Length+4]
  1839.         shld    edx, eax, 9
  1840.         shl     eax, 9
  1841.         mov     [edi+36], edx
  1842.         mov     [edi+32], eax
  1843.         add     edi, 40
  1844.         mov     [ebp+NTFS.cur_buf], edi
  1845.         mov     [ebp+NTFS.cur_iRecord], 3
  1846.         mov     [ebp+NTFS.cur_attr], 0x60
  1847.         mov     [ebp+NTFS.cur_offs], 0
  1848.         mov     [ebp+NTFS.cur_size], 1
  1849.         call    ntfs_read_attr
  1850.         jc      ntfsFail
  1851.         mov     ecx, [ebp+NTFS.cur_read]
  1852.         mov     [edi+ecx], ax
  1853.         cmp     [ebx+8], eax
  1854.         jnz     .end
  1855.         mov     esi, edi
  1856.         shr     ecx, 1
  1857.         jz      .end
  1858. @@:
  1859.         lodsw
  1860.         call    uni2ansi_char
  1861.         stosb
  1862.         dec     ecx
  1863.         jnz     @b
  1864.         mov     byte [edi], 0
  1865.         jmp     .end
  1866.  
  1867. ;----------------------------------------------------------------
  1868. ntfs_CreateFolder:
  1869.         mov     [ebp+NTFS.bFolder], 1
  1870.         jmp     @f
  1871.  
  1872. ntfs_CreateFile:
  1873.         mov     [ebp+NTFS.bFolder], 0
  1874. @@:
  1875.         cmp     byte [esi], 0
  1876.         jnz     @f
  1877.         xor     ebx, ebx
  1878.         movi    eax, ERROR_ACCESS_DENIED
  1879.         ret
  1880.  
  1881. @@: ; 1. Search file
  1882.         call    ntfs_lock
  1883.         call    ntfs_find_lfn
  1884.         jc      .notFound
  1885. ; found, rewrite
  1886.         cmp     [ebp+NTFS.cur_iRecord], 16
  1887.         jc      ntfsDenied
  1888.         cmp     [ebp+NTFS.bFolder], 1
  1889.         jz      .folder
  1890.         test    byte [eax+fileFlags], 1
  1891.         jnz     ntfsDenied
  1892.         cmp     [ebp+NTFS.fragmentCount], 1
  1893.         jnz     ntfsUnsupported     ; record fragmented
  1894. ; edit directory node
  1895.         mov     edi, [ebp+NTFS.cur_index_buf]
  1896.         cmp     dword [edi], 'INDX'
  1897.         jz      @f
  1898.         mov     esi, [ebp+NTFS.frs_buffer]
  1899.         mov     ecx, [esi+recordRealSize]
  1900.         shr     ecx, 2
  1901.         rep movsd
  1902.         mov     esi, [ebp+NTFS.attr_offs]
  1903.         mov     cl, [esi+attributeOffset]
  1904.         sub     esi, [ebp+NTFS.frs_buffer]
  1905.         add     eax, ecx
  1906.         add     eax, esi
  1907. @@:
  1908.         mov     edi, eax
  1909.         mov     eax, [ebx+12]
  1910.         mov     [edi+fileRealSize], eax
  1911.         mov     dword [edi+fileRealSize+4], 0
  1912.         push    ebx eax
  1913.         call    ntfsGetTime
  1914.         mov     [edi+fileModified], eax
  1915.         mov     [edi+fileModified+4], edx
  1916.         mov     [edi+recordModified], eax
  1917.         mov     [edi+recordModified+4], edx
  1918.         mov     [edi+fileAccessed], eax
  1919.         mov     [edi+fileAccessed+4], edx
  1920.         pop     edx ebx
  1921.         mov     eax, [ebp+NTFS.LastRead]
  1922.         mov     [ebp+NTFS.nodeLastRead], eax
  1923.         mov     [ebp+NTFS.cur_attr], 0x80
  1924.         mov     [ebp+NTFS.cur_offs], 0
  1925.         mov     [ebp+NTFS.cur_size], 0
  1926.         call    ntfs_read_attr
  1927.         jc      ntfsFail
  1928.         mov     esi, edi
  1929.         mov     edi, [ebp+NTFS.frs_buffer]
  1930.         cmp     word [edi+baseRecordReuse], 0
  1931.         jnz     ntfsUnsupported     ; auxiliary record
  1932.         mov     al, [edi+attributeOffset]
  1933.         add     edi, eax
  1934.         mov     al, [edi+attributeOffset]
  1935.         add     edi, eax
  1936.         mov     ecx, 6
  1937.         add     esi, fileModified
  1938.         add     edi, 8
  1939.         rep movsd
  1940.         mov     eax, edx
  1941.         xor     edx, edx
  1942.         mov     ecx, [ebp+NTFS.attr_offs]
  1943.         cmp     word [ecx+attributeFlags], 0
  1944.         jnz     ntfsUnsupported
  1945.         push    ebx
  1946.         cmp     byte [ecx+nonResidentFlag], 0
  1947.         jz      @f
  1948.         cmp     [ecx+attributeRealSize+4], edx
  1949.         jnz     @f
  1950.         cmp     [ecx+attributeRealSize], eax
  1951.         jz      ntfs_WriteFile.writeNode
  1952. @@:
  1953.         jmp     ntfs_WriteFile.resizeAttribute
  1954.  
  1955. .folder:
  1956.         bt      dword [eax+fileFlags], 28
  1957.         jnc     ntfsDenied
  1958.         push    0
  1959.         jmp     ntfsOut
  1960.  
  1961. .notFound:  ; create
  1962.         test    eax, eax
  1963.         jz      ntfsFail
  1964.         cmp     [ebp+NTFS.fragmentCount], 1
  1965.         jnz     ntfsUnsupported     ; record fragmented
  1966. ; 2. Prepare directory record
  1967.         mov     ecx, esi
  1968. @@:         ; count characters
  1969.         inc     ecx
  1970.         cmp     byte [ecx], '/'
  1971.         jz      ntfsNotFound    ; path folder not found
  1972.         cmp     byte [ecx], 0
  1973.         jnz     @b
  1974.         sub     ecx, esi
  1975.         push    ecx     ; name length
  1976.         shl     ecx, 1
  1977.         add     ecx, fileName+7
  1978.         and     ecx, not 7
  1979.         mov     edi, [ebp+NTFS.cur_index_buf]
  1980.         mov     edx, [ebx+12]
  1981.         mov     [ebp+NTFS.fileRealSize], edx
  1982.         mov     edx, [ebx+16]
  1983.         mov     [ebp+NTFS.fileDataBuffer], edx
  1984.         push    esi
  1985.         push    ecx     ; index length
  1986.         mov     edx, ecx
  1987.         cmp     dword [edi], 'INDX'
  1988.         jz      .indexRecord
  1989.         mov     esi, [ebp+NTFS.frs_buffer]  ; indexRoot
  1990.         mov     ecx, [esi+recordRealSize]
  1991.         add     edx, ecx
  1992.         cmp     [esi+recordAllocatedSize], edx
  1993.         jc      .growTree
  1994.         mov     [esi+recordRealSize], edx
  1995.         shr     ecx, 2
  1996.         rep movsd
  1997.         mov     edi, [ebp+NTFS.indexRoot]
  1998.         sub     edi, [ebp+NTFS.frs_buffer]
  1999.         add     edi, [ebp+NTFS.cur_index_buf]
  2000.         mov     esi, [esp]
  2001.         add     [edi+sizeWithHeader], esi
  2002.         add     [edi+sizeWithoutHeader], esi
  2003.         mov     cl, [edi+attributeOffset]
  2004.         add     edi, ecx
  2005.         add     [edi+rootNode+nodeRealSize], esi
  2006.         add     [edi+rootNode+nodeAllocatedSize], esi
  2007.         sub     eax, [ebp+NTFS.cur_index_buf]
  2008.         add     eax, edi
  2009.         mov     edi, [ebp+NTFS.cur_index_buf]
  2010.         jmp     .common
  2011.  
  2012. .growTree:  ; create indexRecord
  2013.         mov     edi, [ebp+NTFS.cur_index_buf]
  2014.         mov     ecx, 10
  2015.         xor     eax, eax
  2016.         rep stosd
  2017.         mov     esi, [ebp+NTFS.indexRoot]
  2018.         mov     al, [esi+attributeOffset]
  2019.         add     esi, eax
  2020.         rdtsc
  2021.         stosw
  2022.         mov     eax, [esi+indexRecordSize]
  2023.         cmp     eax, [ebp+NTFS.frs_size]
  2024.         jc      .errorPop3
  2025.         shr     eax, 9
  2026.         inc     eax
  2027.         mov     edi, [ebp+NTFS.cur_index_buf]
  2028.         mov     dword[edi], 'INDX'
  2029.         mov     byte [edi+updateSequenceOffset], 28h
  2030.         mov     [edi+updateSequenceSize], al
  2031.         add     edi, recordNode
  2032.         shl     eax, 1
  2033.         add     eax, 28h-recordNode+7
  2034.         and     eax, not 7
  2035.         mov     [edi+indexOffset], eax
  2036.         mov     ecx, [esi+indexRecordSize]
  2037.         sub     ecx, recordNode
  2038.         mov     [edi+nodeAllocatedSize], ecx
  2039.         add     esi, rootNode
  2040.         push    esi
  2041.         mov     ecx, [esi+nodeRealSize]
  2042.         sub     ecx, [esi+indexOffset]
  2043.         add     eax, ecx
  2044.         mov     [edi+nodeRealSize], eax
  2045.         mov     eax, [esi+nonLeafFlag]
  2046.         mov     [edi+nonLeafFlag], eax
  2047.         shr     ecx, 2
  2048.         add     esi, [esi+indexOffset]
  2049.         add     edi, [edi+indexOffset]
  2050.         rep movsd       ; copy root indexes
  2051. ; clear root node
  2052.         mov     cl, 10
  2053.         mov     edi, [esp]
  2054.         xor     eax, eax
  2055.         rep stosd
  2056.         pop     edi
  2057.         mov     byte [edi+indexOffset], 16
  2058.         mov     byte [edi+nodeRealSize], 28h
  2059.         mov     byte [edi+nodeAllocatedSize], 28h
  2060.         mov     byte [edi+nonLeafFlag], 1
  2061.         mov     byte [edi+16+indexAllocatedSize], 18h
  2062.         mov     byte [edi+16+indexFlags], 3
  2063.         mov     esi, [ebp+NTFS.indexRoot]
  2064.         add     edi, 28h
  2065.         mov     eax, edi
  2066.         sub     eax, esi
  2067.         mov     word [esi+sizeWithoutHeader], 38h
  2068.         xchg    [esi+sizeWithHeader], eax
  2069.         add     esi, eax
  2070.         mov     [ebp+NTFS.attr_offs], edi
  2071.         cmp     byte [esi], 0xA0
  2072.         jnz     @f
  2073.         cmp     dword [esi+attributeAllocatedSize], 0
  2074.         jz      @f
  2075.         mov     eax, [ebp+NTFS.frs_buffer]
  2076.         mov     ecx, eax
  2077.         add     ecx, [eax+recordRealSize]
  2078.         sub     ecx, esi
  2079.         shr     ecx, 2
  2080.         rep movsd
  2081.         sub     edi, eax
  2082.         mov     [eax+recordRealSize], edi
  2083.         call    .ntfsNodeAlloc
  2084.         jc      ntfsErrorPop3
  2085.         mov     eax, [ebp+NTFS.newRecord]
  2086.         mov     edi, [ebp+NTFS.cur_index_buf]
  2087.         mov     [edi+recordVCN], eax
  2088.         mov     edi, [ebp+NTFS.attr_offs]
  2089.         mov     [edi-8], eax
  2090.         jmp     .refresh
  2091.  
  2092. @@:
  2093.         mov     cl, 32
  2094.         xor     eax, eax
  2095.         rep stosd
  2096.         mov     eax, [ebp+NTFS.cur_subnode_size]
  2097.         cmp     eax, [ebp+NTFS.cur_size]
  2098.         jnz     @f
  2099.         mov     al, 1
  2100. @@:
  2101.         mov     [ebp+NTFS.fileDataSize], eax
  2102.         mov     edi, [ebp+NTFS.BitmapStart]
  2103.         call    ntfsSpaceAlloc
  2104.         movi    eax, ERROR_DISK_FULL
  2105.         jc      ntfsErrorPop3
  2106. ; create $IndexAllocation
  2107.         mov     edi, [ebp+NTFS.attr_offs]
  2108.         mov     byte [edi+attributeType], 0xA0
  2109.         mov     byte [edi+nonResidentFlag], 1
  2110.         mov     byte [edi+nameLength], 4
  2111.         mov     byte [edi+nameOffset], 40h
  2112.         mov     byte [edi+dataRunsOffset], 48h
  2113.         mov     byte [edi+sizeWithHeader], 50h
  2114.         mov     eax, [ebp+NTFS.fileDataSize]
  2115.         dec     eax
  2116.         mov     [edi+lastVCN], eax
  2117.         inc     eax
  2118.         mul     [ebp+NTFS.sectors_per_cluster]
  2119.         shl     eax, 9
  2120.         mov     [edi+attributeAllocatedSize], eax
  2121.         mov     [edi+attributeRealSize], eax
  2122.         mov     [edi+initialDataSize], eax
  2123.         mov     dword[edi+40h], 490024h     ; unicode $I30
  2124.         mov     dword[edi+40h+4], 300033h
  2125.         push    edi
  2126.         mov     esi, edi
  2127.         add     edi, 48h
  2128.         call    createMcbEntry
  2129.         mov     esi, [ebp+NTFS.frs_buffer]
  2130.         pop     edi
  2131.         mov     al, [esi+newAttributeID]
  2132.         mov     [edi+attributeID], al
  2133.         add     edi, 50h
  2134.         inc     eax
  2135. ; create $Bitmap
  2136.         mov     [edi+attributeID], al
  2137.         inc     eax
  2138.         mov     [esi+newAttributeID], al
  2139.         mov     byte [edi+attributeType], 0xB0
  2140.         mov     byte [edi+nameLength], 4
  2141.         mov     byte [edi+nameOffset], 18h
  2142.         mov     byte [edi+attributeOffset], 20h
  2143.         mov     byte [edi+sizeWithoutHeader], 8
  2144.         mov     byte [edi+sizeWithHeader], 28h
  2145.         mov     dword[edi+18h], 490024h     ; unicode $I30
  2146.         mov     dword[edi+18h+4], 300033h
  2147.         mov     byte [edi+20h], 1
  2148.         mov     dword[edi+28h], -1
  2149.         add     edi, 30h
  2150.         sub     edi, esi
  2151.         mov     [esi+recordRealSize], edi
  2152.         mov     eax, [ebp+NTFS.fileDataStart]
  2153.         mul     [ebp+NTFS.sectors_per_cluster]
  2154.         mov     edx, eax
  2155.         jmp     @f
  2156.  
  2157. .refresh:
  2158.         mov     [ebp+NTFS.cur_size], 0
  2159.         call    ntfs_read_attr.continue
  2160.         movi    eax, ERROR_FS_FAIL
  2161.         jc      ntfsErrorPop3
  2162.         mov     edx, [ebp+NTFS.LastRead]
  2163. @@:
  2164.         mov     ebx, [ebp+NTFS.cur_index_buf]
  2165.         call    writeRecord
  2166.         mov     ebx, [ebp+NTFS.frs_buffer]
  2167.         mov     edx, [ebp+NTFS.rootLastRead]
  2168.         call    writeRecord
  2169.         mov     esi, [esp+4]
  2170.         call    ntfs_find_lfn.doit2
  2171.         test    eax, eax
  2172.         jz      .errorPop3
  2173.         mov     edi, [ebp+NTFS.cur_index_buf]
  2174.         mov     edx, [esp]
  2175. .indexRecord:
  2176.         add     edi, recordNode
  2177.         add     edx, [edi+nodeRealSize]
  2178.         cmp     [edi+nodeAllocatedSize], edx
  2179.         jc      .arborizeTree
  2180.         mov     [edi+nodeRealSize], edx
  2181.         jmp     .common
  2182.  
  2183. .errorPop3:
  2184.         add     esp, 12
  2185.         jmp     ntfsUnsupported
  2186.  
  2187. .ntfsNodeAlloc:
  2188. ; in: [ebp+NTFS.attr_offs] -> $IndexAllocation
  2189. ;   out:
  2190. ; [ebp+NTFS.newRecord] = node VCN
  2191. ; [ebp+NTFS.cur_offs]
  2192. ; CF=1 -> eax = error code
  2193.         mov     esi, [ebp+NTFS.attr_offs]
  2194.         add     esi, [esi+sizeWithHeader]
  2195.         cmp     byte [esi], 0xB0
  2196.         jnz     .ret
  2197.         movzx   ecx, word [esi+sizeWithoutHeader]
  2198.         shr     ecx, 2
  2199.         movzx   edi, byte [esi+attributeOffset]
  2200.         add     edi, esi
  2201.         mov     edx, edi
  2202.         or      eax, -1
  2203.         repz scasd
  2204.         jnz     @f
  2205.         cmp     [edi], eax
  2206.         jnz     .ret
  2207. ; extend folder $Bitmap
  2208.         add     word [esi+sizeWithHeader], 8
  2209.         add     word [esi+sizeWithoutHeader], 8
  2210.         mov     esi, [ebp+NTFS.frs_buffer]
  2211.         mov     eax, [esi+recordRealSize]
  2212.         add     eax, 8
  2213.         cmp     [esi+recordAllocatedSize], eax
  2214.         jc      .ret
  2215.         mov     [esi+recordRealSize], eax
  2216.         xor     eax, eax
  2217.         stosd
  2218.         mov     [edi], eax
  2219.         mov     [edi+8], eax
  2220.         dec     eax
  2221.         mov     [edi+4], eax
  2222. @@:
  2223.         sub     edi, 4
  2224.         mov     eax, [edi]
  2225.         not     eax
  2226.         bsf     eax, eax
  2227.         bts     [edi], eax
  2228.         sub     edi, edx
  2229.         shl     edi, 3
  2230.         add     eax, edi
  2231.         mul     [ebp+NTFS.cur_subnode_size]
  2232.         mov     [ebp+NTFS.newRecord], eax
  2233.         mov     ecx, [ebp+NTFS.cur_size]
  2234.         cmp     ecx, [ebp+NTFS.cur_subnode_size]
  2235.         jz      @f
  2236.         mul     [ebp+NTFS.sectors_per_cluster]
  2237. @@:
  2238.         mov     [ebp+NTFS.cur_offs], eax
  2239.         add     eax, ecx
  2240.         shl     eax, 9
  2241.         mov     esi, [ebp+NTFS.attr_offs]
  2242.         cmp     [esi+attributeAllocatedSize], eax
  2243.         jnc     @f
  2244.         xor     edx, edx
  2245.         jmp     resizeAttribute
  2246.  
  2247. .ret:
  2248.         movi    eax, ERROR_UNSUPPORTED_FS
  2249.         stc
  2250. @@:
  2251.         ret
  2252.  
  2253. .arborizeTree:      ; find median index
  2254.         mov     ecx, [edi+nodeRealSize]
  2255.         sub     ecx, [edi+indexOffset]
  2256.         shr     ecx, 1
  2257.         add     edi, [edi+indexOffset]
  2258.         xor     eax, eax
  2259. @@:
  2260.         add     edi, eax
  2261.         mov     ax, [edi+indexAllocatedSize]
  2262.         sub     ecx, eax
  2263.         jnc     @b
  2264.         add     eax, 8
  2265.         mov     esi, [ebp+NTFS.secondIndexBuffer]
  2266.         cmp     dword [esi], 'INDX'
  2267.         jz      @f
  2268. ; move index to the root node
  2269.         mov     esi, [ebp+NTFS.frs_buffer]
  2270.         mov     ecx, eax
  2271.         add     ecx, 8
  2272.         add     ecx, [esi+recordRealSize]
  2273.         cmp     [esi+recordAllocatedSize], ecx
  2274.         jc      .growTree
  2275.         push    edi eax
  2276.         call    .ntfsNodeAlloc
  2277.         jc      ntfsErrorPop5
  2278.         pop     eax
  2279.         mov     edi, [ebp+NTFS.indexRoot]
  2280.         add     [ebp+NTFS.attr_offs], eax
  2281.         add     [edi+sizeWithHeader], eax
  2282.         add     [edi+sizeWithoutHeader], eax
  2283.         movzx   ecx, byte [edi+attributeOffset]
  2284.         add     ecx, edi
  2285.         add     [ecx+rootNode+nodeRealSize], eax
  2286.         add     [ecx+rootNode+nodeAllocatedSize], eax
  2287.         add     ecx, [ebp+NTFS.indexPointer]
  2288.         sub     ecx, [ebp+NTFS.secondIndexBuffer]
  2289.         mov     esi, [ebp+NTFS.frs_buffer]
  2290.         add     [esi+recordRealSize], eax
  2291.         add     esi, [esi+recordRealSize]
  2292.         mov     edi, esi
  2293.         sub     esi, eax
  2294.         neg     ecx
  2295.         add     ecx, esi
  2296.         shr     ecx, 2
  2297.         sub     esi, 4
  2298.         sub     edi, 4
  2299.         std
  2300.         rep movsd   ; make space
  2301.         mov     [edi], ecx
  2302.         mov     edi, esi
  2303.         add     edi, 4
  2304.         mov     esi, [esp]
  2305.         add     word [esi+indexAllocatedSize], 8
  2306.         mov     byte [esi+indexFlags], 1
  2307.         mov     ecx, eax
  2308.         sub     ecx, 8
  2309.         shr     ecx, 2
  2310.         cld
  2311.         rep movsd   ; insert index
  2312.         mov     eax, [ebp+NTFS.newRecord]
  2313.         stosd
  2314.         jmp     .splitNode
  2315.  
  2316. .growBranch:    ; move node and replace it with empty one
  2317.         mov     esi, [ebp+NTFS.cur_index_buf]
  2318.         mov     edi, [ebp+NTFS.secondIndexBuffer]
  2319.         mov     eax, [esi+recordVCN]
  2320.         mov     [edi+recordVCN], eax
  2321.         add     edi, recordNode
  2322.         mov     eax, [edi+indexOffset]
  2323.         add     eax, 18h
  2324.         mov     [edi+nodeRealSize], eax
  2325.         add     edi, [edi+indexOffset]
  2326.         mov     ecx, 6
  2327.         xor     eax, eax
  2328.         mov     [ebp+NTFS.indexPointer], edi
  2329.         push    edi
  2330.         rep stosd
  2331.         pop     edi
  2332.         mov     eax, [ebp+NTFS.newRecord]
  2333.         mov     byte [edi+indexAllocatedSize], 18h
  2334.         mov     byte [edi+indexFlags], 3
  2335.         mov     [edi+16], eax
  2336.         mov     [esi+recordVCN], eax
  2337.         mov     eax, [ebp+NTFS.LastRead]
  2338.         mov     [ebp+NTFS.nodeLastRead], eax
  2339.         push    [ebp+NTFS.cur_size]
  2340.         mov     [ebp+NTFS.cur_size], 0
  2341.         call    ntfs_read_attr.continue
  2342.         pop     [ebp+NTFS.cur_size]
  2343.         movi    eax, ERROR_FS_FAIL
  2344.         jc      ntfsErrorPop5
  2345.         pop     eax edi
  2346. @@:         ; move index to the branch node
  2347.         push    edi eax
  2348.         call    .ntfsNodeAlloc
  2349.         jc      ntfsErrorPop5
  2350.         mov     eax, [esp]
  2351.         mov     esi, [ebp+NTFS.secondIndexBuffer]
  2352.         add     esi, recordNode
  2353.         mov     ecx, [esi+nodeRealSize]
  2354.         add     eax, ecx
  2355.         cmp     [esi+nodeAllocatedSize], eax
  2356.         jc      .growBranch
  2357.         mov     [esi+nodeRealSize], eax
  2358.         lea     edi, [esi+eax-4]
  2359.         add     esi, ecx
  2360.         mov     ecx, esi
  2361.         sub     ecx, [ebp+NTFS.indexPointer]
  2362.         shr     ecx, 2
  2363.         sub     esi, 4
  2364.         std
  2365.         rep movsd   ; make space
  2366.         mov     [edi], ecx
  2367.         pop     ecx
  2368.         sub     ecx, 8
  2369.         shr     ecx, 2
  2370.         mov     edi, esi
  2371.         add     edi, 4
  2372.         mov     esi, [esp]
  2373.         add     word [esi+indexAllocatedSize], 8
  2374.         mov     byte [esi+indexFlags], 1
  2375.         cld
  2376.         rep movsd   ; insert index
  2377.         mov     eax, [ebp+NTFS.newRecord]
  2378.         stosd
  2379.         mov     ebx, [ebp+NTFS.secondIndexBuffer]
  2380.         mov     edx, [ebp+NTFS.nodeLastRead]
  2381.         push    esi
  2382.         call    writeRecord
  2383.         pop     esi
  2384. .splitNode:
  2385.         mov     edi, [ebp+NTFS.cur_index_buf]
  2386.         mov     eax, edi
  2387.         add     eax, recordNode
  2388.         add     eax, [edi+recordNode+nodeRealSize]
  2389.         sub     eax, esi
  2390.         push    eax
  2391.         mov     ecx, [edi+recordNode+indexOffset]
  2392.         add     eax, ecx
  2393.         add     ecx, recordNode
  2394.         shr     ecx, 2
  2395.         push    esi
  2396.         mov     esi, edi
  2397.         mov     edi, [ebp+NTFS.secondIndexBuffer]
  2398.         rep movsd
  2399.         pop     esi
  2400.         pop     ecx
  2401.         shr     ecx, 2
  2402.         rep movsd
  2403.         mov     edi, [ebp+NTFS.secondIndexBuffer]
  2404.         mov     [edi+recordNode+nodeRealSize], eax
  2405.         pop     edi
  2406.         mov     cl, 4
  2407.         xor     eax, eax
  2408.         mov     esi, edi
  2409.         rep stosd
  2410.         mov     byte [esi+indexAllocatedSize], 16
  2411.         mov     byte [esi+indexFlags], 2
  2412.         mov     esi, [ebp+NTFS.cur_index_buf]
  2413.         mov     eax, [ebp+NTFS.newRecord]
  2414.         mov     [esi+recordVCN], eax
  2415.         add     esi, recordNode
  2416.         sub     edi, esi
  2417.         mov     [esi+nodeRealSize], edi
  2418.         mov     ebx, [ebp+NTFS.secondIndexBuffer]
  2419.         mov     edx, [ebp+NTFS.LastRead]
  2420.         call    writeRecord
  2421.         jmp     .refresh
  2422.  
  2423. .common:
  2424.         add     edi, edx
  2425.         sub     edi, 4
  2426.         mov     esi, edi
  2427.         sub     esi, [esp]
  2428.         mov     ecx, esi
  2429.         sub     ecx, eax    ; eax = pointer in the record
  2430.         shr     ecx, 2
  2431.         inc     ecx
  2432.         std
  2433.         rep movsd           ; move forward, make space
  2434.         mov     ecx, [esp]
  2435.         shr     ecx, 2
  2436.         xor     eax, eax
  2437.         rep stosd
  2438.         cld
  2439.         add     edi, 4
  2440.         call    ntfsGetTime
  2441.         mov     [edi+fileCreated], eax
  2442.         mov     [edi+fileCreated+4], edx
  2443.         mov     [edi+fileModified], eax
  2444.         mov     [edi+fileModified+4], edx
  2445.         mov     [edi+recordModified], eax
  2446.         mov     [edi+recordModified+4], edx
  2447.         mov     [edi+fileAccessed], eax
  2448.         mov     [edi+fileAccessed+4], edx
  2449.         pop     ecx
  2450.         pop     esi
  2451.         mov     [edi+indexAllocatedSize], cx    ; fill index with data
  2452.         mov     eax, [esp]
  2453.         shl     eax, 1
  2454.         add     eax, 42h
  2455.         mov     [edi+indexRawSize], ax
  2456.         mov     eax, [ebp+NTFS.cur_iRecord]
  2457.         mov     [edi+directoryRecordReference], eax
  2458.         mov     eax, [ebp+NTFS.frs_buffer]
  2459.         mov     eax, [eax+reuseCounter]
  2460.         mov     [edi+directoryReferenceReuse], ax
  2461.         mov     eax, [ebp+NTFS.frs_size]
  2462.         shr     eax, 8
  2463.         add     ecx, 30h+48h+8+18h+8
  2464.         add     ecx, eax
  2465.         mov     eax, [ebp+NTFS.fileRealSize]
  2466.         add     ecx, eax
  2467.         mov     [edi+fileRealSize], eax
  2468.         cmp     [ebp+NTFS.frs_size], ecx
  2469.         jc      @f
  2470.         xor     eax, eax
  2471. @@:
  2472.         mov     ecx, [ebp+NTFS.sectors_per_cluster]
  2473.         shl     ecx, 9
  2474.         add     eax, ecx
  2475.         dec     eax
  2476.         xor     edx, edx
  2477.         div     ecx
  2478.         mov     [ebp+NTFS.fileDataSize], eax
  2479.         mul     ecx
  2480.         mov     [edi+fileAllocatedSize], eax
  2481.         pop     ecx
  2482.         mov     [ebp+NTFS.indexPointer], edi
  2483.         mov     [edi+fileNameLength], cl
  2484.         add     edi, fileName
  2485. @@:         ; record filename
  2486.         lodsb
  2487.         call    ansi2uni_char
  2488.         stosw
  2489.         dec     ecx
  2490.         jnz     @b
  2491.         mov     eax, [ebp+NTFS.LastRead]
  2492.         mov     [ebp+NTFS.nodeLastRead], eax
  2493.         cmp     [ebp+NTFS.bFolder], 0
  2494.         jz      @f
  2495.         mov     edi, [ebp+NTFS.indexPointer]
  2496.         bts     dword [edi+fileFlags], 28
  2497.         jmp     .mftBitmap
  2498.  
  2499. @@: ; 3. File data
  2500.         cmp     [ebp+NTFS.fileDataSize], 0
  2501.         jz      .mftBitmap
  2502.         mov     edi, [ebp+NTFS.BitmapStart]
  2503.         call    ntfsSpaceAlloc
  2504.         jc      ntfsDiskFull
  2505.         mov     eax, [ebp+NTFS.fileDataStart]
  2506.         mul     [ebp+NTFS.sectors_per_cluster]
  2507.         mov     ecx, [ebp+NTFS.fileRealSize]
  2508.         add     ecx, 511
  2509.         shr     ecx, 9
  2510.         mov     ebx, [ebp+NTFS.fileDataBuffer]
  2511.         call    fs_write64_app
  2512.         test    eax, eax
  2513.         jnz     ntfsDevice
  2514.     ; 4. MFT record
  2515. .mftBitmap: ; search for free record
  2516.         mov     edi, [ebp+NTFS.mftBitmapBuffer]
  2517.         mov     ecx, [ebp+NTFS.mftBitmapSize]
  2518.         mov     al, -1
  2519.         add     edi, 3
  2520.         sub     ecx, 3
  2521.         repz scasb
  2522.         dec     edi
  2523.         movzx   eax, byte [edi]
  2524.         not     al
  2525.         bsf     ecx, eax
  2526.         jz      .extendBitmapMFT    ; no free records
  2527.         bts     [edi], ecx
  2528. ; get record location
  2529.         sub     edi, [ebp+NTFS.mftBitmapBuffer]
  2530.         shl     edi, 3
  2531.         add     edi, ecx
  2532.         mov     [ebp+NTFS.newRecord], edi
  2533.         mov     eax, [ebp+NTFS.frs_size]
  2534.         shr     eax, 9
  2535.         mul     edi
  2536.         mov     [ebp+NTFS.cur_iRecord], 0
  2537.         mov     [ebp+NTFS.cur_attr], 0x80
  2538.         mov     [ebp+NTFS.cur_offs], eax
  2539.         push    eax
  2540.         mov     [ebp+NTFS.cur_size], 0
  2541.         mov     eax, [ebp+NTFS.frs_buffer]
  2542.         mov     [ebp+NTFS.cur_buf], eax
  2543.         call    ntfs_read_attr
  2544.         pop     eax
  2545.         jc      ntfsFail
  2546.         cmp     eax, [ebp+NTFS.mftSize]
  2547.         jnc     .extendMFT
  2548.         jmp     .mftRecord
  2549.  
  2550. .extendBitmapMFT:
  2551.         mov     eax, [ebp+NTFS.sectors_per_cluster]
  2552.         mov     [ebp+NTFS.cur_offs], eax
  2553.         shl     eax, 9
  2554.         cmp     [ebp+NTFS.mftBitmapSize], eax
  2555.         jnc     ntfsUnsupported
  2556.         mov     [ebp+NTFS.cur_iRecord], 0
  2557.         mov     [ebp+NTFS.cur_attr], 0xB0
  2558.         mov     [ebp+NTFS.cur_size], 0
  2559.         call    ntfs_read_attr
  2560.         jc      ntfsFail
  2561.         mov     eax, [ebp+NTFS.mft_cluster]
  2562.         mul     [ebp+NTFS.sectors_per_cluster]
  2563.         cmp     eax, [ebp+NTFS.LastRead]
  2564.         jnz     ntfsUnsupported     ; auxiliary record
  2565.         mov     edi, [ebp+NTFS.mftBitmapBuffer]
  2566.         mov     ecx, [ebp+NTFS.mftBitmapSize]
  2567.         add     edi, ecx
  2568.         mov     eax, ecx
  2569.         mov     edx, [ebp+NTFS.attr_offs]
  2570.         add     ecx, 8
  2571.         mov     [edx+attributeRealSize], ecx
  2572.         mov     [edx+initialDataSize], ecx
  2573.         shl     eax, 3
  2574.         mov     [ebp+NTFS.newRecord], eax
  2575.         mov     dword [edi], 1
  2576.         mov     dword [edi+4], 0
  2577.         mov     [ebp+NTFS.cur_attr], 0x80
  2578.         mov     [ebp+NTFS.cur_offs], 0
  2579.         call    ntfs_read_attr.newAttribute
  2580.         jc      ntfsFail
  2581.         mov     [ebp+NTFS.mftBitmapSize], ecx
  2582. .extendMFT:
  2583.         mov     eax, [ebp+NTFS.mft_cluster]
  2584.         mul     [ebp+NTFS.sectors_per_cluster]
  2585.         cmp     eax, [ebp+NTFS.LastRead]
  2586.         jnz     ntfsUnsupported     ; auxiliary record
  2587.         mov     ecx, [ebp+NTFS.attr_offs]
  2588.         mov     eax, [ecx+attributeRealSize]
  2589.         mov     edx, [ecx+attributeRealSize+4]
  2590.         xor     ax, ax
  2591.         add     eax, 10000h
  2592.         adc     edx, 0
  2593.         push    [ebp+NTFS.fileDataStart]
  2594.         push    [ebp+NTFS.fileDataSize]
  2595.         call    resizeAttribute
  2596.         jc      ntfsErrorPop2
  2597.         mov     ebx, [ebp+NTFS.frs_buffer]
  2598.         mov     edx, [ebp+NTFS.LastRead]
  2599.         call    writeRecord     ; $MFT
  2600.         mov     eax, [ebp+NTFS.mftmirr_cluster]
  2601.         mul     [ebp+NTFS.sectors_per_cluster]
  2602.         mov     ecx, [ebp+NTFS.frs_size]
  2603.         shr     ecx, 9
  2604.         call    fs_write64_sys  ; $MFTMirr
  2605. ; update $MFT retrieval information
  2606.         mov     edi, [ebp+NTFS.mft_retrieval_end]
  2607.         mov     eax, [edi-4]
  2608.         add     eax, [edi-8]
  2609.         mov     edx, [ebp+NTFS.fileDataSize]
  2610.         cmp     eax, [ebp+NTFS.fileDataStart]
  2611.         jnz     .newFragment
  2612.         add     [edi-8], edx
  2613.         jmp     @f
  2614. .newFragment:
  2615.         lea     eax, [ebp+NTFS.attrlist_buf]
  2616.         cmp     eax, edi
  2617.         jz      @f
  2618.         mov     [edi], edx
  2619.         mov     eax, [ebp+NTFS.fileDataStart]
  2620.         mov     [edi+4], eax
  2621.         add     [ebp+NTFS.mft_retrieval_end], 8
  2622. @@:
  2623.         mov     eax, [ebp+NTFS.fileDataSize]
  2624.         mul     [ebp+NTFS.sectors_per_cluster]
  2625.         add     [ebp+NTFS.mftSize], eax
  2626.         call    ntfsSpaceClean
  2627.         pop     [ebp+NTFS.fileDataSize]
  2628.         pop     [ebp+NTFS.fileDataStart]
  2629. .mftRecord:
  2630.         mov     ecx, [ebp+NTFS.frs_size]
  2631.         shr     ecx, 2
  2632.         mov     edi, [ebp+NTFS.frs_buffer]
  2633.         xor     eax, eax
  2634.         rep stosd
  2635.         mov     esi, [ebp+NTFS.indexPointer]
  2636.         mov     eax, [ebp+NTFS.newRecord]
  2637.         mov     [esi+fileRecordReference], eax
  2638.         rdtsc
  2639.         mov     [esi+fileReferenceReuse], ax
  2640.         mov     edi, [ebp+NTFS.frs_buffer]
  2641. ; record header
  2642.         mov     [edi+reuseCounter], ax
  2643.         mov     [edi+2ah], ax
  2644.         mov     eax, [ebp+NTFS.frs_size]
  2645.         mov     [edi+recordAllocatedSize], eax
  2646.         shr     eax, 9
  2647.         inc     eax
  2648.         mov     [edi+updateSequenceSize], al
  2649.         shl     eax, 1
  2650.         add     eax, 2ah+7
  2651.         and     eax, not 7
  2652.         mov     dword[edi], 'FILE'
  2653.         mov     byte [edi+updateSequenceOffset], 2ah
  2654.         mov     byte [edi+hardLinkCounter], 1
  2655.         mov     byte [edi+newAttributeID], 3
  2656.         mov     [edi+attributeOffset], al
  2657.         add     edi, eax
  2658. ; $StandardInformation
  2659.         mov     byte [edi+attributeType], 10h
  2660.         mov     byte [edi+sizeWithHeader], 48h
  2661.         mov     byte [edi+sizeWithoutHeader], 30h
  2662.         mov     byte [edi+attributeOffset], 18h
  2663.         mov     cl, 8
  2664.         add     esi, fileCreated
  2665.         add     edi, 18h
  2666.         rep movsd
  2667.         add     edi, 16
  2668.         mov     esi, [ebp+NTFS.indexPointer]
  2669. ; $FileName
  2670.         mov     byte [edi+attributeType], 30h
  2671.         mov     byte [edi+attributeID], 1
  2672.         mov     byte [edi+attributeOffset], 18h
  2673.         mov     byte [edi+indexedFlag], 1
  2674.         mov     cx, [esi+indexRawSize]
  2675.         mov     [edi+sizeWithoutHeader], ecx
  2676.         mov     cx, [esi+indexAllocatedSize]
  2677.         add     ecx, 8
  2678.         mov     [edi+sizeWithHeader], ecx
  2679.         add     edi, 18h
  2680.         add     esi, 16
  2681.         sub     ecx, 18h
  2682.         shr     ecx, 2
  2683.         rep movsd
  2684.         mov     byte [edi+sizeWithHeader], 50h
  2685.         mov     byte [edi+attributeID], 2
  2686.         cmp     [ebp+NTFS.bFolder], 1
  2687.         jz      .indexRoot
  2688. ; $Data
  2689.         mov     byte [edi+attributeType], 80h
  2690.         mov     eax, [ebp+NTFS.fileDataSize]
  2691.         test    eax, eax
  2692.         jz      .resident
  2693.         mov     esi, [ebp+NTFS.indexPointer]
  2694.         dec     eax
  2695.         mov     [edi+lastVCN], eax
  2696.         mov     byte [edi+nonResidentFlag], 1
  2697.         mov     byte [edi+dataRunsOffset], 40h
  2698.         mov     eax, [esi+fileAllocatedSize]
  2699.         mov     [edi+attributeAllocatedSize], eax
  2700.         mov     eax, [esi+fileRealSize]
  2701.         mov     [edi+attributeRealSize], eax
  2702.         mov     [edi+initialDataSize], eax
  2703.         push    edi
  2704.         mov     esi, edi
  2705.         add     edi, 40h
  2706.         call    createMcbEntry
  2707.         inc     edi
  2708.         jmp     @f
  2709.  
  2710. .resident:
  2711.         mov     ecx, [ebp+NTFS.fileRealSize]
  2712.         mov     [edi+sizeWithoutHeader], ecx
  2713.         mov     byte [edi+attributeOffset], 18h
  2714.         push    edi
  2715.         mov     esi, [ebp+NTFS.fileDataBuffer]
  2716.         add     edi, 18h
  2717.         rep movsb
  2718. @@:
  2719.         mov     eax, edi
  2720.         pop     edi
  2721.         sub     eax, edi
  2722.         add     eax, 7
  2723.         and     eax, not 7
  2724.         mov     [edi+sizeWithHeader], eax
  2725.         add     edi, eax
  2726.         mov     al, 1
  2727.         jmp     .end
  2728.  
  2729. .indexRoot:
  2730.         mov     byte [edi+attributeType], 90h
  2731.         mov     byte [edi+nameLength], 4
  2732.         mov     byte [edi+nameOffset], 18h
  2733.         mov     byte [edi+sizeWithoutHeader], 30h
  2734.         mov     byte [edi+attributeOffset], 20h
  2735.         mov     dword[edi+18h], 490024h     ; unicode $I30
  2736.         mov     dword[edi+18h+4], 300033h
  2737.         mov     byte [edi+20h+indexedAttributesType], 30h
  2738.         mov     byte [edi+20h+collationRule], 1
  2739.         mov     eax, [ebp+NTFS.sectors_per_cluster]
  2740.         mov     dl, 1
  2741.         shl     eax, 8
  2742. @@:
  2743.         shl     eax, 1
  2744.         shl     edx, 1
  2745.         cmp     eax, [ebp+NTFS.frs_size]
  2746.         jc      @b
  2747.         shr     edx, 1
  2748.         mov     [edi+20h+indexRecordSize], eax
  2749.         mov     [edi+20h+indexRecordSizeClus], dl
  2750.         mov     byte [edi+30h+indexOffset], 16
  2751.         mov     byte [edi+30h+nodeRealSize], 32
  2752.         mov     byte [edi+30h+nodeAllocatedSize], 32
  2753.         mov     byte [edi+40h+indexAllocatedSize], 16
  2754.         mov     byte [edi+40h+indexFlags], 2
  2755.         add     edi, 50h
  2756.         mov     al, 3
  2757. .end:
  2758.         mov     ebx, [ebp+NTFS.frs_buffer]
  2759.         mov     dword [edi], -1
  2760.         mov     dword [edi+4], 0
  2761.         add     edi, 8
  2762.         sub     edi, ebx
  2763.         mov     [ebx+recordFlags], al
  2764.         mov     [ebx+recordRealSize], edi
  2765.         mov     edx, [ebp+NTFS.LastRead]
  2766.         call    writeRecord
  2767. ; write MFT bitmap
  2768.         mov     eax, [ebp+NTFS.newRecord]
  2769.         shr     eax, 3+9
  2770.         mov     ebx, eax
  2771.         shl     ebx, 9
  2772.         add     eax, [ebp+NTFS.mftBitmapLocation]
  2773.         add     ebx, [ebp+NTFS.mftBitmapBuffer]
  2774.         mov     ecx, 1
  2775.         xor     edx, edx
  2776.         call    fs_write64_sys
  2777. ; 5. Write directory node
  2778.         mov     ebx, [ebp+NTFS.cur_index_buf]
  2779.         mov     edx, [ebp+NTFS.nodeLastRead]
  2780.         call    writeRecord
  2781.         mov     ebx, [ebp+NTFS.fileRealSize]
  2782. ntfsDone:
  2783.         mov     esi, [ebp+PARTITION.Disk]
  2784.         call    disk_sync
  2785.         call    ntfs_unlock
  2786.         xor     eax, eax
  2787.         ret
  2788.  
  2789. writeRecord:
  2790. ; make updateSequence and write to disk
  2791. ;   in:
  2792. ; ebx -> record
  2793. ; edx = partition sector
  2794.         mov     esi, ebx
  2795.         mov     edi, ebx
  2796.         movzx   ecx, word [esi+updateSequenceOffset]
  2797.         add     edi, ecx
  2798.         mov     ax, [edi]
  2799.         inc     ax
  2800.         stosw
  2801.         mov     cx, [esi+updateSequenceSize]
  2802.         dec     ecx
  2803.         push    ecx
  2804. @@:
  2805.         add     esi, 510
  2806.         movsw
  2807.         mov     [esi-2], ax
  2808.         dec     ecx
  2809.         jnz     @b
  2810.         mov     eax, edx
  2811.         xor     edx, edx
  2812.         pop     ecx
  2813.         jmp     fs_write64_sys
  2814.  
  2815. createMcbEntry:
  2816. ;   in:
  2817. ; [ebp+NTFS.fileDataStart] = position value
  2818. ; [ebp+NTFS.fileDataSize] = size value
  2819. ; edi -> destination
  2820. ; esi -> attribute header
  2821.         mov     eax, [ebp+NTFS.fileDataStart]
  2822.         xor     edx, edx
  2823.         shl     eax, 1
  2824.         jnc     @f
  2825.         not     eax
  2826. @@:
  2827.         inc     edx
  2828.         shr     eax, 8
  2829.         jnz     @b
  2830.         mov     eax, [ebp+NTFS.fileDataSize]
  2831.         shl     eax, 1
  2832.         xor     ecx, ecx
  2833. @@:
  2834.         inc     ecx
  2835.         shr     eax, 8
  2836.         jnz     @b
  2837.         lea     eax, [edi+edx+1]
  2838.         add     eax, ecx
  2839.         sub     eax, esi
  2840.         sub     eax, [esi+sizeWithHeader]
  2841.         jc      @f
  2842.         add     word [esi+sizeWithHeader], 8    ; extend attribute
  2843.         mov     esi, [ebp+NTFS.frs_buffer]
  2844.         mov     eax, [esi+recordRealSize]
  2845.         add     eax, 8
  2846.         cmp     [esi+recordAllocatedSize], eax
  2847.         jc      .end    ; no space in the record
  2848.         mov     [esi+recordRealSize], eax
  2849.         push    ecx edi
  2850.         add     esi, eax
  2851.         mov     ecx, esi
  2852.         sub     ecx, edi
  2853.         sub     ecx, 8
  2854.         shr     ecx, 2
  2855.         mov     edi, esi
  2856.         sub     edi, 4
  2857.         sub     esi, 12
  2858.         std
  2859.         rep movsd
  2860.         cld
  2861.         pop     edi ecx
  2862. @@:
  2863.         mov     eax, edx
  2864.         shl     eax, 4
  2865.         add     eax, ecx
  2866.         stosb
  2867.         lea     esi, [ebp+NTFS.fileDataSize]
  2868.         rep movsb
  2869.         lea     esi, [ebp+NTFS.fileDataStart]
  2870.         mov     ecx, edx
  2871.         rep movsb
  2872.         mov     [edi], cl
  2873. .end:
  2874.         ret
  2875.  
  2876. resizeAttribute:
  2877. ;   in:
  2878. ; [ebp+NTFS.frs_buffer] -> file record
  2879. ; [ebp+NTFS.attr_offs] -> attribute
  2880. ; edx:eax = new size
  2881. ;   out:
  2882. ; [ebp+NTFS.fileDataSize] = clusters added (positive)
  2883. ; [ebp+NTFS.fileDataStart] = added block
  2884. ; CF=1 -> eax = error code
  2885.         mov     esi, [ebp+NTFS.attr_offs]
  2886.         mov     dword [ebp+NTFS.attr_size], eax
  2887.         mov     dword [ebp+NTFS.attr_size+4], edx
  2888.         cmp     byte [esi+nonResidentFlag], 0
  2889.         jz      .resident
  2890.         mov     ecx, [ebp+NTFS.sectors_per_cluster]
  2891.         shl     ecx, 9
  2892.         mov     [esi+attributeRealSize], eax
  2893.         mov     [esi+attributeRealSize+4], edx
  2894.         mov     [esi+initialDataSize], eax
  2895.         mov     [esi+initialDataSize+4], edx
  2896.         sub     eax, 1
  2897.         sbb     edx, 0
  2898.         jc      .makeResident
  2899.         div     ecx
  2900.         mov     edi, eax
  2901.         inc     eax
  2902.         mul     ecx
  2903.         mov     [esi+attributeAllocatedSize], eax
  2904.         mov     [esi+attributeAllocatedSize+4], edx
  2905.         mov     ecx, [esi+lastVCN]
  2906.         mov     [esi+lastVCN], edi
  2907.         movzx   eax, byte [esi+dataRunsOffset]
  2908.         sub     edi, ecx
  2909.         mov     [ebp+NTFS.fileDataSize], edi
  2910.         jz      .done
  2911.         jc      .shrinkAttribute
  2912. ; extend attribute
  2913.         xor     edi, edi
  2914.         add     esi, eax
  2915.         push    edi edi edi edi
  2916. @@:
  2917.         mov     edx, eax
  2918.         mov     eax, esi
  2919.         add     edi, [esp+8]
  2920.         call    ntfs_decode_mcb_entry
  2921.         jc      @b
  2922.         mov     [esp+4], edx
  2923.         mov     [esp+12], edi
  2924.         add     edi, [esp]
  2925.         push    edi
  2926.         shr     edi, 5
  2927.         shl     edi, 2
  2928.         push    eax
  2929.         cmp     [ebp+NTFS.cur_iRecord], 0
  2930.         jz      @f
  2931.         cmp     edi, [ebp+NTFS.BitmapStart]
  2932.         jc      .err1
  2933. @@:
  2934.         call    ntfsSpaceAlloc
  2935.         jc      .err1
  2936.         mov     eax, [ebp+NTFS.fileDataStart]
  2937.         pop     edi
  2938.         pop     edx
  2939.         cmp     edx, eax
  2940.         jnz     .newEntry
  2941.         pop     edx
  2942.         pop     edi
  2943.         pop     [ebp+NTFS.fileDataStart]
  2944.         mov     [esp], eax
  2945.         push    [ebp+NTFS.fileDataSize]
  2946.         add     [ebp+NTFS.fileDataSize], edx
  2947.         jmp     @f
  2948.  
  2949. .newEntry:
  2950.         add     esp, 12
  2951.         pop     edx
  2952.         push    eax
  2953.         push    [ebp+NTFS.fileDataSize]
  2954.         sub     eax, edx
  2955.         mov     [ebp+NTFS.fileDataStart], eax
  2956. @@:
  2957.         mov     esi, [ebp+NTFS.attr_offs]
  2958.         call    createMcbEntry
  2959.         pop     [ebp+NTFS.fileDataSize]
  2960.         pop     [ebp+NTFS.fileDataStart]
  2961.         movi    eax, ERROR_UNSUPPORTED_FS
  2962. .done:
  2963.         ret
  2964.  
  2965. .err1:
  2966.         add     esp, 24
  2967.         stc
  2968. .err2:
  2969.         movi    eax, ERROR_DISK_FULL
  2970.         ret
  2971.  
  2972. .err3:
  2973.         movi    eax, ERROR_FS_FAIL
  2974.         add     esp, 20
  2975.         stc
  2976.         ret
  2977.  
  2978. .shrinkAttribute:
  2979.         add     ecx, edi
  2980.         inc     ecx
  2981.         add     esi, eax
  2982.         xor     edi, edi
  2983.         sub     esp, 20
  2984. @@:
  2985.         mov     [esp+16], esi
  2986.         call    ntfs_decode_mcb_entry
  2987.         jnc     .err3
  2988.         add     edi, [esp+8]
  2989.         sub     ecx, [esp]
  2990.         jnc     @b
  2991.         mov     ebx, ecx
  2992.         add     ecx, [esp]
  2993.         mov     eax, [esp+8]
  2994.         mov     [ebp+NTFS.fileDataSize], ecx
  2995.         mov     [ebp+NTFS.fileDataStart], eax
  2996.         push    edi
  2997.         add     edi, ecx
  2998.         neg     ebx
  2999.         call    ntfsSpaceFree
  3000.         pop     edi
  3001.         jc      .end
  3002. @@:
  3003.         call    ntfs_decode_mcb_entry
  3004.         jnc     .end
  3005.         cmp     dword[esp+8], 0
  3006.         jz      @b
  3007.         add     edi, [esp+8]
  3008.         mov     ebx, [esp]
  3009.         call    ntfsSpaceFree
  3010.         jnc     @b
  3011. .end:
  3012.         add     esp, 16
  3013.         pop     edi
  3014.         cmp     [ebp+NTFS.fileDataSize], 0
  3015.         jz      @f
  3016.         mov     esi, [ebp+NTFS.attr_offs]
  3017.         call    createMcbEntry
  3018.         mov     [ebp+NTFS.fileDataSize], 0
  3019. @@:
  3020.         ret
  3021.  
  3022. .resident:
  3023.         test    edx, edx
  3024.         jnz     .nonResident
  3025.         cmp     eax, 8000h
  3026.         jnc     .nonResident
  3027.         add     ax, [esi+attributeOffset]
  3028.         sub     eax, [esi+sizeWithHeader]
  3029.         jc      @f
  3030.         mov     edi, [ebp+NTFS.frs_buffer]
  3031.         mov     ecx, eax
  3032.         add     ecx, [edi+recordRealSize]
  3033.         cmp     [edi+recordAllocatedSize], ecx
  3034.         jc      .nonResident
  3035.         add     eax, 7
  3036.         and     eax, not 7
  3037.         add     [edi+recordRealSize], eax
  3038.         add     edi, [edi+recordRealSize]
  3039.         add     [esi+sizeWithHeader], eax
  3040.         add     esi, [esi+sizeWithHeader]
  3041.         mov     ecx, edi
  3042.         sub     ecx, esi
  3043.         shr     ecx, 2
  3044.         sub     edi, 4
  3045.         mov     esi, edi
  3046.         sub     esi, eax
  3047.         std
  3048.         rep movsd
  3049.         mov     ecx, eax
  3050.         shr     ecx, 2
  3051.         xor     eax, eax
  3052.         rep stosd
  3053.         cld
  3054.         mov     esi, [ebp+NTFS.attr_offs]
  3055. @@:
  3056.         mov     eax, dword [ebp+NTFS.attr_size]
  3057.         mov     [esi+sizeWithoutHeader], eax
  3058.         mov     [ebp+NTFS.fileDataSize], 0
  3059.         clc
  3060.         ret
  3061.  
  3062. .nonResident:   ; convert resident to non-resident
  3063.         mov     eax, dword [ebp+NTFS.attr_size]
  3064.         sub     eax, 1
  3065.         sbb     edx, 0
  3066.         mov     ecx, [ebp+NTFS.sectors_per_cluster]
  3067.         shl     ecx, 9
  3068.         div     ecx
  3069.         inc     eax
  3070.         mov     [ebp+NTFS.fileDataSize], eax
  3071.         mov     edi, [ebp+NTFS.BitmapStart]
  3072.         push    ecx
  3073.         call    ntfsSpaceAlloc
  3074.         pop     ecx
  3075.         jc      .err2
  3076.         mov     esi, [ebp+NTFS.attr_offs]
  3077.         xor     eax, eax
  3078.         xor     edx, edx
  3079. @@:
  3080.         add     eax, ecx
  3081.         inc     edx
  3082.         cmp     eax, [esi+sizeWithoutHeader]
  3083.         jc      @b
  3084.         push    edx
  3085.         push    eax
  3086.         stdcall kernel_alloc, eax
  3087.         mov     ecx, [esp]
  3088.         shr     ecx, 2
  3089.         mov     edi, eax
  3090.         mov     ebx, eax
  3091.         xor     eax, eax
  3092.         rep stosd
  3093.         mov     al, [esi+attributeOffset]
  3094.         mov     ecx, [esi+sizeWithoutHeader]
  3095.         add     esi, eax
  3096.         mov     edi, ebx
  3097.         rep movsb
  3098.         mov     eax, [ebp+NTFS.fileDataStart]
  3099.         mul     [ebp+NTFS.sectors_per_cluster]
  3100.         pop     ecx
  3101.         shr     ecx, 9
  3102.         call    fs_write64_app
  3103.         stdcall kernel_free, ebx
  3104.         mov     esi, [ebp+NTFS.attr_offs]
  3105.         add     esi, [esi+sizeWithHeader]
  3106.         mov     ecx, [ebp+NTFS.frs_buffer]
  3107.         add     ecx, [ecx+recordRealSize]
  3108.         sub     ecx, esi
  3109.         shr     ecx, 2
  3110.         lea     edi, [ebp+NTFS.bitmap_buf]
  3111.         push    ecx
  3112.         rep movsd
  3113.         mov     edi, [ebp+NTFS.attr_offs]
  3114.         add     edi, 16
  3115.         mov     cl, 6
  3116.         xor     eax, eax
  3117.         rep stosd
  3118.         mov     edi, [ebp+NTFS.attr_offs]
  3119.         mov     eax, [ebp+NTFS.fileDataSize]
  3120.         dec     eax
  3121.         mov     [edi+lastVCN], eax
  3122.         inc     eax
  3123.         mov     ecx, [ebp+NTFS.sectors_per_cluster]
  3124.         shl     ecx, 9
  3125.         mul     ecx
  3126.         mov     byte [edi+sizeWithHeader], 50h
  3127.         mov     byte [edi+nonResidentFlag], 1
  3128.         mov     byte [edi+dataRunsOffset], 40h
  3129.         mov     [edi+attributeAllocatedSize], eax
  3130.         mov     [edi+attributeAllocatedSize+4], edx
  3131.         mov     eax, dword [ebp+NTFS.attr_size]
  3132.         mov     edx, dword [ebp+NTFS.attr_size+4]
  3133.         mov     [edi+attributeRealSize], eax
  3134.         mov     [edi+attributeRealSize+4], edx
  3135.         mov     [edi+initialDataSize], eax
  3136.         mov     [edi+initialDataSize+4], edx
  3137.         mov     esi, edi
  3138.         add     edi, 40h
  3139.         call    createMcbEntry
  3140.         mov     eax, edi
  3141.         mov     edi, [ebp+NTFS.attr_offs]
  3142.         sub     eax, edi
  3143.         add     eax, 8
  3144.         and     eax, not 7
  3145.         mov     [edi+sizeWithHeader], eax
  3146.         pop     ecx
  3147.         lea     esi, [ebp+NTFS.bitmap_buf]
  3148.         add     edi, eax
  3149.         rep movsd
  3150.         mov     esi, [ebp+NTFS.frs_buffer]
  3151.         sub     edi, esi
  3152.         mov     [esi+recordRealSize], edi
  3153.         pop     edx
  3154.         sub     [ebp+NTFS.fileDataSize], edx
  3155.         add     [ebp+NTFS.fileDataStart], edx
  3156.         ret
  3157.  
  3158. .makeResident:  ; convert non-resident to empty resident
  3159.         movzx   eax, byte [esi+dataRunsOffset]
  3160.         mov     byte [esi+nonResidentFlag], 0
  3161.         mov     dword [esi+sizeWithoutHeader], 0
  3162.         mov     dword [esi+attributeOffset], 18h
  3163.         add     esi, eax
  3164.         xor     edi, edi
  3165.         sub     esp, 16
  3166. @@:
  3167.         call    ntfs_decode_mcb_entry
  3168.         jnc     @f
  3169.         cmp     dword[esp+8], 0
  3170.         jz      @b
  3171.         add     edi, [esp+8]
  3172.         mov     ebx, [esp]
  3173.         call    ntfsSpaceFree
  3174.         jnc     @b
  3175. @@:
  3176.         add     esp, 16
  3177.         mov     [ebp+NTFS.fileDataSize], 0
  3178.         ret
  3179.  
  3180. ntfsSpaceClean:
  3181. ; clean up to 16 Mb of disk space
  3182. ;   in:
  3183. ; [ebp+NTFS.fileDataStart] = block to clean
  3184. ; [ebp+NTFS.fileDataSize] = block size
  3185.         mov     eax, [ebp+NTFS.fileDataSize]
  3186.         test    eax, eax
  3187.         jz      @f
  3188.         mul     [ebp+NTFS.sectors_per_cluster]
  3189.         cmp     eax, 8001h
  3190.         jnc     @f
  3191.         push    eax
  3192.         shl     eax, 9
  3193.         stdcall kernel_alloc, eax
  3194.         pop     ecx
  3195.         test    eax, eax
  3196.         jz      @f
  3197.         push    ecx
  3198.         shl     ecx, 7
  3199.         mov     edi, eax
  3200.         mov     ebx, eax
  3201.         xor     eax, eax
  3202.         rep stosd
  3203.         mov     eax, [ebp+NTFS.fileDataStart]
  3204.         mul     [ebp+NTFS.sectors_per_cluster]
  3205.         mov     [ebp+NTFS.LastRead], eax
  3206.         pop     ecx
  3207.         call    fs_write64_app
  3208.         stdcall kernel_free, ebx
  3209. @@:
  3210.         ret
  3211.  
  3212. ntfsSpaceAlloc:
  3213. ; allocate disk space
  3214. ;   in:
  3215. ; edi = offset in bitmap to start search from
  3216. ; [ebp+NTFS.fileDataSize] = block size in clusters
  3217. ;   out:
  3218. ; [ebp+NTFS.fileDataStart] = allocated block starting cluster
  3219. ; CF=1 -> disk full
  3220.         push    eax
  3221.         mov     ecx, [ebp+NTFS.BitmapBuffer]
  3222.         add     edi, ecx
  3223.         add     ecx, [ebp+NTFS.BitmapSize]
  3224.         sub     ecx, edi
  3225.         jnc     @f
  3226.         call    bitmapBuffering
  3227.         shl     ecx, 2
  3228. @@:
  3229.         shr     ecx, 2
  3230.         mov     eax, [ebp+NTFS.fileDataSize]
  3231.         shr     eax, 5
  3232.         jz      .small
  3233.         mov     ebx, eax    ; bitmap dwords
  3234. .start:
  3235.         mov     ecx, [ebp+NTFS.BitmapBuffer]
  3236.         add     ecx, [ebp+NTFS.BitmapSize]
  3237.         sub     ecx, edi
  3238.         shr     ecx, 2
  3239. @@:
  3240.         xor     eax, eax
  3241.         repnz scasd         ; search for empty dword
  3242.         jz      @f
  3243.         call    bitmapBuffering
  3244.         jmp     @b
  3245. @@:
  3246.         cmp     ecx, ebx
  3247.         jnc     @f
  3248.         call    bitmapBuffering
  3249.         jmp     @b
  3250. @@:
  3251.         sub     edi, 4
  3252.         mov     ecx, ebx
  3253.         mov     esi, edi
  3254.         xor     eax, eax
  3255.         repz scasd          ; check following dwords
  3256.         jnz     .start
  3257.         sub     esi, 4
  3258.         mov     eax, [esi]
  3259.         xor     edx, edx
  3260.         bsr     edx, eax
  3261.         inc     edx
  3262.         push    edx         ; starting bit
  3263.         push    esi         ; starting dword
  3264.         add     esi, 4
  3265.         neg     edx
  3266.         add     edx, 32
  3267.         mov     eax, [ebp+NTFS.fileDataSize]
  3268.         sub     eax, edx
  3269.         mov     edx, eax
  3270.         shr     eax, 5
  3271.         shl     eax, 2
  3272.         add     esi, eax
  3273.         mov     eax, [esi]
  3274.         bsf     ecx, eax    ; check last dword
  3275.         jz      .done
  3276.         and     edx, 31
  3277.         cmp     ecx, edx
  3278.         jnc     .done
  3279.         add     esp, 8
  3280.         jmp     .start
  3281.  
  3282. .small:     ; less than 32 clusters
  3283.         mov     eax, -1
  3284.         repz scasd          ; search for zero bits
  3285.         test    ecx, ecx
  3286.         jnz     @f
  3287.         call    bitmapBuffering
  3288.         jmp     .small
  3289. @@:
  3290.         sub     edi, 4
  3291.         mov     eax, [edi]
  3292.         not     eax
  3293. @@:
  3294.         bsf     ebx, eax    ; first 0
  3295.         jz      .again
  3296.         not     eax
  3297.         shr     eax, cl
  3298.         shl     eax, cl
  3299.         bsf     edx, eax    ; next 1
  3300.         jz      @f
  3301.         sub     edx, ebx
  3302.         cmp     edx, [ebp+NTFS.fileDataSize]
  3303.         jnc     .got        ; fits inside
  3304.         bsf     ebx, eax
  3305.         not     eax
  3306.         shr     eax, cl
  3307.         shl     eax, cl
  3308.         jmp     @b
  3309. @@:         ; next dword
  3310.         mov     eax, [edi+4]
  3311.         bsf     edx, eax
  3312.         jz      .got        ; empty
  3313.         add     edx, 32
  3314.         sub     edx, ebx
  3315.         cmp     edx, [ebp+NTFS.fileDataSize]
  3316.         jnc     .got        ; share between dwords
  3317. .again:
  3318.         add     edi, 4
  3319.         jmp     .small
  3320.  
  3321. .got:
  3322.         push    ebx         ; starting bit
  3323.         push    edi         ; starting dword
  3324. .done:      ; mark space
  3325.         mov     ecx, [esp+4]
  3326.         cmp     ecx, 32
  3327.         jc      @f
  3328.         xor     ecx, ecx
  3329.         add     dword [esp], 4
  3330.         mov     [esp+4], ecx
  3331. @@:
  3332.         mov     edi, [esp]
  3333.         xor     eax, eax
  3334.         dec     eax
  3335.         shr     eax, cl
  3336.         shl     eax, cl
  3337.         neg     ecx
  3338.         add     ecx, 32
  3339.         sub     ecx, [ebp+NTFS.fileDataSize]
  3340.         jc      @f
  3341.         shl     eax, cl     ; fits inside dword
  3342.         shr     eax, cl
  3343.         or      [edi], eax
  3344.         jmp     .end
  3345.  
  3346. @@:
  3347.         or      [edi], eax
  3348.         neg     ecx
  3349.         push    ecx
  3350.         shr     ecx, 5
  3351.         add     edi, 4
  3352.         xor     eax, eax
  3353.         dec     eax
  3354.         rep stosd
  3355.         pop     ecx
  3356.         and     ecx, 31
  3357.         shr     eax, cl
  3358.         shl     eax, cl
  3359.         not     eax
  3360.         or      [edi], eax
  3361. .end:
  3362.         pop     eax
  3363.         pop     ecx
  3364.         sub     eax, [ebp+NTFS.BitmapBuffer]
  3365.         shl     eax, 3
  3366.         add     eax, ecx
  3367.         pop     ecx
  3368.         mov     ecx, [ebp+NTFS.fileDataSize]
  3369.         mov     [ebp+NTFS.fileDataStart], eax
  3370.         add     ecx, eax
  3371.         add     ecx, 4095
  3372.         shr     ecx, 3+9
  3373.         shr     eax, 3+9
  3374.         sub     ecx, eax
  3375.         mov     ebx, eax
  3376.         shl     ebx, 9
  3377.         add     eax, [ebp+NTFS.BitmapLocation]
  3378.         add     ebx, [ebp+NTFS.BitmapBuffer]
  3379.         xor     edx, edx
  3380.         jmp     fs_write64_app
  3381.  
  3382. ntfsSpaceFree:
  3383. ; free disk space
  3384. ;   in:
  3385. ; edi = starting cluster
  3386. ; ebx = size in clusters
  3387.         mov     eax, edi
  3388.         add     eax, ebx
  3389.         shr     eax, 3
  3390.         inc     eax
  3391.         cmp     eax, [ebp+NTFS.BitmapSize]
  3392.         jc      @f
  3393.         add     eax, [ebp+NTFS.BitmapBuffer]
  3394.         push    edi
  3395.         mov     edi, eax
  3396.         call    bitmapBuffering
  3397.         pop     edi
  3398. @@:
  3399.         push    edi
  3400.         mov     ecx, edi
  3401.         shr     edi, 5
  3402.         shl     edi, 2
  3403.         add     edi, [ebp+NTFS.BitmapBuffer]
  3404.         and     ecx, 31
  3405.         xor     eax, eax
  3406.         dec     eax
  3407.         shr     eax, cl
  3408.         shl     eax, cl
  3409.         neg     ecx
  3410.         add     ecx, 32
  3411.         sub     ecx, ebx
  3412.         jc      @f
  3413.         shl     eax, cl     ; fits inside dword
  3414.         shr     eax, cl
  3415.         not     eax
  3416.         and     [edi], eax
  3417.         jmp     .writeBitmap
  3418.  
  3419. @@:
  3420.         not     eax
  3421.         and     [edi], eax
  3422.         neg     ecx
  3423.         push    ecx
  3424.         shr     ecx, 5
  3425.         add     edi, 4
  3426.         xor     eax, eax
  3427.         rep stosd
  3428.         pop     ecx
  3429.         and     ecx, 31
  3430.         dec     eax
  3431.         shr     eax, cl
  3432.         shl     eax, cl
  3433.         and     [edi], eax
  3434. .writeBitmap:
  3435.         pop     eax
  3436.         mov     edi, eax
  3437.         lea     ecx, [eax+ebx+4095]
  3438.         shr     eax, 3+9
  3439.         shr     ecx, 3+9
  3440.         sub     ecx, eax
  3441.         mov     ebx, eax
  3442.         shl     ebx, 9
  3443.         add     eax, [ebp+NTFS.BitmapLocation]
  3444.         add     ebx, [ebp+NTFS.BitmapBuffer]
  3445.         xor     edx, edx
  3446.         jmp     fs_write64_app
  3447.  
  3448. bitmapBuffering:
  3449. ; Extend BitmapBuffer and read next 32kb of bitmap
  3450. ; Warning: $Bitmap fragmentation is not foreseen
  3451. ; in: edi -> position in bitmap buffer
  3452. ; out: ecx = number of buffered dwords left
  3453.         push    ebx
  3454.         mov     eax, [ebp+NTFS.BitmapTotalSize]
  3455.         cmp     eax, [ebp+NTFS.BitmapSize]
  3456.         jz      .end
  3457.         stdcall alloc_pages, 8
  3458.         test    eax, eax
  3459.         jz      .end
  3460.         add     eax, 3
  3461.         mov     ebx, [ebp+NTFS.BitmapBuffer]
  3462.         add     ebx, [ebp+NTFS.BitmapSize]
  3463.         push    ebx
  3464.         mov     ecx, 8
  3465.         call    commit_pages
  3466.         mov     eax, [ebp+NTFS.BitmapSize]
  3467.         shr     eax, 9
  3468.         add     eax, [ebp+NTFS.BitmapLocation]
  3469.         pop     ebx
  3470.         mov     ecx, 64
  3471.         xor     edx, edx
  3472.         call    fs_read64_app
  3473.         test    eax, eax
  3474.         jnz     .err
  3475.         add     [ebp+NTFS.BitmapSize], 8000h
  3476.         mov     eax, [ebp+NTFS.BitmapTotalSize]
  3477.         cmp     eax, [ebp+NTFS.BitmapSize]
  3478.         jnc     @f
  3479.         mov     [ebp+NTFS.BitmapSize], eax
  3480. @@:
  3481.         pop     ebx
  3482.         mov     ecx, [ebp+NTFS.BitmapBuffer]
  3483.         add     ecx, [ebp+NTFS.BitmapSize]
  3484.         sub     ecx, edi
  3485.         jc      bitmapBuffering
  3486.         shr     ecx, 2
  3487.         ret
  3488.  
  3489. .err:
  3490.         mov     eax, [ebp+NTFS.BitmapBuffer]
  3491.         add     eax, [ebp+NTFS.BitmapSize]
  3492.         mov     ecx, 8
  3493.         call    release_pages
  3494. .end:
  3495.         add     esp, 12     ; ret
  3496.         stc
  3497.         ret
  3498.  
  3499. ;----------------------------------------------------------------
  3500. ntfs_WriteFile:
  3501.         cmp     byte [esi], 0
  3502.         jnz     @f
  3503.         xor     ebx, ebx
  3504.         movi    eax, ERROR_ACCESS_DENIED
  3505.         ret
  3506. @@:
  3507.         call    ntfs_lock
  3508.         call    ntfs_find_lfn
  3509.         jc      ntfsNotFound
  3510.         cmp     [ebp+NTFS.cur_iRecord], 16
  3511.         jc      ntfsDenied
  3512.         test    dword [eax+fileFlags], 10000001h
  3513.         jnz     ntfsDenied
  3514.         cmp     [ebp+NTFS.fragmentCount], 1
  3515.         jnz     ntfsUnsupported     ; record fragmented
  3516. ; edit directory node
  3517.         mov     edi, [ebp+NTFS.cur_index_buf]
  3518.         cmp     dword [edi], 'INDX'
  3519.         jz      @f
  3520.         mov     esi, [ebp+NTFS.frs_buffer]
  3521.         mov     ecx, [esi+recordRealSize]
  3522.         shr     ecx, 2
  3523.         rep movsd
  3524.         mov     esi, [ebp+NTFS.attr_offs]
  3525.         mov     cl, [esi+attributeOffset]
  3526.         sub     esi, [ebp+NTFS.frs_buffer]
  3527.         add     eax, ecx
  3528.         add     eax, esi
  3529. @@:
  3530.         mov     edi, eax
  3531.         mov     eax, [ebx+4]
  3532.         mov     edx, [ebx+8]
  3533.         add     eax, [ebx+12]
  3534.         adc     edx, 0
  3535.         mov     [edi+fileRealSize], eax
  3536.         mov     [edi+fileRealSize+4], edx
  3537.         push    edx eax ebx
  3538.         call    ntfsGetTime
  3539.         mov     [edi+fileModified], eax
  3540.         mov     [edi+fileModified+4], edx
  3541.         mov     [edi+recordModified], eax
  3542.         mov     [edi+recordModified+4], edx
  3543.         mov     [edi+fileAccessed], eax
  3544.         mov     [edi+fileAccessed+4], edx
  3545.         pop     ebx ecx edx
  3546.         mov     eax, [ebp+NTFS.LastRead]
  3547.         mov     [ebp+NTFS.nodeLastRead], eax
  3548.         mov     [ebp+NTFS.cur_attr], 0x80
  3549.         mov     [ebp+NTFS.cur_offs], 0
  3550.         mov     [ebp+NTFS.cur_size], 0
  3551.         call    ntfs_read_attr
  3552.         jc      ntfsFail
  3553.         mov     esi, edi
  3554.         mov     edi, [ebp+NTFS.frs_buffer]
  3555.         cmp     word [edi+baseRecordReuse], 0
  3556.         jnz     ntfsUnsupported     ; auxiliary record
  3557.         mov     al, [edi+attributeOffset]
  3558.         add     edi, eax
  3559.         mov     al, [edi+attributeOffset]
  3560.         add     edi, eax
  3561.         mov     eax, ecx
  3562.         mov     ecx, 6
  3563.         add     esi, fileModified
  3564.         add     edi, 8
  3565.         rep movsd
  3566.         mov     ecx, [ebp+NTFS.attr_offs]
  3567.         cmp     word [ecx+attributeFlags], 0
  3568.         jnz     ntfsUnsupported
  3569.         push    ebx
  3570.         cmp     byte [ecx+nonResidentFlag], 0
  3571.         jz      .resizeAttribute
  3572.         cmp     edx, [ecx+attributeRealSize+4]
  3573.         jc      .writeNode
  3574.         jnz     .resizeAttribute
  3575.         cmp     [ecx+attributeRealSize], eax
  3576.         jnc     .writeNode
  3577. .resizeAttribute:
  3578.         call    resizeAttribute
  3579.         jc      ntfsErrorPop
  3580.         mov     ecx, [ebp+NTFS.attr_offs]
  3581.         cmp     byte [ecx+nonResidentFlag], 1
  3582.         jz      @f
  3583.         mov     ebx, [esp]
  3584.         movzx   edi, byte [ecx+attributeOffset]
  3585.         add     edi, ecx
  3586.         add     edi, [ebx+4]
  3587.         mov     ecx, [ebx+12]
  3588.         mov     esi, [ebx+16]
  3589.         rep movsb
  3590. @@:
  3591.         mov     ebx, [ebp+NTFS.frs_buffer]
  3592.         mov     edx, [ebp+NTFS.mftLastRead]
  3593.         call    writeRecord     ; file
  3594.         call    ntfs_restore_usa_frs
  3595. .writeNode:
  3596.         mov     ebx, [ebp+NTFS.cur_index_buf]
  3597.         mov     edx, [ebp+NTFS.nodeLastRead]
  3598.         call    writeRecord     ; directory
  3599.         pop     ebx
  3600.         mov     ecx, [ebp+NTFS.attr_offs]
  3601.         cmp     byte [ecx+nonResidentFlag], 0
  3602.         jz      .done
  3603.         mov     ecx, [ebx+12]
  3604.         test    ecx, ecx
  3605.         jz      .done
  3606.         mov     eax, [ebx+4]
  3607.         mov     edx, [ebx+8]
  3608.         mov     esi, [ebx+16]
  3609.         shrd    eax, edx, 9
  3610.         test    dword[ebx+4], 1FFh
  3611.         jz      .aligned
  3612.         mov     [ebp+NTFS.cur_offs], eax
  3613.         mov     [ebp+NTFS.cur_size], 1
  3614.         lea     edi, [ebp+NTFS.bitmap_buf]
  3615.         mov     [ebp+NTFS.cur_buf], edi
  3616.         call    ntfs_read_attr.continue
  3617.         jc      ntfsDevice
  3618.         mov     eax, [ebx+4]
  3619.         and     eax, 1FFh
  3620.         add     edi, eax
  3621.         sub     eax, [ebp+NTFS.cur_read]
  3622.         neg     eax
  3623.         push    ecx
  3624.         cmp     ecx, eax
  3625.         jb      @f
  3626.         mov     ecx, eax
  3627. @@:
  3628.         sub     [esp], ecx
  3629.         rep movsb
  3630.         push    ebx
  3631.         mov     eax, [ebp+NTFS.LastRead]
  3632.         lea     ebx, [ebp+NTFS.bitmap_buf]
  3633.         mov     ecx, 1
  3634.         xor     edx, edx
  3635.         call    fs_write64_app
  3636.         pop     ebx
  3637.         pop     ecx
  3638.         test    ecx, ecx
  3639.         jz      .done
  3640.         mov     eax, [ebx+4]
  3641.         mov     edx, [ebx+8]
  3642.         shrd    eax, edx, 9
  3643.         inc     eax
  3644. .aligned:
  3645.         push    ecx
  3646.         shr     ecx, 9
  3647.         mov     [ebp+NTFS.cur_offs], eax
  3648.         mov     [ebp+NTFS.cur_size], ecx
  3649.         mov     [ebp+NTFS.cur_buf], esi
  3650.         add     eax, ecx
  3651.         push    eax
  3652.         mov     [ebp+NTFS.bWriteAttr], 1
  3653.         call    ntfs_read_attr.continue
  3654.         mov     [ebp+NTFS.bWriteAttr], 0
  3655.         pop     [ebp+NTFS.cur_offs]
  3656.         pop     ecx
  3657.         jc      ntfsDevice
  3658.         and     ecx, 1FFh
  3659.         jz      .done
  3660.         add     esi, [ebp+NTFS.cur_read]
  3661.         mov     [ebp+NTFS.cur_size], 1
  3662.         lea     edi, [ebp+NTFS.bitmap_buf]
  3663.         mov     [ebp+NTFS.cur_buf], edi
  3664.         call    ntfs_read_attr.continue
  3665.         jc      ntfsDevice
  3666.         rep movsb
  3667.         push    ebx
  3668.         mov     eax, [ebp+NTFS.LastRead]
  3669.         lea     ebx, [ebp+NTFS.bitmap_buf]
  3670.         mov     ecx, 1
  3671.         xor     edx, edx
  3672.         call    fs_write64_app
  3673.         pop     ebx
  3674. .done:
  3675.         mov     ebx, [ebx+12]
  3676.         jmp     ntfsDone
  3677.  
  3678. ;----------------------------------------------------------------
  3679. ntfs_Delete:
  3680.         cmp     byte [esi], 0
  3681.         jnz     @f
  3682.         xor     ebx, ebx
  3683.         movi    eax, ERROR_ACCESS_DENIED
  3684.         ret
  3685.  
  3686. @@:
  3687.         call    ntfs_lock
  3688.         call    ntfs_find_lfn
  3689.         jc      ntfsNotFound
  3690.         cmp     [ebp+NTFS.cur_iRecord], 16
  3691.         jc      ntfsDenied
  3692.         test    byte [eax+fileFlags], 1
  3693.         jnz     ntfsDenied
  3694.         cmp     [ebp+NTFS.fragmentCount], 1
  3695.         jnz     ntfsUnsupported     ; record fragmented
  3696.         mov     ebx, [eax+directoryRecordReference]
  3697.         mov     [ebp+NTFS.newRecord], ebx
  3698.         mov     bx, [eax+fileReferenceReuse]
  3699.         mov     [ebp+NTFS.indexPointer], esi
  3700.         mov     eax, [ebp+NTFS.cur_iRecord]
  3701.         shr     eax, 3
  3702.         cmp     eax, [ebp+NTFS.mftBitmapSize]
  3703.         jnc     ntfsUnsupported
  3704. ; examine file record
  3705.         mov     [ebp+NTFS.cur_attr], 0x80   ; file?
  3706.         mov     [ebp+NTFS.cur_offs], 0
  3707.         mov     [ebp+NTFS.cur_size], 0
  3708.         call    ntfs_read_attr
  3709.         jnc     @f
  3710.         xor     eax, eax
  3711.         push    ebx eax eax eax eax
  3712.         mov     [esp+12], esp
  3713.         push    eax
  3714.         mov     ebx, esp
  3715.         mov     [ebp+NTFS.cur_attr], 0x90   ; folder?
  3716.         call    ntfs_ReadFolder.doit
  3717.         mov     edx, [esp+12]
  3718.         add     esp, 20
  3719.         pop     ebx
  3720.         test    eax, eax
  3721.         jnz     .ret
  3722.         cmp     edx, 2
  3723.         jnz     ntfsDenied      ; folder is not empty
  3724.         mov     [ebp+NTFS.cur_attr], 0xA0
  3725.         mov     [ebp+NTFS.cur_offs], 0
  3726.         mov     [ebp+NTFS.cur_size], 0
  3727.         call    ntfs_read_attr.newAttribute
  3728.         jc      .deleteFileRecord
  3729. @@:
  3730.         mov     esi, [ebp+NTFS.frs_buffer]
  3731.         cmp     word [esi+baseRecordReuse], 0
  3732.         jnz     ntfsUnsupported     ; auxiliary record
  3733.         cmp     word [esi+reuseCounter], bx
  3734.         jnz     .backToIndex        ; broken index
  3735.         test    byte [esi+recordFlags], 1
  3736.         jz      .writeBitmapMFT     ; record deleted
  3737.         cmp     byte [esi+hardLinkCounter], 3
  3738.         jnc     ntfsUnsupported
  3739.         mov     esi, [ebp+NTFS.attr_offs]
  3740.         cmp     byte [esi+nonResidentFlag], 0
  3741.         jz      .deleteFileRecord
  3742.         movzx   eax, byte [esi+dataRunsOffset]
  3743.         add     esi, eax
  3744.         xor     edi, edi
  3745.         sub     esp, 16
  3746. @@:
  3747.         call    ntfs_decode_mcb_entry
  3748.         jnc     @f
  3749.         cmp     dword[esp+8], 0
  3750.         jz      @b
  3751.         add     edi, [esp+8]
  3752.         mov     ebx, [esp]
  3753.         call    ntfsSpaceFree
  3754.         jnc     @b
  3755. @@:
  3756.         add     esp, 16
  3757. .deleteFileRecord:
  3758.         mov     ebx, [ebp+NTFS.frs_buffer]
  3759.         mov     byte [ebx+recordFlags], 0
  3760.         mov     edx, [ebp+NTFS.mftLastRead]
  3761.         call    writeRecord
  3762. .writeBitmapMFT:
  3763.         mov     eax, [ebp+NTFS.cur_iRecord]
  3764.         mov     ecx, eax
  3765.         shr     eax, 3
  3766.         and     ecx, 7
  3767.         mov     edi, [ebp+NTFS.mftBitmapBuffer]
  3768.         btr     [edi+eax], ecx
  3769.         shr     eax, 9
  3770.         mov     ebx, eax
  3771.         shl     ebx, 9
  3772.         add     eax, [ebp+NTFS.mftBitmapLocation]
  3773.         add     ebx, edi
  3774.         mov     ecx, 1
  3775.         xor     edx, edx
  3776.         call    fs_write64_sys
  3777. .backToIndex:
  3778.         mov     eax, [ebp+NTFS.newRecord]
  3779.         mov     [ebp+NTFS.cur_iRecord], eax
  3780.         mov     esi, [ebp+NTFS.indexPointer]
  3781.         call    ntfs_find_lfn.doit2
  3782.         jc      ntfsFail
  3783.         mov     ebx, [ebp+NTFS.secondIndexBuffer]
  3784.         mov     byte [ebx], 0
  3785.         mov     ebx, [ebp+NTFS.LastRead]
  3786.         mov     [ebp+NTFS.nodeLastRead], ebx
  3787.         xor     ebx, ebx
  3788.         test    byte [eax+indexFlags], 1
  3789.         jz      .deleteIndex    ; no subnode
  3790.         mov     edi, eax
  3791.         call    .findSubindex
  3792.         jc      ntfsFail
  3793.         movzx   edx, word [edi+indexAllocatedSize]
  3794.         test    esi, esi
  3795.         jz      @f
  3796.         sub     edx, eax
  3797.         sub     edx, 8
  3798. @@:
  3799.         mov     eax, edi
  3800.         mov     ebx, esi
  3801.         jmp     @f
  3802.  
  3803. .deleteIndex:
  3804.         movzx   edx, word [eax+indexAllocatedSize]
  3805.         mov     ecx, [eax+fileRecordReference]
  3806.         cmp     [eax+edx+fileRecordReference], ecx
  3807.         jnz     @f
  3808.         add     dx, [eax+edx+indexAllocatedSize]
  3809. @@:
  3810.         mov     edi, [ebp+NTFS.cur_index_buf]
  3811.         cmp     dword [edi], 'INDX'
  3812.         jz      .indexRecord
  3813.         sub     eax, edi
  3814.         mov     edi, [ebp+NTFS.indexRoot]
  3815.         sub     [edi+sizeWithHeader], edx
  3816.         sub     [edi+sizeWithoutHeader], edx
  3817.         movzx   ecx, byte [edi+attributeOffset]
  3818.         add     edi, ecx
  3819.         add     eax, edi
  3820.         sub     [edi+rootNode+nodeRealSize], edx
  3821.         sub     [edi+rootNode+nodeAllocatedSize], edx
  3822.         mov     edi, [ebp+NTFS.frs_buffer]
  3823.         sub     [edi+recordRealSize], edx
  3824.         mov     ecx, [edi+recordRealSize]
  3825.         cmp     [edi+recordAllocatedSize], ecx
  3826.         jmp     @f
  3827.  
  3828. .indexRecord:
  3829.         add     edi, recordNode
  3830.         sub     [edi+nodeRealSize], edx
  3831.         mov     ecx, [edi+nodeRealSize]
  3832.         cmp     [edi+nodeAllocatedSize], ecx
  3833. @@:
  3834.         jc      ntfsUnsupported
  3835.         add     ecx, edi
  3836.         sub     ecx, eax
  3837.         mov     esi, eax
  3838.         add     esi, edx
  3839.         mov     edi, eax
  3840.         test    edx, edx
  3841.         jns     @f
  3842.         neg     edx
  3843.         add     edx, ecx
  3844.         sub     edx, 4
  3845.         add     esi, edx
  3846.         add     edi, edx
  3847.         std
  3848. @@:
  3849.         jz      @f
  3850.         shr     ecx, 2
  3851.         rep movsd
  3852.         cld
  3853. @@:
  3854.         test    ebx, ebx
  3855.         jz      .done
  3856. ; copy index from the subnode to replace deleted pointing index
  3857.         movzx   ecx, word [ebx+indexAllocatedSize]
  3858.         mov     edx, ecx
  3859.         test    byte [ebx+indexFlags], 1
  3860.         jz      @f
  3861.         sub     ecx, 8
  3862.         movzx   edi, word [ebx+edx+indexAllocatedSize]
  3863.         add     edi, edx
  3864.         mov     esi, [ebx+ecx]
  3865.         mov     [ebx+edi-8], esi
  3866.         mov     [ebx+indexAllocatedSize], cx
  3867. @@:
  3868.         shr     ecx, 2
  3869.         mov     esi, ebx
  3870.         mov     edi, eax
  3871.         rep movsd
  3872.         add     word [eax+indexAllocatedSize], 8
  3873.         mov     byte [eax+indexFlags], 1
  3874.         mov     edi, [ebp+NTFS.secondIndexBuffer]
  3875.         mov     eax, ebx
  3876.         xor     ebx, ebx
  3877.         jmp     .indexRecord
  3878.  
  3879. .done:
  3880.         mov     ebx, [ebp+NTFS.frs_buffer]
  3881.         mov     edx, [ebp+NTFS.rootLastRead]
  3882.         call    writeRecord
  3883.         mov     ebx, [ebp+NTFS.cur_index_buf]
  3884.         cmp     dword [ebx], 'INDX'
  3885.         jnz     @f
  3886.         mov     edx, [ebp+NTFS.nodeLastRead]
  3887.         call    writeRecord
  3888. @@:
  3889.         mov     ebx, [ebp+NTFS.secondIndexBuffer]
  3890.         cmp     byte [ebx], 0
  3891.         jz      ntfsDone
  3892.         mov     edx, [ebp+NTFS.LastRead]
  3893.         call    writeRecord
  3894.         jmp     ntfsDone
  3895.  
  3896. .findSubindex:
  3897. ; in: eax -> index
  3898. ;   out:
  3899. ; CF=1 -> error
  3900. ; esi=0 -> subnode deleted
  3901. ; esi -> replacement index
  3902. ; eax = index effective size
  3903.         movzx   edx, word [eax+indexAllocatedSize]
  3904.         mov     eax, [eax+edx-8]
  3905.         mov     edx, [ebp+NTFS.cur_size]
  3906.         push    edx
  3907.         cmp     edx, [ebp+NTFS.cur_subnode_size]
  3908.         jz      @f
  3909.         mul     [ebp+NTFS.sectors_per_cluster]
  3910. @@:
  3911.         mov     [ebp+NTFS.cur_attr], 0xA0
  3912.         mov     [ebp+NTFS.cur_offs], eax
  3913.         push    eax
  3914.         mov     ebx, [ebp+NTFS.secondIndexBuffer]
  3915.         mov     esi, ebx
  3916.         mov     [ebp+NTFS.cur_buf], ebx
  3917.         call    ntfs_read_attr.newAttribute
  3918.         pop     [ebp+NTFS.cur_offs]
  3919.         pop     eax
  3920.         jc      .ret
  3921.         cmp     dword [esi], 'INDX'
  3922.         stc
  3923.         jnz     .ret
  3924.         mov     [ebp+NTFS.cur_size], eax
  3925.         shl     eax, 9
  3926.         call    ntfs_restore_usa
  3927.         jc      .ret
  3928.         add     esi, recordNode
  3929.         add     esi, [esi+indexOffset]
  3930.         test    byte [esi+indexFlags], 2
  3931.         jnz     .emptyNode
  3932.         cmp     [ebp+NTFS.fragmentCount], 1
  3933.         stc
  3934.         jnz     .ret    ; record fragmented
  3935.         xor     eax, eax
  3936. @@:
  3937.         add     esi, eax
  3938.         mov     ax, [esi+indexAllocatedSize]
  3939.         test    byte [esi+eax+indexFlags], 2
  3940.         jz      @b
  3941.         test    byte [esi+indexFlags], 1
  3942.         jz      .ret
  3943.         add     eax, esi
  3944.         push    esi
  3945.         push    [ebp+NTFS.cur_offs]
  3946.         call    .findSubindex
  3947.         pop     [ebp+NTFS.cur_offs]
  3948.         pop     edx
  3949.         jc      .ret
  3950.         test    esi, esi
  3951.         jnz     .ret
  3952.         mov     esi, edx
  3953.         mov     ebx, [ebp+NTFS.secondIndexBuffer]
  3954.         mov     [ebp+NTFS.cur_buf], ebx
  3955.         push    [ebp+NTFS.cur_size]
  3956.         call    ntfs_read_attr.continue
  3957.         pop     eax
  3958.         jc      .ret
  3959.         shl     eax, 9
  3960.         call    ntfs_restore_usa
  3961.         jc      .ret
  3962.         movzx   eax, word [esi+indexAllocatedSize]
  3963.         sub     eax, 8
  3964. .ret:
  3965.         ret
  3966.  
  3967. .emptyNode:
  3968.         test    byte [esi+indexFlags], 1
  3969.         jz      @f
  3970.         mov     eax, esi
  3971.         push    [ebp+NTFS.cur_offs]
  3972.         call    .findSubindex
  3973.         pop     [ebp+NTFS.cur_offs]
  3974.         jc      .ret
  3975.         test    esi, esi
  3976.         jnz     .ret
  3977. @@:         ; delete node
  3978.         mov     esi, [ebp+NTFS.attr_offs]
  3979.         add     esi, [esi+sizeWithHeader]
  3980.         cmp     byte [esi], 0xB0
  3981.         stc
  3982.         jnz     .ret
  3983.         movzx   eax, byte [esi+attributeOffset]
  3984.         add     esi, eax
  3985.         mov     eax, [ebp+NTFS.cur_offs]
  3986.         xor     edx, edx
  3987.         div     [ebp+NTFS.cur_size]
  3988.         mov     edx, eax
  3989.         shr     eax, 3
  3990.         and     edx, 7
  3991.         btr     [esi+eax], edx
  3992.         mov     esi, [ebp+NTFS.secondIndexBuffer]
  3993.         mov     byte [esi], 0
  3994.         xor     esi, esi
  3995.         ret
  3996.  
  3997. ;----------------------------------------------------------------
  3998. ntfs_SetFileEnd:
  3999.         cmp     byte [esi], 0
  4000.         jnz     @f
  4001.         xor     ebx, ebx
  4002.         movi    eax, ERROR_ACCESS_DENIED
  4003.         ret
  4004. @@:
  4005.         call    ntfs_lock
  4006.         call    ntfs_find_lfn
  4007.         jc      ntfsNotFound
  4008.         cmp     [ebp+NTFS.cur_iRecord], 16
  4009.         jc      ntfsDenied
  4010.         test    dword [eax+fileFlags], 10000001h
  4011.         jnz     ntfsDenied
  4012.         cmp     [ebp+NTFS.fragmentCount], 1
  4013.         jnz     ntfsUnsupported     ; record fragmented
  4014. ; edit directory node
  4015.         mov     edi, [ebp+NTFS.cur_index_buf]
  4016.         cmp     dword [edi], 'INDX'
  4017.         jz      @f
  4018.         mov     esi, [ebp+NTFS.frs_buffer]
  4019.         mov     ecx, [esi+recordRealSize]
  4020.         shr     ecx, 2
  4021.         rep movsd
  4022.         mov     esi, [ebp+NTFS.attr_offs]
  4023.         mov     cl, [esi+attributeOffset]
  4024.         sub     esi, [ebp+NTFS.frs_buffer]
  4025.         add     eax, ecx
  4026.         add     eax, esi
  4027. @@:
  4028.         mov     edi, eax
  4029.         mov     eax, [ebx+4]
  4030.         mov     edx, [ebx+8]
  4031.         mov     [edi+fileRealSize], eax
  4032.         mov     [edi+fileRealSize+4], edx
  4033.         push    edx eax ebx
  4034.         call    ntfsGetTime
  4035.         mov     [edi+fileModified], eax
  4036.         mov     [edi+fileModified+4], edx
  4037.         mov     [edi+recordModified], eax
  4038.         mov     [edi+recordModified+4], edx
  4039.         mov     [edi+fileAccessed], eax
  4040.         mov     [edi+fileAccessed+4], edx
  4041.         pop     ebx ecx edx
  4042.         mov     eax, [ebp+NTFS.LastRead]
  4043.         mov     [ebp+NTFS.nodeLastRead], eax
  4044.         mov     [ebp+NTFS.cur_attr], 0x80
  4045.         mov     [ebp+NTFS.cur_offs], 0
  4046.         mov     [ebp+NTFS.cur_size], 0
  4047.         call    ntfs_read_attr
  4048.         jc      ntfsFail
  4049.         mov     esi, edi
  4050.         mov     edi, [ebp+NTFS.frs_buffer]
  4051.         cmp     word [edi+baseRecordReuse], 0
  4052.         jnz     ntfsUnsupported     ; auxiliary record
  4053.         mov     al, [edi+attributeOffset]
  4054.         add     edi, eax
  4055.         mov     al, [edi+attributeOffset]
  4056.         add     edi, eax
  4057.         mov     eax, ecx
  4058.         mov     ecx, 6
  4059.         add     esi, fileModified
  4060.         add     edi, 8
  4061.         rep movsd
  4062.         mov     ecx, [ebp+NTFS.attr_offs]
  4063.         cmp     word [ecx+attributeFlags], 0
  4064.         jnz     ntfsUnsupported
  4065.         cmp     byte [ecx+nonResidentFlag], 0
  4066.         jz      .resizeAttribute
  4067.         cmp     [ecx+attributeRealSize+4], edx
  4068.         jnz     .resizeAttribute
  4069.         cmp     [ecx+attributeRealSize], eax
  4070.         jnc     .resizeAttribute
  4071.         mov     eax, [ecx+attributeRealSize]
  4072.         mov     ecx, [ebp+NTFS.sectors_per_cluster]
  4073.         mov     [ebp+NTFS.cur_size], ecx
  4074.         shl     ecx, 9
  4075.         div     ecx
  4076.         test    edx, edx
  4077.         jz      .aligned
  4078.         push    edx
  4079.         push    ecx
  4080.         mul     [ebp+NTFS.sectors_per_cluster]
  4081.         mov     [ebp+NTFS.cur_offs], eax
  4082.         stdcall kernel_alloc, ecx
  4083.         pop     ecx
  4084.         pop     edi
  4085.         mov     esi, eax
  4086.         sub     ecx, edi
  4087.         add     edi, eax
  4088.         mov     [ebp+NTFS.cur_buf], eax
  4089.         call    ntfs_read_attr.continue
  4090.         jc      @f
  4091.         xor     eax, eax
  4092.         rep stosb
  4093.         push    ebx
  4094.         mov     eax, [ebp+NTFS.LastRead]
  4095.         mov     ebx, esi
  4096.         mov     ecx, [ebp+NTFS.sectors_per_cluster]
  4097.         xor     edx, edx
  4098.         call    fs_write64_app
  4099.         pop     ebx
  4100. @@:
  4101.         stdcall kernel_free, esi
  4102. .aligned:
  4103.         mov     eax, [ebx+4]
  4104.         mov     edx, [ebx+8]
  4105. .resizeAttribute:
  4106.         call    resizeAttribute
  4107.         jc      ntfsError
  4108.         mov     ebx, [ebp+NTFS.frs_buffer]
  4109.         mov     edx, [ebp+NTFS.mftLastRead]
  4110.         call    writeRecord     ; file
  4111.         mov     ebx, [ebp+NTFS.cur_index_buf]
  4112.         mov     edx, [ebp+NTFS.nodeLastRead]
  4113.         call    writeRecord     ; directory
  4114.         call    ntfsSpaceClean
  4115.         jmp     ntfsDone
  4116.  
  4117. ntfsGetTime:
  4118.         call    fsGetTime
  4119.         jmp     @f
  4120.  
  4121. ntfsCalculateTime:
  4122. ; in: esi -> data block
  4123. ; out: edx:eax = seconds since 01.01.1601 x10000000
  4124.         call    fsCalculateTime
  4125. @@:
  4126.         mov     edx, 10000000
  4127.         mul     edx
  4128.         add     eax, 3365781504
  4129.         adc     edx, 29389701
  4130.         ret
  4131.  
  4132. ;----------------------------------------------------------------
  4133. ntfs_SetFileInfo:
  4134.         cmp     byte [esi], 0
  4135.         jnz     @f
  4136.         movi    eax, ERROR_UNSUPPORTED_FS
  4137.         ret
  4138. @@:
  4139.         call    ntfs_lock
  4140.         call    ntfs_find_lfn
  4141.         jnc     @f
  4142.         test    eax, eax
  4143.         jz      ntfsFail
  4144.         jmp     ntfsNotFound
  4145.  
  4146. @@:
  4147.         cmp     [ebp+NTFS.fragmentCount], 1
  4148.         jnz     ntfsUnsupported     ; record fragmented
  4149.         mov     esi, [ebp+NTFS.cur_index_buf]
  4150.         cmp     dword [esi], 'INDX'
  4151.         jz      @f
  4152.         sub     eax, esi
  4153.         mov     esi, [ebp+NTFS.indexRoot]
  4154.         movzx   edx, byte [esi+attributeOffset]
  4155.         add     eax, esi
  4156.         add     eax, edx
  4157. @@:
  4158.         mov     esi, [ebx+16]
  4159.         mov     edi, eax
  4160.         mov     eax, [esi]
  4161.         and     eax, 27h
  4162.         and     byte [edi+fileFlags], -28h
  4163.         or      [edi+fileFlags], al
  4164.         add     esi, 8
  4165.         call    ntfsCalculateTime
  4166.         mov     [edi+fileCreated], eax
  4167.         mov     [edi+fileCreated+4], edx
  4168.         add     esi, 8
  4169.         call    ntfsCalculateTime
  4170.         mov     [edi+fileAccessed], eax
  4171.         mov     [edi+fileAccessed+4], edx
  4172.         add     esi, 8
  4173.         call    ntfsCalculateTime
  4174.         mov     [edi+fileModified], eax
  4175.         mov     [edi+fileModified+4], edx
  4176.         mov     ebx, [ebp+NTFS.cur_index_buf]
  4177.         cmp     dword [ebx], 'INDX'
  4178.         jz      @f
  4179.         mov     ebx, [ebp+NTFS.frs_buffer]
  4180. @@:
  4181.         mov     edx, [ebp+NTFS.LastRead]
  4182.         call    writeRecord
  4183.         jmp     ntfsDone
  4184.  
  4185. ntfsUnsupported:
  4186.         push    ERROR_UNSUPPORTED_FS
  4187.         jmp     ntfsOut
  4188. ntfsDevice:
  4189.         push    ERROR_DEVICE
  4190.         jmp     ntfsOut
  4191. ntfsNotFound:
  4192.         push    ERROR_FILE_NOT_FOUND
  4193.         jmp     ntfsOut
  4194. ntfsDenied:
  4195.         push    ERROR_ACCESS_DENIED
  4196.         jmp     ntfsOut
  4197. ntfsFail:
  4198.         push    ERROR_FS_FAIL
  4199.         jmp     ntfsOut
  4200. ntfsDiskFull:
  4201.         push    ERROR_DISK_FULL
  4202.         jmp     ntfsOut
  4203. ntfsErrorPop5:
  4204.         pop     ebx
  4205.         pop     ebx
  4206. ntfsErrorPop3:
  4207.         pop     ebx
  4208. ntfsErrorPop2:
  4209.         pop     ebx
  4210. ntfsErrorPop:
  4211.         pop     ebx
  4212. ntfsError:
  4213.         push    eax
  4214. ntfsOut:
  4215.         call    ntfs_unlock
  4216.         xor     ebx, ebx
  4217.         pop     eax
  4218.         ret
  4219.