Subversion Repositories Kolibri OS

Rev

Rev 6428 | Rev 6468 | 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: 6462 $
  9.  
  10. ; NTFS external functions
  11. ;   in:
  12. ; ebx -> parameter structure of sysfunc 70
  13. ; ebp -> NTFS structure
  14. ; [esi]+[[esp+4]] = name
  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]+[esp+4] = name
  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     4
  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.         inc     esi
  1341.         cmp     byte [esi-1], 0
  1342.         jnz     @f
  1343.         cmp     dword [esp+8], 0
  1344.         jz      .ret2
  1345.         mov     esi, [esp+8]
  1346.         mov     dword [esp+8], 0
  1347. @@:
  1348.         pop     eax
  1349.         jmp     .doit2
  1350.  
  1351. ;----------------------------------------------------------------
  1352. ntfs_ReadFile:
  1353.         cmp     byte [esi], 0
  1354.         jnz     @f
  1355.         or      ebx, -1
  1356.         movi    eax, ERROR_ACCESS_DENIED
  1357.         ret
  1358.  
  1359. @@:
  1360.         call    ntfs_lock
  1361.         stdcall ntfs_find_lfn, [esp+4]
  1362.         jnc     .found
  1363.         call    ntfs_unlock
  1364.         or      ebx, -1
  1365.         movi    eax, ERROR_FILE_NOT_FOUND
  1366.         ret
  1367.  
  1368. .found:
  1369.         mov     [ebp+NTFS.cur_attr], 0x80   ; $DATA
  1370.         and     [ebp+NTFS.cur_offs], 0
  1371.         and     [ebp+NTFS.cur_size], 0
  1372.         call    ntfs_read_attr
  1373.         jnc     @f
  1374.         call    ntfs_unlock
  1375.         or      ebx, -1
  1376.         movi    eax, ERROR_ACCESS_DENIED
  1377.         ret
  1378.  
  1379. @@:
  1380.         pushad
  1381.         and     dword [esp+10h], 0
  1382.         xor     eax, eax
  1383.         cmp     dword [ebx+8], 0x200
  1384.         jb      @f
  1385. .eof0:
  1386.         popad
  1387.         xor     ebx, ebx
  1388. .eof:
  1389.         call    ntfs_unlock
  1390.         movi    eax, ERROR_END_OF_FILE
  1391.         ret
  1392.  
  1393. @@:
  1394.         mov     ecx, [ebx+12]
  1395.         mov     edx, [ebx+16]
  1396.         mov     eax, [ebx+4]
  1397.         test    eax, 0x1FF
  1398.         jz      .alignedstart
  1399.         push    edx
  1400.         mov     edx, [ebx+8]
  1401.         shrd    eax, edx, 9
  1402.         pop     edx
  1403.         mov     [ebp+NTFS.cur_offs], eax
  1404.         mov     [ebp+NTFS.cur_size], 1
  1405.         lea     eax, [ebp+NTFS.bitmap_buf]
  1406.         mov     [ebp+NTFS.cur_buf], eax
  1407.         call    ntfs_read_attr.continue
  1408.         mov     eax, [ebx+4]
  1409.         and     eax, 0x1FF
  1410.         lea     esi, [ebp+NTFS.bitmap_buf+eax]
  1411.         sub     eax, [ebp+NTFS.cur_read]
  1412.         jae     .eof0
  1413.         neg     eax
  1414.         push    ecx
  1415.         cmp     ecx, eax
  1416.         jb      @f
  1417.         mov     ecx, eax
  1418. @@:
  1419.         mov     [esp+10h+4], ecx
  1420.         mov     edi, edx
  1421.         rep movsb
  1422.         mov     edx, edi
  1423.         pop     ecx
  1424.         sub     ecx, [esp+10h]
  1425.         jnz     @f
  1426. .retok:
  1427.         popad
  1428.         call    ntfs_unlock
  1429.         xor     eax, eax
  1430.         ret
  1431.  
  1432. @@:
  1433.         cmp     [ebp+NTFS.cur_read], 0x200
  1434.         jz      .alignedstart
  1435. .eof_ebx:
  1436.         popad
  1437.         jmp     .eof
  1438.  
  1439. .alignedstart:
  1440.         mov     eax, [ebx+4]
  1441.         push    edx
  1442.         mov     edx, [ebx+8]
  1443.         add     eax, 511
  1444.         adc     edx, 0
  1445.         shrd    eax, edx, 9
  1446.         pop     edx
  1447.         mov     [ebp+NTFS.cur_offs], eax
  1448.         mov     [ebp+NTFS.cur_buf], edx
  1449.         mov     eax, ecx
  1450.         shr     eax, 9
  1451.         mov     [ebp+NTFS.cur_size], eax
  1452.         add     eax, [ebp+NTFS.cur_offs]
  1453.         push    eax
  1454.         call    ntfs_read_attr.continue
  1455.         pop     [ebp+NTFS.cur_offs]
  1456.         mov     eax, [ebp+NTFS.cur_read]
  1457.         add     [esp+10h], eax
  1458.         mov     eax, ecx
  1459.         and     eax, not 0x1FF
  1460.         cmp     [ebp+NTFS.cur_read], eax
  1461.         jnz     .eof_ebx
  1462.         and     ecx, 0x1FF
  1463.         jz      .retok
  1464.         add     edx, [ebp+NTFS.cur_read]
  1465.         mov     [ebp+NTFS.cur_size], 1
  1466.         lea     eax, [ebp+NTFS.bitmap_buf]
  1467.         mov     [ebp+NTFS.cur_buf], eax
  1468.         call    ntfs_read_attr.continue
  1469.         cmp     [ebp+NTFS.cur_read], ecx
  1470.         jb      @f
  1471.         mov     [ebp+NTFS.cur_read], ecx
  1472. @@:
  1473.         xchg    ecx, [ebp+NTFS.cur_read]
  1474.         push    ecx
  1475.         mov     edi, edx
  1476.         lea     esi, [ebp+NTFS.bitmap_buf]
  1477.         add     [esp+10h+4], ecx
  1478.         rep movsb
  1479.         pop     ecx
  1480.         xor     eax, eax
  1481.         cmp     ecx, [ebp+NTFS.cur_read]
  1482.         jz      @f
  1483.         mov     al, ERROR_END_OF_FILE
  1484. @@:
  1485.         mov     [esp+1Ch], eax
  1486.         call    ntfs_unlock
  1487.         popad
  1488.         ret
  1489.  
  1490. ;----------------------------------------------------------------
  1491. ntfs_ReadFolder:
  1492.         call    ntfs_lock
  1493.         mov     [ebp+NTFS.cur_iRecord], 5   ; root directory
  1494.         cmp     byte [esi], 0
  1495.         jz      @f
  1496.         stdcall ntfs_find_lfn, [esp+4]
  1497.         jc      ntfsNotFound
  1498. @@:
  1499.         mov     [ebp+NTFS.cur_attr], 0x10   ; $STANDARD_INFORMATION
  1500.         and     [ebp+NTFS.cur_offs], 0
  1501.         mov     [ebp+NTFS.cur_size], 1
  1502.         lea     eax, [ebp+NTFS.bitmap_buf]
  1503.         mov     [ebp+NTFS.cur_buf], eax
  1504.         call    ntfs_read_attr
  1505.         jc      ntfsFail
  1506.         mov     [ebp+NTFS.cur_attr], 0x90   ; $INDEX_ROOT
  1507. .doit:
  1508.         mov     eax, [ebp+NTFS.cur_index_size]
  1509.         mov     [ebp+NTFS.cur_size], eax
  1510.         mov     eax, [ebp+NTFS.cur_index_buf]
  1511.         mov     [ebp+NTFS.cur_buf], eax
  1512.         call    ntfs_read_attr.newAttribute
  1513.         jc      ntfsFail
  1514.         cmp     [ebp+NTFS.cur_read], 0x20
  1515.         jc      ntfsFail
  1516.         mov     esi, [ebp+NTFS.cur_index_buf]
  1517.         mov     eax, [esi+indexRecordSize]
  1518.         shr     eax, 9
  1519.         cmp     [ebp+NTFS.cur_index_size], eax
  1520.         jc      .realloc
  1521.         mov     [ebp+NTFS.cur_subnode_size], eax
  1522.         add     esi, rootNode
  1523.         mov     eax, [esi+nodeRealSize]
  1524.         add     eax, rootNode
  1525.         cmp     [ebp+NTFS.cur_read], eax
  1526.         jc      ntfsFail
  1527.         mov     edi, [ebx+16]
  1528.         mov     ecx, [ebx+12]
  1529.         pushd   [ebx]
  1530.         pushd   [ebx+8]     ; read ANSI/UNICODE name
  1531.         push    edi
  1532.         mov     edx, esp
  1533.         mov     ebx, [ebx+4]
  1534. ; init header
  1535.         xor     eax, eax
  1536.         mov     [edi+8], eax
  1537.         mov     [edi+4], eax
  1538.         inc     eax
  1539.         mov     [edi], eax      ; version
  1540.         add     edi, 32
  1541. ; edi -> BDFE, esi -> current index data, ebx = first wanted block,
  1542. ; ecx = number of blocks to read
  1543. ; edx -> parameters block: dd <output>, dd <flags>
  1544.         cmp     [ebp+NTFS.cur_iRecord], 5
  1545.         jz      .skip_specials
  1546. ; dot and dotdot entries
  1547.         push    esi
  1548.         xor     esi, esi
  1549.         call    .add_special_entry
  1550.         inc     esi
  1551.         call    .add_special_entry
  1552.         pop     esi
  1553. .skip_specials:
  1554. ; at first, dump index root
  1555.         add     esi, [esi+indexOffset]
  1556. .dump_root:
  1557.         test    byte [esi+indexFlags], 2
  1558.         jnz     .dump_root_done
  1559.         call    .add_entry
  1560.         movzx   eax, word [esi+indexAllocatedSize]
  1561.         add     esi, eax
  1562.         jmp     .dump_root
  1563.  
  1564. .realloc:
  1565.         mov     edi, eax
  1566.         mov     eax, [esi+indexRecordSize]
  1567.         shl     eax, 1
  1568.         stdcall kernel_alloc, eax
  1569.         test    eax, eax
  1570.         jz      ntfsFail
  1571.         mov     edx, [ebp+NTFS.cur_index_buf]
  1572.         cmp     edx, [ebp+NTFS.secondIndexBuffer]
  1573.         jc      @f
  1574.         mov     edx, [ebp+NTFS.secondIndexBuffer]
  1575. @@:
  1576.         mov     [ebp+NTFS.cur_index_buf], eax
  1577.         add     eax, [esi+indexRecordSize]
  1578.         mov     [ebp+NTFS.secondIndexBuffer], eax
  1579.         mov     [ebp+NTFS.cur_index_size], edi
  1580.         stdcall kernel_free, edx
  1581.         jmp     .doit
  1582.  
  1583. .dump_root_done:
  1584. ; now dump all subnodes
  1585.         push    ecx edi
  1586.         lea     edi, [ebp+NTFS.bitmap_buf]
  1587.         mov     [ebp+NTFS.cur_buf], edi
  1588.         mov     ecx, 0x400/4
  1589.         xor     eax, eax
  1590.         rep stosd
  1591.         mov     [ebp+NTFS.cur_attr], 0xB0   ; $BITMAP
  1592.         and     [ebp+NTFS.cur_offs], 0
  1593.         mov     [ebp+NTFS.cur_size], 2
  1594.         call    ntfs_read_attr.newAttribute
  1595.         pop     edi ecx
  1596.         push    0       ; save offset in $BITMAP attribute
  1597.         and     [ebp+NTFS.cur_offs], 0
  1598. .dumploop:
  1599.         mov     [ebp+NTFS.cur_attr], 0xA0
  1600.         mov     eax, [ebp+NTFS.cur_subnode_size]
  1601.         mov     [ebp+NTFS.cur_size], eax
  1602.         mov     esi, [ebp+NTFS.cur_index_buf]
  1603.         mov     [ebp+NTFS.cur_buf], esi
  1604.         mov     eax, [ebp+NTFS.cur_offs]
  1605.         push    eax
  1606.         imul    eax, [ebp+NTFS.cur_subnode_size]
  1607.         mov     [ebp+NTFS.cur_offs], eax
  1608.         call    ntfs_read_attr.newAttribute
  1609.         pop     [ebp+NTFS.cur_offs]
  1610.         mov     eax, [ebp+NTFS.cur_subnode_size]
  1611.         shl     eax, 9
  1612.         cmp     [ebp+NTFS.cur_read], eax
  1613.         jnz     .done
  1614.         push    eax
  1615.         mov     eax, [ebp+NTFS.cur_offs]
  1616.         and     eax, 0x400*8-1
  1617.         bt      dword [ebp+NTFS.bitmap_buf], eax
  1618.         pop     eax
  1619.         jnc     .dump_subnode_done
  1620.         cmp     dword [esi], 'INDX'
  1621.         jnz     .dump_subnode_done
  1622.         push    ebx
  1623.         mov     ebx, esi
  1624.         call    ntfs_restore_usa
  1625.         pop     ebx
  1626.         jc      .dump_subnode_done
  1627.         add     esi, recordNode
  1628.         add     esi, [esi+indexOffset]
  1629. .dump_subnode:
  1630.         test    byte [esi+indexFlags], 2
  1631.         jnz     .dump_subnode_done
  1632.         call    .add_entry
  1633.         movzx   eax, word [esi+indexAllocatedSize]
  1634.         add     esi, eax
  1635.         jmp     .dump_subnode
  1636.  
  1637. .dump_subnode_done:
  1638.         inc     [ebp+NTFS.cur_offs]
  1639.         test    [ebp+NTFS.cur_offs], 0x400*8-1
  1640.         jnz     .dumploop
  1641.         mov     [ebp+NTFS.cur_attr], 0xB0
  1642.         push    ecx edi
  1643.         lea     edi, [ebp+NTFS.bitmap_buf]
  1644.         mov     [ebp+NTFS.cur_buf], edi
  1645.         mov     ecx, 0x400/4
  1646.         xor     eax, eax
  1647.         rep stosd
  1648.         pop     edi ecx
  1649.         pop     eax
  1650.         push    [ebp+NTFS.cur_offs]
  1651.         inc     eax
  1652.         mov     [ebp+NTFS.cur_offs], eax
  1653.         mov     [ebp+NTFS.cur_size], 2
  1654.         push    eax
  1655.         call    ntfs_read_attr.newAttribute
  1656.         pop     eax
  1657.         pop     [ebp+NTFS.cur_offs]
  1658.         push    eax
  1659.         jmp     .dumploop
  1660.  
  1661. .done:
  1662.         pop     eax
  1663.         pop     eax
  1664.         mov     ebx, [eax+4]
  1665.         pop     eax
  1666.         pop     eax
  1667.         test    eax, eax
  1668.         jz      .ret
  1669.         xor     eax, eax
  1670.         dec     ecx
  1671.         js      @f
  1672.         mov     al, ERROR_END_OF_FILE
  1673. @@:
  1674.         push    eax
  1675.         call    ntfs_unlock
  1676.         pop     eax
  1677.         ret
  1678.  
  1679. .add_special_entry:
  1680.         mov     eax, [edx]
  1681.         inc     dword [eax+8]   ; new file found
  1682.         dec     ebx
  1683.         jns     .ret
  1684.         dec     ecx
  1685.         js      .ret
  1686.         inc     dword [eax+4]   ; new file block copied
  1687.         mov     eax, [edx+4]
  1688.         mov     [edi+4], eax
  1689.         mov     eax, 0x10
  1690.         stosd
  1691.         scasd
  1692.         push    ebx ecx edx
  1693.         mov     eax, dword [ebp+NTFS.bitmap_buf]
  1694.         mov     edx, dword [ebp+NTFS.bitmap_buf+4]
  1695.         call    ntfs_datetime_to_bdfe
  1696.         mov     eax, dword [ebp+NTFS.bitmap_buf+0x18]
  1697.         mov     edx, dword [ebp+NTFS.bitmap_buf+0x1C]
  1698.         call    ntfs_datetime_to_bdfe
  1699.         mov     eax, dword [ebp+NTFS.bitmap_buf+8]
  1700.         mov     edx, dword [ebp+NTFS.bitmap_buf+0xC]
  1701.         call    ntfs_datetime_to_bdfe
  1702.         pop     edx ecx ebx
  1703.         xor     eax, eax
  1704.         stosd
  1705.         stosd
  1706.         mov     al, '.'
  1707.         push    edi ecx
  1708.         lea     ecx, [esi+1]
  1709.         test    byte [edi-0x24], 1
  1710.         jz      @f
  1711.         rep stosw
  1712.         pop     ecx
  1713.         xor     eax, eax
  1714.         stosw
  1715.         pop     edi
  1716.         add     edi, 520
  1717.         ret
  1718.  
  1719. @@:
  1720.         rep stosb
  1721.         pop     ecx
  1722.         xor     eax, eax
  1723.         stosb
  1724.         pop     edi
  1725.         add     edi, 264
  1726. .ret:
  1727.         ret
  1728.  
  1729. .add_entry:
  1730. ; do not return DOS 8.3 names
  1731.         cmp     byte [esi+namespace], 2
  1732.         jz      .ret
  1733. ; do not return system files
  1734. ; ... note that there will be no bad effects if system files also were reported ...
  1735.         cmp     dword [esi+fileRecordReference], 0x10
  1736.         jb      .ret
  1737.         mov     eax, [edx]
  1738.         inc     dword [eax+8]   ; new file found
  1739.         dec     ebx
  1740.         jns     .ret
  1741.         dec     ecx
  1742.         js      .ret
  1743.         inc     dword [eax+4]   ; new file block copied
  1744.         mov     eax, [edx+4]    ; flags
  1745.         call    ntfs_direntry_to_bdfe
  1746.         push    ecx esi edi
  1747.         movzx   ecx, byte [esi+fileNameLength]
  1748.         add     esi, fileName
  1749.         test    byte [edi-0x24], 1
  1750.         jz      .ansi
  1751.         shr     ecx, 1
  1752.         rep movsd
  1753.         adc     ecx, ecx
  1754.         rep movsw
  1755.         and     word [edi], 0
  1756.         pop     edi
  1757.         add     edi, 520
  1758.         pop     esi ecx
  1759.         ret
  1760.  
  1761. .ansi:
  1762.         jecxz   .skip
  1763. @@:
  1764.         lodsw
  1765.         call    uni2ansi_char
  1766.         stosb
  1767.         loop    @b
  1768. .skip:
  1769.         xor     al, al
  1770.         stosb
  1771.         pop     edi
  1772.         add     edi, 264
  1773.         pop     esi ecx
  1774.         ret
  1775.  
  1776. ntfs_direntry_to_bdfe:
  1777.         mov     [edi+4], eax    ; ANSI/UNICODE name
  1778.         mov     eax, [esi+fileFlags]
  1779.         test    eax, 0x10000000
  1780.         jz      @f
  1781.         and     eax, not 0x10000000
  1782.         or      al, 0x10
  1783. @@:
  1784.         stosd
  1785.         scasd
  1786.         push    ebx ecx edx
  1787.         mov     eax, [esi+fileCreated]
  1788.         mov     edx, [esi+fileCreated+4]
  1789.         call    ntfs_datetime_to_bdfe
  1790.         mov     eax, [esi+fileAccessed]
  1791.         mov     edx, [esi+fileAccessed+4]
  1792.         call    ntfs_datetime_to_bdfe
  1793.         mov     eax, [esi+fileModified]
  1794.         mov     edx, [esi+fileModified+4]
  1795.         call    ntfs_datetime_to_bdfe
  1796.         pop     edx ecx ebx
  1797.         mov     eax, [esi+fileRealSize]
  1798.         stosd
  1799.         mov     eax, [esi+fileRealSize+4]
  1800.         stosd
  1801.         ret
  1802.  
  1803. ntfs_datetime_to_bdfe:
  1804. ; in: edx:eax = seconds since 01.01.1601 x10000000
  1805. ; edi -> data block
  1806. ; out: edi = edi+8
  1807.         sub     eax, 3365781504
  1808.         sbb     edx, 29389701
  1809.         mov     ecx, 10000000
  1810.         cmp     edx, ecx
  1811.         jc      @f
  1812.         xor     edx, edx
  1813. @@:
  1814.         div     ecx
  1815.         jmp     fsTime2bdfe
  1816.  
  1817. ;----------------------------------------------------------------
  1818. ntfs_GetFileInfo:
  1819.         call    ntfs_lock
  1820.         mov     edi, [ebx+16]
  1821.         cmp     byte [esi], 0
  1822.         jz      .volume
  1823.         stdcall ntfs_find_lfn, [esp+4]
  1824.         jnc     .found
  1825.         test    eax, eax
  1826.         jz      ntfsFail
  1827.         jmp     ntfsNotFound
  1828.  
  1829. .found:
  1830.         mov     esi, eax
  1831.         xor     eax, eax
  1832.         call    ntfs_direntry_to_bdfe
  1833. .end:
  1834.         call    ntfs_unlock
  1835.         xor     eax, eax
  1836.         ret
  1837.  
  1838. .volume:
  1839.         mov     byte [edi], 8
  1840.         mov     eax, [ebx+8]
  1841.         mov     [edi+4], eax
  1842.         mov     eax, dword [ebp+NTFS.Length]
  1843.         mov     edx, dword [ebp+NTFS.Length+4]
  1844.         shld    edx, eax, 9
  1845.         shl     eax, 9
  1846.         mov     [edi+36], edx
  1847.         mov     [edi+32], eax
  1848.         add     edi, 40
  1849.         mov     [ebp+NTFS.cur_buf], edi
  1850.         mov     [ebp+NTFS.cur_iRecord], 3
  1851.         mov     [ebp+NTFS.cur_attr], 0x60
  1852.         mov     [ebp+NTFS.cur_offs], 0
  1853.         mov     [ebp+NTFS.cur_size], 1
  1854.         call    ntfs_read_attr
  1855.         jc      ntfsFail
  1856.         mov     ecx, [ebp+NTFS.cur_read]
  1857.         mov     [edi+ecx], ax
  1858.         cmp     [ebx+8], eax
  1859.         jnz     .end
  1860.         mov     esi, edi
  1861.         shr     ecx, 1
  1862.         jz      .end
  1863. @@:
  1864.         lodsw
  1865.         call    uni2ansi_char
  1866.         stosb
  1867.         dec     ecx
  1868.         jnz     @b
  1869.         mov     byte [edi], 0
  1870.         jmp     .end
  1871.  
  1872. ;----------------------------------------------------------------
  1873. ntfs_CreateFolder:
  1874.         mov     [ebp+NTFS.bFolder], 1
  1875.         jmp     @f
  1876.  
  1877. ntfs_CreateFile:
  1878.         mov     [ebp+NTFS.bFolder], 0
  1879. @@:
  1880.         cmp     byte [esi], 0
  1881.         jnz     @f
  1882.         xor     ebx, ebx
  1883.         movi    eax, ERROR_ACCESS_DENIED
  1884.         ret
  1885.  
  1886. @@: ; 1. Search file
  1887.         call    ntfs_lock
  1888.         stdcall ntfs_find_lfn, [esp+4]
  1889.         jc      .notFound
  1890. ; found, rewrite
  1891.         cmp     [ebp+NTFS.cur_iRecord], 16
  1892.         jc      ntfsDenied
  1893.         cmp     [ebp+NTFS.bFolder], 1
  1894.         jz      .folder
  1895.         test    byte [eax+fileFlags], 1
  1896.         jnz     ntfsDenied
  1897.         cmp     [ebp+NTFS.fragmentCount], 1
  1898.         jnz     ntfsUnsupported     ; record fragmented
  1899. ; edit directory node
  1900.         mov     edi, [ebp+NTFS.cur_index_buf]
  1901.         cmp     dword [edi], 'INDX'
  1902.         jz      @f
  1903.         mov     esi, [ebp+NTFS.frs_buffer]
  1904.         mov     ecx, [esi+recordRealSize]
  1905.         shr     ecx, 2
  1906.         rep movsd
  1907.         mov     esi, [ebp+NTFS.attr_offs]
  1908.         mov     cl, [esi+attributeOffset]
  1909.         sub     esi, [ebp+NTFS.frs_buffer]
  1910.         add     eax, ecx
  1911.         add     eax, esi
  1912. @@:
  1913.         mov     edi, eax
  1914.         mov     eax, [ebx+12]
  1915.         mov     [edi+fileRealSize], eax
  1916.         mov     dword [edi+fileRealSize+4], 0
  1917.         push    ebx eax
  1918.         call    ntfsGetTime
  1919.         mov     [edi+fileModified], eax
  1920.         mov     [edi+fileModified+4], edx
  1921.         mov     [edi+recordModified], eax
  1922.         mov     [edi+recordModified+4], edx
  1923.         mov     [edi+fileAccessed], eax
  1924.         mov     [edi+fileAccessed+4], edx
  1925.         pop     edx ebx
  1926.         mov     eax, [ebp+NTFS.LastRead]
  1927.         mov     [ebp+NTFS.nodeLastRead], eax
  1928.         mov     [ebp+NTFS.cur_attr], 0x80
  1929.         mov     [ebp+NTFS.cur_offs], 0
  1930.         mov     [ebp+NTFS.cur_size], 0
  1931.         call    ntfs_read_attr
  1932.         jc      ntfsFail
  1933.         mov     esi, edi
  1934.         mov     edi, [ebp+NTFS.frs_buffer]
  1935.         cmp     word [edi+baseRecordReuse], 0
  1936.         jnz     ntfsUnsupported     ; auxiliary record
  1937.         mov     al, [edi+attributeOffset]
  1938.         add     edi, eax
  1939.         mov     al, [edi+attributeOffset]
  1940.         add     edi, eax
  1941.         mov     ecx, 6
  1942.         add     esi, fileModified
  1943.         add     edi, 8
  1944.         rep movsd
  1945.         mov     eax, edx
  1946.         xor     edx, edx
  1947.         mov     ecx, [ebp+NTFS.attr_offs]
  1948.         cmp     word [ecx+attributeFlags], 0
  1949.         jnz     ntfsUnsupported
  1950.         push    ebx
  1951.         cmp     byte [ecx+nonResidentFlag], 0
  1952.         jz      @f
  1953.         cmp     [ecx+attributeRealSize+4], edx
  1954.         jnz     @f
  1955.         cmp     [ecx+attributeRealSize], eax
  1956.         jz      ntfs_WriteFile.writeNode
  1957. @@:
  1958.         jmp     ntfs_WriteFile.resizeAttribute
  1959.  
  1960. .folder:
  1961.         bt      dword [eax+fileFlags], 28
  1962.         jnc     ntfsDenied
  1963.         push    0
  1964.         jmp     ntfsOut
  1965.  
  1966. .notFound:  ; create
  1967.         test    eax, eax
  1968.         jz      ntfsFail
  1969.         cmp     [ebp+NTFS.fragmentCount], 1
  1970.         jnz     ntfsUnsupported     ; record fragmented
  1971. ; 2. Prepare directory record
  1972.         mov     ecx, esi
  1973. @@:         ; count characters
  1974.         inc     ecx
  1975.         cmp     byte [ecx], '/'
  1976.         jz      ntfsNotFound    ; path folder not found
  1977.         cmp     byte [ecx], 0
  1978.         jnz     @b
  1979.         sub     ecx, esi
  1980.         push    ecx     ; name length
  1981.         shl     ecx, 1
  1982.         add     ecx, fileName+7
  1983.         and     ecx, not 7
  1984.         mov     edi, [ebp+NTFS.cur_index_buf]
  1985.         mov     edx, [ebx+12]
  1986.         mov     [ebp+NTFS.fileRealSize], edx
  1987.         mov     edx, [ebx+16]
  1988.         mov     [ebp+NTFS.fileDataBuffer], edx
  1989.         push    esi
  1990.         push    ecx     ; index length
  1991.         mov     edx, ecx
  1992.         cmp     dword [edi], 'INDX'
  1993.         jz      .indexRecord
  1994.         mov     esi, [ebp+NTFS.frs_buffer]  ; indexRoot
  1995.         mov     ecx, [esi+recordRealSize]
  1996.         add     edx, ecx
  1997.         cmp     [esi+recordAllocatedSize], edx
  1998.         jc      .growTree
  1999.         mov     [esi+recordRealSize], edx
  2000.         shr     ecx, 2
  2001.         rep movsd
  2002.         mov     edi, [ebp+NTFS.indexRoot]
  2003.         sub     edi, [ebp+NTFS.frs_buffer]
  2004.         add     edi, [ebp+NTFS.cur_index_buf]
  2005.         mov     esi, [esp]
  2006.         add     [edi+sizeWithHeader], esi
  2007.         add     [edi+sizeWithoutHeader], esi
  2008.         mov     cl, [edi+attributeOffset]
  2009.         add     edi, ecx
  2010.         add     [edi+rootNode+nodeRealSize], esi
  2011.         add     [edi+rootNode+nodeAllocatedSize], esi
  2012.         sub     eax, [ebp+NTFS.cur_index_buf]
  2013.         add     eax, edi
  2014.         mov     edi, [ebp+NTFS.cur_index_buf]
  2015.         jmp     .common
  2016.  
  2017. .growTree:  ; create indexRecord
  2018.         mov     edi, [ebp+NTFS.cur_index_buf]
  2019.         mov     ecx, 10
  2020.         xor     eax, eax
  2021.         rep stosd
  2022.         mov     esi, [ebp+NTFS.indexRoot]
  2023.         mov     al, [esi+attributeOffset]
  2024.         add     esi, eax
  2025.         rdtsc
  2026.         stosw
  2027.         mov     eax, [esi+indexRecordSize]
  2028.         cmp     eax, [ebp+NTFS.frs_size]
  2029.         jc      .errorPop3
  2030.         shr     eax, 9
  2031.         inc     eax
  2032.         mov     edi, [ebp+NTFS.cur_index_buf]
  2033.         mov     dword[edi], 'INDX'
  2034.         mov     byte [edi+updateSequenceOffset], 28h
  2035.         mov     [edi+updateSequenceSize], al
  2036.         add     edi, recordNode
  2037.         shl     eax, 1
  2038.         add     eax, 28h-recordNode+7
  2039.         and     eax, not 7
  2040.         mov     [edi+indexOffset], eax
  2041.         mov     ecx, [esi+indexRecordSize]
  2042.         sub     ecx, recordNode
  2043.         mov     [edi+nodeAllocatedSize], ecx
  2044.         add     esi, rootNode
  2045.         push    esi
  2046.         mov     ecx, [esi+nodeRealSize]
  2047.         sub     ecx, [esi+indexOffset]
  2048.         add     eax, ecx
  2049.         mov     [edi+nodeRealSize], eax
  2050.         mov     eax, [esi+nonLeafFlag]
  2051.         mov     [edi+nonLeafFlag], eax
  2052.         shr     ecx, 2
  2053.         add     esi, [esi+indexOffset]
  2054.         add     edi, [edi+indexOffset]
  2055.         rep movsd       ; copy root indexes
  2056. ; clear root node
  2057.         mov     cl, 10
  2058.         mov     edi, [esp]
  2059.         xor     eax, eax
  2060.         rep stosd
  2061.         pop     edi
  2062.         mov     byte [edi+indexOffset], 16
  2063.         mov     byte [edi+nodeRealSize], 28h
  2064.         mov     byte [edi+nodeAllocatedSize], 28h
  2065.         mov     byte [edi+nonLeafFlag], 1
  2066.         mov     byte [edi+16+indexAllocatedSize], 18h
  2067.         mov     byte [edi+16+indexFlags], 3
  2068.         mov     esi, [ebp+NTFS.indexRoot]
  2069.         add     edi, 28h
  2070.         mov     eax, edi
  2071.         sub     eax, esi
  2072.         mov     word [esi+sizeWithoutHeader], 38h
  2073.         xchg    [esi+sizeWithHeader], eax
  2074.         add     esi, eax
  2075.         mov     [ebp+NTFS.attr_offs], edi
  2076.         cmp     byte [esi], 0xA0
  2077.         jnz     @f
  2078.         cmp     dword [esi+attributeAllocatedSize], 0
  2079.         jz      @f
  2080.         mov     eax, [ebp+NTFS.frs_buffer]
  2081.         mov     ecx, eax
  2082.         add     ecx, [eax+recordRealSize]
  2083.         sub     ecx, esi
  2084.         shr     ecx, 2
  2085.         rep movsd
  2086.         sub     edi, eax
  2087.         mov     [eax+recordRealSize], edi
  2088.         call    .ntfsNodeAlloc
  2089.         jc      ntfsErrorPop3
  2090.         mov     eax, [ebp+NTFS.newRecord]
  2091.         mov     edi, [ebp+NTFS.cur_index_buf]
  2092.         mov     [edi+recordVCN], eax
  2093.         mov     edi, [ebp+NTFS.attr_offs]
  2094.         mov     [edi-8], eax
  2095.         jmp     .refresh
  2096.  
  2097. @@:
  2098.         mov     cl, 32
  2099.         xor     eax, eax
  2100.         rep stosd
  2101.         mov     eax, [ebp+NTFS.cur_subnode_size]
  2102.         cmp     eax, [ebp+NTFS.cur_size]
  2103.         jnz     @f
  2104.         mov     al, 1
  2105. @@:
  2106.         mov     [ebp+NTFS.fileDataSize], eax
  2107.         mov     edi, [ebp+NTFS.BitmapStart]
  2108.         call    ntfsSpaceAlloc
  2109.         movi    eax, ERROR_DISK_FULL
  2110.         jc      ntfsErrorPop3
  2111. ; create $IndexAllocation
  2112.         mov     edi, [ebp+NTFS.attr_offs]
  2113.         mov     byte [edi+attributeType], 0xA0
  2114.         mov     byte [edi+nonResidentFlag], 1
  2115.         mov     byte [edi+nameLength], 4
  2116.         mov     byte [edi+nameOffset], 40h
  2117.         mov     byte [edi+dataRunsOffset], 48h
  2118.         mov     byte [edi+sizeWithHeader], 50h
  2119.         mov     eax, [ebp+NTFS.fileDataSize]
  2120.         dec     eax
  2121.         mov     [edi+lastVCN], eax
  2122.         inc     eax
  2123.         mul     [ebp+NTFS.sectors_per_cluster]
  2124.         shl     eax, 9
  2125.         mov     [edi+attributeAllocatedSize], eax
  2126.         mov     [edi+attributeRealSize], eax
  2127.         mov     [edi+initialDataSize], eax
  2128.         mov     dword[edi+40h], 490024h     ; unicode $I30
  2129.         mov     dword[edi+40h+4], 300033h
  2130.         push    edi
  2131.         mov     esi, edi
  2132.         add     edi, 48h
  2133.         call    createMcbEntry
  2134.         mov     esi, [ebp+NTFS.frs_buffer]
  2135.         pop     edi
  2136.         mov     al, [esi+newAttributeID]
  2137.         mov     [edi+attributeID], al
  2138.         add     edi, 50h
  2139.         inc     eax
  2140. ; create $Bitmap
  2141.         mov     [edi+attributeID], al
  2142.         inc     eax
  2143.         mov     [esi+newAttributeID], al
  2144.         mov     byte [edi+attributeType], 0xB0
  2145.         mov     byte [edi+nameLength], 4
  2146.         mov     byte [edi+nameOffset], 18h
  2147.         mov     byte [edi+attributeOffset], 20h
  2148.         mov     byte [edi+sizeWithoutHeader], 8
  2149.         mov     byte [edi+sizeWithHeader], 28h
  2150.         mov     dword[edi+18h], 490024h     ; unicode $I30
  2151.         mov     dword[edi+18h+4], 300033h
  2152.         mov     byte [edi+20h], 1
  2153.         mov     dword[edi+28h], -1
  2154.         add     edi, 30h
  2155.         sub     edi, esi
  2156.         mov     [esi+recordRealSize], edi
  2157.         mov     eax, [ebp+NTFS.fileDataStart]
  2158.         mul     [ebp+NTFS.sectors_per_cluster]
  2159.         mov     edx, eax
  2160.         jmp     @f
  2161.  
  2162. .refresh:
  2163.         mov     [ebp+NTFS.cur_size], 0
  2164.         call    ntfs_read_attr.continue
  2165.         movi    eax, ERROR_FS_FAIL
  2166.         jc      ntfsErrorPop3
  2167.         mov     edx, [ebp+NTFS.LastRead]
  2168. @@:
  2169.         mov     ebx, [ebp+NTFS.cur_index_buf]
  2170.         call    writeRecord
  2171.         mov     ebx, [ebp+NTFS.frs_buffer]
  2172.         mov     edx, [ebp+NTFS.rootLastRead]
  2173.         call    writeRecord
  2174.         mov     esi, [esp+4]
  2175.         stdcall ntfs_find_lfn.doit2, 0
  2176.         test    eax, eax
  2177.         jz      .errorPop3
  2178.         mov     edi, [ebp+NTFS.cur_index_buf]
  2179.         mov     edx, [esp]
  2180. .indexRecord:
  2181.         add     edi, recordNode
  2182.         add     edx, [edi+nodeRealSize]
  2183.         cmp     [edi+nodeAllocatedSize], edx
  2184.         jc      .arborizeTree
  2185.         mov     [edi+nodeRealSize], edx
  2186.         jmp     .common
  2187.  
  2188. .errorPop3:
  2189.         add     esp, 12
  2190.         jmp     ntfsUnsupported
  2191.  
  2192. .ntfsNodeAlloc:
  2193. ; in: [ebp+NTFS.attr_offs] -> $IndexAllocation
  2194. ;   out:
  2195. ; [ebp+NTFS.newRecord] = node VCN
  2196. ; [ebp+NTFS.cur_offs]
  2197. ; CF=1 -> eax = error code
  2198.         mov     esi, [ebp+NTFS.attr_offs]
  2199.         add     esi, [esi+sizeWithHeader]
  2200.         cmp     byte [esi], 0xB0
  2201.         jnz     .ret
  2202.         movzx   ecx, word [esi+sizeWithoutHeader]
  2203.         shr     ecx, 2
  2204.         movzx   edi, byte [esi+attributeOffset]
  2205.         add     edi, esi
  2206.         mov     edx, edi
  2207.         or      eax, -1
  2208.         repz scasd
  2209.         jnz     @f
  2210.         cmp     [edi], eax
  2211.         jnz     .ret
  2212. ; extend folder $Bitmap
  2213.         add     word [esi+sizeWithHeader], 8
  2214.         add     word [esi+sizeWithoutHeader], 8
  2215.         mov     esi, [ebp+NTFS.frs_buffer]
  2216.         mov     eax, [esi+recordRealSize]
  2217.         add     eax, 8
  2218.         cmp     [esi+recordAllocatedSize], eax
  2219.         jc      .ret
  2220.         mov     [esi+recordRealSize], eax
  2221.         xor     eax, eax
  2222.         stosd
  2223.         mov     [edi], eax
  2224.         mov     [edi+8], eax
  2225.         dec     eax
  2226.         mov     [edi+4], eax
  2227. @@:
  2228.         sub     edi, 4
  2229.         mov     eax, [edi]
  2230.         not     eax
  2231.         bsf     eax, eax
  2232.         bts     [edi], eax
  2233.         sub     edi, edx
  2234.         shl     edi, 3
  2235.         add     eax, edi
  2236.         mul     [ebp+NTFS.cur_subnode_size]
  2237.         mov     [ebp+NTFS.newRecord], eax
  2238.         mov     ecx, [ebp+NTFS.cur_size]
  2239.         cmp     ecx, [ebp+NTFS.cur_subnode_size]
  2240.         jz      @f
  2241.         mul     [ebp+NTFS.sectors_per_cluster]
  2242. @@:
  2243.         mov     [ebp+NTFS.cur_offs], eax
  2244.         add     eax, ecx
  2245.         shl     eax, 9
  2246.         mov     esi, [ebp+NTFS.attr_offs]
  2247.         cmp     [esi+attributeAllocatedSize], eax
  2248.         jnc     @f
  2249.         xor     edx, edx
  2250.         jmp     resizeAttribute
  2251.  
  2252. .ret:
  2253.         movi    eax, ERROR_UNSUPPORTED_FS
  2254.         stc
  2255. @@:
  2256.         ret
  2257.  
  2258. .arborizeTree:      ; find median index
  2259.         mov     ecx, [edi+nodeRealSize]
  2260.         sub     ecx, [edi+indexOffset]
  2261.         shr     ecx, 1
  2262.         add     edi, [edi+indexOffset]
  2263.         xor     eax, eax
  2264. @@:
  2265.         add     edi, eax
  2266.         mov     ax, [edi+indexAllocatedSize]
  2267.         sub     ecx, eax
  2268.         jnc     @b
  2269.         add     eax, 8
  2270.         mov     esi, [ebp+NTFS.secondIndexBuffer]
  2271.         cmp     dword [esi], 'INDX'
  2272.         jz      @f
  2273. ; move index to the root node
  2274.         mov     esi, [ebp+NTFS.frs_buffer]
  2275.         mov     ecx, eax
  2276.         add     ecx, 8
  2277.         add     ecx, [esi+recordRealSize]
  2278.         cmp     [esi+recordAllocatedSize], ecx
  2279.         jc      .growTree
  2280.         push    edi eax
  2281.         call    .ntfsNodeAlloc
  2282.         jc      ntfsErrorPop5
  2283.         pop     eax
  2284.         mov     edi, [ebp+NTFS.indexRoot]
  2285.         add     [ebp+NTFS.attr_offs], eax
  2286.         add     [edi+sizeWithHeader], eax
  2287.         add     [edi+sizeWithoutHeader], eax
  2288.         movzx   ecx, byte [edi+attributeOffset]
  2289.         add     ecx, edi
  2290.         add     [ecx+rootNode+nodeRealSize], eax
  2291.         add     [ecx+rootNode+nodeAllocatedSize], eax
  2292.         add     ecx, [ebp+NTFS.indexPointer]
  2293.         sub     ecx, [ebp+NTFS.secondIndexBuffer]
  2294.         mov     esi, [ebp+NTFS.frs_buffer]
  2295.         add     [esi+recordRealSize], eax
  2296.         add     esi, [esi+recordRealSize]
  2297.         mov     edi, esi
  2298.         sub     esi, eax
  2299.         neg     ecx
  2300.         add     ecx, esi
  2301.         shr     ecx, 2
  2302.         sub     esi, 4
  2303.         sub     edi, 4
  2304.         std
  2305.         rep movsd   ; make space
  2306.         mov     [edi], ecx
  2307.         mov     edi, esi
  2308.         add     edi, 4
  2309.         mov     esi, [esp]
  2310.         add     word [esi+indexAllocatedSize], 8
  2311.         mov     byte [esi+indexFlags], 1
  2312.         mov     ecx, eax
  2313.         sub     ecx, 8
  2314.         shr     ecx, 2
  2315.         cld
  2316.         rep movsd   ; insert index
  2317.         mov     eax, [ebp+NTFS.newRecord]
  2318.         stosd
  2319.         jmp     .splitNode
  2320.  
  2321. .growBranch:    ; move node and replace it with empty one
  2322.         mov     esi, [ebp+NTFS.cur_index_buf]
  2323.         mov     edi, [ebp+NTFS.secondIndexBuffer]
  2324.         mov     eax, [esi+recordVCN]
  2325.         mov     [edi+recordVCN], eax
  2326.         add     edi, recordNode
  2327.         mov     eax, [edi+indexOffset]
  2328.         add     eax, 18h
  2329.         mov     [edi+nodeRealSize], eax
  2330.         add     edi, [edi+indexOffset]
  2331.         mov     ecx, 6
  2332.         xor     eax, eax
  2333.         mov     [ebp+NTFS.indexPointer], edi
  2334.         push    edi
  2335.         rep stosd
  2336.         pop     edi
  2337.         mov     eax, [ebp+NTFS.newRecord]
  2338.         mov     byte [edi+indexAllocatedSize], 18h
  2339.         mov     byte [edi+indexFlags], 3
  2340.         mov     [edi+16], eax
  2341.         mov     [esi+recordVCN], eax
  2342.         mov     eax, [ebp+NTFS.LastRead]
  2343.         mov     [ebp+NTFS.nodeLastRead], eax
  2344.         push    [ebp+NTFS.cur_size]
  2345.         mov     [ebp+NTFS.cur_size], 0
  2346.         call    ntfs_read_attr.continue
  2347.         pop     [ebp+NTFS.cur_size]
  2348.         movi    eax, ERROR_FS_FAIL
  2349.         jc      ntfsErrorPop5
  2350.         pop     eax edi
  2351. @@:         ; move index to the branch node
  2352.         push    edi eax
  2353.         call    .ntfsNodeAlloc
  2354.         jc      ntfsErrorPop5
  2355.         mov     eax, [esp]
  2356.         mov     esi, [ebp+NTFS.secondIndexBuffer]
  2357.         add     esi, recordNode
  2358.         mov     ecx, [esi+nodeRealSize]
  2359.         add     eax, ecx
  2360.         cmp     [esi+nodeAllocatedSize], eax
  2361.         jc      .growBranch
  2362.         mov     [esi+nodeRealSize], eax
  2363.         lea     edi, [esi+eax-4]
  2364.         add     esi, ecx
  2365.         mov     ecx, esi
  2366.         sub     ecx, [ebp+NTFS.indexPointer]
  2367.         shr     ecx, 2
  2368.         sub     esi, 4
  2369.         std
  2370.         rep movsd   ; make space
  2371.         mov     [edi], ecx
  2372.         pop     ecx
  2373.         sub     ecx, 8
  2374.         shr     ecx, 2
  2375.         mov     edi, esi
  2376.         add     edi, 4
  2377.         mov     esi, [esp]
  2378.         add     word [esi+indexAllocatedSize], 8
  2379.         mov     byte [esi+indexFlags], 1
  2380.         cld
  2381.         rep movsd   ; insert index
  2382.         mov     eax, [ebp+NTFS.newRecord]
  2383.         stosd
  2384.         mov     ebx, [ebp+NTFS.secondIndexBuffer]
  2385.         mov     edx, [ebp+NTFS.nodeLastRead]
  2386.         push    esi
  2387.         call    writeRecord
  2388.         pop     esi
  2389. .splitNode:
  2390.         mov     edi, [ebp+NTFS.cur_index_buf]
  2391.         mov     eax, edi
  2392.         add     eax, recordNode
  2393.         add     eax, [edi+recordNode+nodeRealSize]
  2394.         sub     eax, esi
  2395.         push    eax
  2396.         mov     ecx, [edi+recordNode+indexOffset]
  2397.         add     eax, ecx
  2398.         add     ecx, recordNode
  2399.         shr     ecx, 2
  2400.         push    esi
  2401.         mov     esi, edi
  2402.         mov     edi, [ebp+NTFS.secondIndexBuffer]
  2403.         rep movsd
  2404.         pop     esi
  2405.         pop     ecx
  2406.         shr     ecx, 2
  2407.         rep movsd
  2408.         mov     edi, [ebp+NTFS.secondIndexBuffer]
  2409.         mov     [edi+recordNode+nodeRealSize], eax
  2410.         pop     edi
  2411.         mov     cl, 4
  2412.         xor     eax, eax
  2413.         mov     esi, edi
  2414.         rep stosd
  2415.         mov     byte [esi+indexAllocatedSize], 16
  2416.         mov     byte [esi+indexFlags], 2
  2417.         mov     esi, [ebp+NTFS.cur_index_buf]
  2418.         mov     eax, [ebp+NTFS.newRecord]
  2419.         mov     [esi+recordVCN], eax
  2420.         add     esi, recordNode
  2421.         sub     edi, esi
  2422.         mov     [esi+nodeRealSize], edi
  2423.         mov     ebx, [ebp+NTFS.secondIndexBuffer]
  2424.         mov     edx, [ebp+NTFS.LastRead]
  2425.         call    writeRecord
  2426.         jmp     .refresh
  2427.  
  2428. .common:
  2429.         add     edi, edx
  2430.         sub     edi, 4
  2431.         mov     esi, edi
  2432.         sub     esi, [esp]
  2433.         mov     ecx, esi
  2434.         sub     ecx, eax    ; eax = pointer in the record
  2435.         shr     ecx, 2
  2436.         inc     ecx
  2437.         std
  2438.         rep movsd           ; move forward, make space
  2439.         mov     ecx, [esp]
  2440.         shr     ecx, 2
  2441.         xor     eax, eax
  2442.         rep stosd
  2443.         cld
  2444.         add     edi, 4
  2445.         call    ntfsGetTime
  2446.         mov     [edi+fileCreated], eax
  2447.         mov     [edi+fileCreated+4], edx
  2448.         mov     [edi+fileModified], eax
  2449.         mov     [edi+fileModified+4], edx
  2450.         mov     [edi+recordModified], eax
  2451.         mov     [edi+recordModified+4], edx
  2452.         mov     [edi+fileAccessed], eax
  2453.         mov     [edi+fileAccessed+4], edx
  2454.         pop     ecx
  2455.         pop     esi
  2456.         mov     [edi+indexAllocatedSize], cx    ; fill index with data
  2457.         mov     eax, [esp]
  2458.         shl     eax, 1
  2459.         add     eax, 42h
  2460.         mov     [edi+indexRawSize], ax
  2461.         mov     eax, [ebp+NTFS.cur_iRecord]
  2462.         mov     [edi+directoryRecordReference], eax
  2463.         mov     eax, [ebp+NTFS.frs_buffer]
  2464.         mov     eax, [eax+reuseCounter]
  2465.         mov     [edi+directoryReferenceReuse], ax
  2466.         mov     eax, [ebp+NTFS.frs_size]
  2467.         shr     eax, 8
  2468.         add     ecx, 30h+48h+8+18h+8
  2469.         add     ecx, eax
  2470.         mov     eax, [ebp+NTFS.fileRealSize]
  2471.         add     ecx, eax
  2472.         mov     [edi+fileRealSize], eax
  2473.         cmp     [ebp+NTFS.frs_size], ecx
  2474.         jc      @f
  2475.         xor     eax, eax
  2476. @@:
  2477.         mov     ecx, [ebp+NTFS.sectors_per_cluster]
  2478.         shl     ecx, 9
  2479.         add     eax, ecx
  2480.         dec     eax
  2481.         xor     edx, edx
  2482.         div     ecx
  2483.         mov     [ebp+NTFS.fileDataSize], eax
  2484.         mul     ecx
  2485.         mov     [edi+fileAllocatedSize], eax
  2486.         pop     ecx
  2487.         mov     [ebp+NTFS.indexPointer], edi
  2488.         mov     [edi+fileNameLength], cl
  2489.         add     edi, fileName
  2490. @@:         ; record filename
  2491.         lodsb
  2492.         call    ansi2uni_char
  2493.         stosw
  2494.         dec     ecx
  2495.         jnz     @b
  2496.         mov     eax, [ebp+NTFS.LastRead]
  2497.         mov     [ebp+NTFS.nodeLastRead], eax
  2498.         cmp     [ebp+NTFS.bFolder], 0
  2499.         jz      @f
  2500.         mov     edi, [ebp+NTFS.indexPointer]
  2501.         bts     dword [edi+fileFlags], 28
  2502.         jmp     .mftBitmap
  2503.  
  2504. @@: ; 3. File data
  2505.         cmp     [ebp+NTFS.fileDataSize], 0
  2506.         jz      .mftBitmap
  2507.         mov     edi, [ebp+NTFS.BitmapStart]
  2508.         call    ntfsSpaceAlloc
  2509.         jc      ntfsDiskFull
  2510.         mov     eax, [ebp+NTFS.fileDataStart]
  2511.         mul     [ebp+NTFS.sectors_per_cluster]
  2512.         mov     ecx, [ebp+NTFS.fileRealSize]
  2513.         add     ecx, 511
  2514.         shr     ecx, 9
  2515.         mov     ebx, [ebp+NTFS.fileDataBuffer]
  2516.         call    fs_write64_app
  2517.         test    eax, eax
  2518.         jnz     ntfsDevice
  2519.     ; 4. MFT record
  2520. .mftBitmap: ; search for free record
  2521.         mov     edi, [ebp+NTFS.mftBitmapBuffer]
  2522.         mov     ecx, [ebp+NTFS.mftBitmapSize]
  2523.         mov     al, -1
  2524.         add     edi, 3
  2525.         sub     ecx, 3
  2526.         repz scasb
  2527.         dec     edi
  2528.         movzx   eax, byte [edi]
  2529.         not     al
  2530.         bsf     ecx, eax
  2531.         jz      .extendBitmapMFT    ; no free records
  2532.         bts     [edi], ecx
  2533. ; get record location
  2534.         sub     edi, [ebp+NTFS.mftBitmapBuffer]
  2535.         shl     edi, 3
  2536.         add     edi, ecx
  2537.         mov     [ebp+NTFS.newRecord], edi
  2538.         mov     eax, [ebp+NTFS.frs_size]
  2539.         shr     eax, 9
  2540.         mul     edi
  2541.         mov     [ebp+NTFS.cur_iRecord], 0
  2542.         mov     [ebp+NTFS.cur_attr], 0x80
  2543.         mov     [ebp+NTFS.cur_offs], eax
  2544.         push    eax
  2545.         mov     [ebp+NTFS.cur_size], 0
  2546.         mov     eax, [ebp+NTFS.frs_buffer]
  2547.         mov     [ebp+NTFS.cur_buf], eax
  2548.         call    ntfs_read_attr
  2549.         pop     eax
  2550.         jc      ntfsFail
  2551.         cmp     eax, [ebp+NTFS.mftSize]
  2552.         jnc     .extendMFT
  2553.         jmp     .mftRecord
  2554.  
  2555. .extendBitmapMFT:
  2556.         mov     eax, [ebp+NTFS.sectors_per_cluster]
  2557.         mov     [ebp+NTFS.cur_offs], eax
  2558.         shl     eax, 9
  2559.         cmp     [ebp+NTFS.mftBitmapSize], eax
  2560.         jnc     ntfsUnsupported
  2561.         mov     [ebp+NTFS.cur_iRecord], 0
  2562.         mov     [ebp+NTFS.cur_attr], 0xB0
  2563.         mov     [ebp+NTFS.cur_size], 0
  2564.         call    ntfs_read_attr
  2565.         jc      ntfsFail
  2566.         mov     eax, [ebp+NTFS.mft_cluster]
  2567.         mul     [ebp+NTFS.sectors_per_cluster]
  2568.         cmp     eax, [ebp+NTFS.LastRead]
  2569.         jnz     ntfsUnsupported     ; auxiliary record
  2570.         mov     edi, [ebp+NTFS.mftBitmapBuffer]
  2571.         mov     ecx, [ebp+NTFS.mftBitmapSize]
  2572.         add     edi, ecx
  2573.         mov     eax, ecx
  2574.         mov     edx, [ebp+NTFS.attr_offs]
  2575.         add     ecx, 8
  2576.         mov     [edx+attributeRealSize], ecx
  2577.         mov     [edx+initialDataSize], ecx
  2578.         shl     eax, 3
  2579.         mov     [ebp+NTFS.newRecord], eax
  2580.         mov     dword [edi], 1
  2581.         mov     dword [edi+4], 0
  2582.         mov     [ebp+NTFS.cur_attr], 0x80
  2583.         mov     [ebp+NTFS.cur_offs], 0
  2584.         call    ntfs_read_attr.newAttribute
  2585.         jc      ntfsFail
  2586.         mov     [ebp+NTFS.mftBitmapSize], ecx
  2587. .extendMFT:
  2588.         mov     eax, [ebp+NTFS.mft_cluster]
  2589.         mul     [ebp+NTFS.sectors_per_cluster]
  2590.         cmp     eax, [ebp+NTFS.LastRead]
  2591.         jnz     ntfsUnsupported     ; auxiliary record
  2592.         mov     ecx, [ebp+NTFS.attr_offs]
  2593.         mov     eax, [ecx+attributeRealSize]
  2594.         mov     edx, [ecx+attributeRealSize+4]
  2595.         xor     ax, ax
  2596.         add     eax, 10000h
  2597.         adc     edx, 0
  2598.         push    [ebp+NTFS.fileDataStart]
  2599.         push    [ebp+NTFS.fileDataSize]
  2600.         call    resizeAttribute
  2601.         jc      ntfsErrorPop2
  2602.         mov     ebx, [ebp+NTFS.frs_buffer]
  2603.         mov     edx, [ebp+NTFS.LastRead]
  2604.         call    writeRecord     ; $MFT
  2605.         mov     eax, [ebp+NTFS.mftmirr_cluster]
  2606.         mul     [ebp+NTFS.sectors_per_cluster]
  2607.         mov     ecx, [ebp+NTFS.frs_size]
  2608.         shr     ecx, 9
  2609.         call    fs_write64_sys  ; $MFTMirr
  2610. ; update $MFT retrieval information
  2611.         mov     edi, [ebp+NTFS.mft_retrieval_end]
  2612.         mov     eax, [edi-4]
  2613.         add     eax, [edi-8]
  2614.         mov     edx, [ebp+NTFS.fileDataSize]
  2615.         cmp     eax, [ebp+NTFS.fileDataStart]
  2616.         jnz     .newFragment
  2617.         add     [edi-8], edx
  2618.         jmp     @f
  2619. .newFragment:
  2620.         lea     eax, [ebp+NTFS.attrlist_buf]
  2621.         cmp     eax, edi
  2622.         jz      @f
  2623.         mov     [edi], edx
  2624.         mov     eax, [ebp+NTFS.fileDataStart]
  2625.         mov     [edi+4], eax
  2626.         add     [ebp+NTFS.mft_retrieval_end], 8
  2627. @@:
  2628.         mov     eax, [ebp+NTFS.fileDataSize]
  2629.         mul     [ebp+NTFS.sectors_per_cluster]
  2630.         add     [ebp+NTFS.mftSize], eax
  2631.         call    ntfsSpaceClean
  2632.         pop     [ebp+NTFS.fileDataSize]
  2633.         pop     [ebp+NTFS.fileDataStart]
  2634. .mftRecord:
  2635.         mov     ecx, [ebp+NTFS.frs_size]
  2636.         shr     ecx, 2
  2637.         mov     edi, [ebp+NTFS.frs_buffer]
  2638.         xor     eax, eax
  2639.         rep stosd
  2640.         mov     esi, [ebp+NTFS.indexPointer]
  2641.         mov     eax, [ebp+NTFS.newRecord]
  2642.         mov     [esi+fileRecordReference], eax
  2643.         rdtsc
  2644.         mov     [esi+fileReferenceReuse], ax
  2645.         mov     edi, [ebp+NTFS.frs_buffer]
  2646. ; record header
  2647.         mov     [edi+reuseCounter], ax
  2648.         mov     [edi+2ah], ax
  2649.         mov     eax, [ebp+NTFS.frs_size]
  2650.         mov     [edi+recordAllocatedSize], eax
  2651.         shr     eax, 9
  2652.         inc     eax
  2653.         mov     [edi+updateSequenceSize], al
  2654.         shl     eax, 1
  2655.         add     eax, 2ah+7
  2656.         and     eax, not 7
  2657.         mov     dword[edi], 'FILE'
  2658.         mov     byte [edi+updateSequenceOffset], 2ah
  2659.         mov     byte [edi+hardLinkCounter], 1
  2660.         mov     byte [edi+newAttributeID], 3
  2661.         mov     [edi+attributeOffset], al
  2662.         add     edi, eax
  2663. ; $StandardInformation
  2664.         mov     byte [edi+attributeType], 10h
  2665.         mov     byte [edi+sizeWithHeader], 48h
  2666.         mov     byte [edi+sizeWithoutHeader], 30h
  2667.         mov     byte [edi+attributeOffset], 18h
  2668.         mov     cl, 8
  2669.         add     esi, fileCreated
  2670.         add     edi, 18h
  2671.         rep movsd
  2672.         add     edi, 16
  2673.         mov     esi, [ebp+NTFS.indexPointer]
  2674. ; $FileName
  2675.         mov     byte [edi+attributeType], 30h
  2676.         mov     byte [edi+attributeID], 1
  2677.         mov     byte [edi+attributeOffset], 18h
  2678.         mov     byte [edi+indexedFlag], 1
  2679.         mov     cx, [esi+indexRawSize]
  2680.         mov     [edi+sizeWithoutHeader], ecx
  2681.         mov     cx, [esi+indexAllocatedSize]
  2682.         add     ecx, 8
  2683.         mov     [edi+sizeWithHeader], ecx
  2684.         add     edi, 18h
  2685.         add     esi, 16
  2686.         sub     ecx, 18h
  2687.         shr     ecx, 2
  2688.         rep movsd
  2689.         mov     byte [edi+sizeWithHeader], 50h
  2690.         mov     byte [edi+attributeID], 2
  2691.         cmp     [ebp+NTFS.bFolder], 1
  2692.         jz      .indexRoot
  2693. ; $Data
  2694.         mov     byte [edi+attributeType], 80h
  2695.         mov     eax, [ebp+NTFS.fileDataSize]
  2696.         test    eax, eax
  2697.         jz      .resident
  2698.         mov     esi, [ebp+NTFS.indexPointer]
  2699.         dec     eax
  2700.         mov     [edi+lastVCN], eax
  2701.         mov     byte [edi+nonResidentFlag], 1
  2702.         mov     byte [edi+dataRunsOffset], 40h
  2703.         mov     eax, [esi+fileAllocatedSize]
  2704.         mov     [edi+attributeAllocatedSize], eax
  2705.         mov     eax, [esi+fileRealSize]
  2706.         mov     [edi+attributeRealSize], eax
  2707.         mov     [edi+initialDataSize], eax
  2708.         push    edi
  2709.         mov     esi, edi
  2710.         add     edi, 40h
  2711.         call    createMcbEntry
  2712.         inc     edi
  2713.         jmp     @f
  2714.  
  2715. .resident:
  2716.         mov     ecx, [ebp+NTFS.fileRealSize]
  2717.         mov     [edi+sizeWithoutHeader], ecx
  2718.         mov     byte [edi+attributeOffset], 18h
  2719.         push    edi
  2720.         mov     esi, [ebp+NTFS.fileDataBuffer]
  2721.         add     edi, 18h
  2722.         rep movsb
  2723. @@:
  2724.         mov     eax, edi
  2725.         pop     edi
  2726.         sub     eax, edi
  2727.         add     eax, 7
  2728.         and     eax, not 7
  2729.         mov     [edi+sizeWithHeader], eax
  2730.         add     edi, eax
  2731.         mov     al, 1
  2732.         jmp     .end
  2733.  
  2734. .indexRoot:
  2735.         mov     byte [edi+attributeType], 90h
  2736.         mov     byte [edi+nameLength], 4
  2737.         mov     byte [edi+nameOffset], 18h
  2738.         mov     byte [edi+sizeWithoutHeader], 30h
  2739.         mov     byte [edi+attributeOffset], 20h
  2740.         mov     dword[edi+18h], 490024h     ; unicode $I30
  2741.         mov     dword[edi+18h+4], 300033h
  2742.         mov     byte [edi+20h+indexedAttributesType], 30h
  2743.         mov     byte [edi+20h+collationRule], 1
  2744.         mov     eax, [ebp+NTFS.sectors_per_cluster]
  2745.         mov     dl, 1
  2746.         shl     eax, 8
  2747. @@:
  2748.         shl     eax, 1
  2749.         shl     edx, 1
  2750.         cmp     eax, [ebp+NTFS.frs_size]
  2751.         jc      @b
  2752.         shr     edx, 1
  2753.         mov     [edi+20h+indexRecordSize], eax
  2754.         mov     [edi+20h+indexRecordSizeClus], dl
  2755.         mov     byte [edi+30h+indexOffset], 16
  2756.         mov     byte [edi+30h+nodeRealSize], 32
  2757.         mov     byte [edi+30h+nodeAllocatedSize], 32
  2758.         mov     byte [edi+40h+indexAllocatedSize], 16
  2759.         mov     byte [edi+40h+indexFlags], 2
  2760.         add     edi, 50h
  2761.         mov     al, 3
  2762. .end:
  2763.         mov     ebx, [ebp+NTFS.frs_buffer]
  2764.         mov     dword [edi], -1
  2765.         mov     dword [edi+4], 0
  2766.         add     edi, 8
  2767.         sub     edi, ebx
  2768.         mov     [ebx+recordFlags], al
  2769.         mov     [ebx+recordRealSize], edi
  2770.         mov     edx, [ebp+NTFS.LastRead]
  2771.         call    writeRecord
  2772. ; write MFT bitmap
  2773.         mov     eax, [ebp+NTFS.newRecord]
  2774.         shr     eax, 3+9
  2775.         mov     ebx, eax
  2776.         shl     ebx, 9
  2777.         add     eax, [ebp+NTFS.mftBitmapLocation]
  2778.         add     ebx, [ebp+NTFS.mftBitmapBuffer]
  2779.         mov     ecx, 1
  2780.         xor     edx, edx
  2781.         call    fs_write64_sys
  2782. ; 5. Write directory node
  2783.         mov     ebx, [ebp+NTFS.cur_index_buf]
  2784.         mov     edx, [ebp+NTFS.nodeLastRead]
  2785.         call    writeRecord
  2786.         mov     ebx, [ebp+NTFS.fileRealSize]
  2787. ntfsDone:
  2788.         mov     esi, [ebp+PARTITION.Disk]
  2789.         call    disk_sync
  2790.         call    ntfs_unlock
  2791.         xor     eax, eax
  2792.         ret
  2793.  
  2794. writeRecord:
  2795. ; make updateSequence and write to disk
  2796. ;   in:
  2797. ; ebx -> record
  2798. ; edx = partition sector
  2799.         mov     esi, ebx
  2800.         mov     edi, ebx
  2801.         movzx   ecx, word [esi+updateSequenceOffset]
  2802.         add     edi, ecx
  2803.         mov     ax, [edi]
  2804.         inc     ax
  2805.         stosw
  2806.         mov     cx, [esi+updateSequenceSize]
  2807.         dec     ecx
  2808.         push    ecx
  2809. @@:
  2810.         add     esi, 510
  2811.         movsw
  2812.         mov     [esi-2], ax
  2813.         dec     ecx
  2814.         jnz     @b
  2815.         mov     eax, edx
  2816.         xor     edx, edx
  2817.         pop     ecx
  2818.         jmp     fs_write64_sys
  2819.  
  2820. createMcbEntry:
  2821. ;   in:
  2822. ; [ebp+NTFS.fileDataStart] = position value
  2823. ; [ebp+NTFS.fileDataSize] = size value
  2824. ; edi -> destination
  2825. ; esi -> attribute header
  2826.         mov     eax, [ebp+NTFS.fileDataStart]
  2827.         xor     edx, edx
  2828.         shl     eax, 1
  2829.         jnc     @f
  2830.         not     eax
  2831. @@:
  2832.         inc     edx
  2833.         shr     eax, 8
  2834.         jnz     @b
  2835.         mov     eax, [ebp+NTFS.fileDataSize]
  2836.         shl     eax, 1
  2837.         xor     ecx, ecx
  2838. @@:
  2839.         inc     ecx
  2840.         shr     eax, 8
  2841.         jnz     @b
  2842.         lea     eax, [edi+edx+1]
  2843.         add     eax, ecx
  2844.         sub     eax, esi
  2845.         sub     eax, [esi+sizeWithHeader]
  2846.         jc      @f
  2847.         add     word [esi+sizeWithHeader], 8    ; extend attribute
  2848.         mov     esi, [ebp+NTFS.frs_buffer]
  2849.         mov     eax, [esi+recordRealSize]
  2850.         add     eax, 8
  2851.         cmp     [esi+recordAllocatedSize], eax
  2852.         jc      .end    ; no space in the record
  2853.         mov     [esi+recordRealSize], eax
  2854.         push    ecx edi
  2855.         add     esi, eax
  2856.         mov     ecx, esi
  2857.         sub     ecx, edi
  2858.         sub     ecx, 8
  2859.         shr     ecx, 2
  2860.         mov     edi, esi
  2861.         sub     edi, 4
  2862.         sub     esi, 12
  2863.         std
  2864.         rep movsd
  2865.         cld
  2866.         pop     edi ecx
  2867. @@:
  2868.         mov     eax, edx
  2869.         shl     eax, 4
  2870.         add     eax, ecx
  2871.         stosb
  2872.         lea     esi, [ebp+NTFS.fileDataSize]
  2873.         rep movsb
  2874.         lea     esi, [ebp+NTFS.fileDataStart]
  2875.         mov     ecx, edx
  2876.         rep movsb
  2877.         mov     [edi], cl
  2878. .end:
  2879.         ret
  2880.  
  2881. resizeAttribute:
  2882. ;   in:
  2883. ; [ebp+NTFS.frs_buffer] -> file record
  2884. ; [ebp+NTFS.attr_offs] -> attribute
  2885. ; edx:eax = new size
  2886. ;   out:
  2887. ; [ebp+NTFS.fileDataSize] = clusters added (positive)
  2888. ; [ebp+NTFS.fileDataStart] = added block
  2889. ; CF=1 -> eax = error code
  2890.         mov     esi, [ebp+NTFS.attr_offs]
  2891.         mov     dword [ebp+NTFS.attr_size], eax
  2892.         mov     dword [ebp+NTFS.attr_size+4], edx
  2893.         cmp     byte [esi+nonResidentFlag], 0
  2894.         jz      .resident
  2895.         mov     ecx, [ebp+NTFS.sectors_per_cluster]
  2896.         shl     ecx, 9
  2897.         mov     [esi+attributeRealSize], eax
  2898.         mov     [esi+attributeRealSize+4], edx
  2899.         mov     [esi+initialDataSize], eax
  2900.         mov     [esi+initialDataSize+4], edx
  2901.         sub     eax, 1
  2902.         sbb     edx, 0
  2903.         jc      .makeResident
  2904.         div     ecx
  2905.         mov     edi, eax
  2906.         inc     eax
  2907.         mul     ecx
  2908.         mov     [esi+attributeAllocatedSize], eax
  2909.         mov     [esi+attributeAllocatedSize+4], edx
  2910.         mov     ecx, [esi+lastVCN]
  2911.         mov     [esi+lastVCN], edi
  2912.         movzx   eax, byte [esi+dataRunsOffset]
  2913.         sub     edi, ecx
  2914.         mov     [ebp+NTFS.fileDataSize], edi
  2915.         jz      .done
  2916.         jc      .shrinkAttribute
  2917. ; extend attribute
  2918.         xor     edi, edi
  2919.         add     esi, eax
  2920.         push    edi edi edi edi
  2921. @@:
  2922.         mov     edx, eax
  2923.         mov     eax, esi
  2924.         add     edi, [esp+8]
  2925.         call    ntfs_decode_mcb_entry
  2926.         jc      @b
  2927.         mov     [esp+4], edx
  2928.         mov     [esp+12], edi
  2929.         add     edi, [esp]
  2930.         push    edi
  2931.         shr     edi, 5
  2932.         shl     edi, 2
  2933.         push    eax
  2934.         cmp     [ebp+NTFS.cur_iRecord], 0
  2935.         jz      @f
  2936.         cmp     edi, [ebp+NTFS.BitmapStart]
  2937.         jc      .err1
  2938. @@:
  2939.         call    ntfsSpaceAlloc
  2940.         jc      .err1
  2941.         mov     eax, [ebp+NTFS.fileDataStart]
  2942.         pop     edi
  2943.         pop     edx
  2944.         cmp     edx, eax
  2945.         jnz     .newEntry
  2946.         pop     edx
  2947.         pop     edi
  2948.         pop     [ebp+NTFS.fileDataStart]
  2949.         mov     [esp], eax
  2950.         push    [ebp+NTFS.fileDataSize]
  2951.         add     [ebp+NTFS.fileDataSize], edx
  2952.         jmp     @f
  2953.  
  2954. .newEntry:
  2955.         add     esp, 12
  2956.         pop     edx
  2957.         push    eax
  2958.         push    [ebp+NTFS.fileDataSize]
  2959.         sub     eax, edx
  2960.         mov     [ebp+NTFS.fileDataStart], eax
  2961. @@:
  2962.         mov     esi, [ebp+NTFS.attr_offs]
  2963.         call    createMcbEntry
  2964.         pop     [ebp+NTFS.fileDataSize]
  2965.         pop     [ebp+NTFS.fileDataStart]
  2966.         movi    eax, ERROR_UNSUPPORTED_FS
  2967. .done:
  2968.         ret
  2969.  
  2970. .err1:
  2971.         add     esp, 24
  2972.         stc
  2973. .err2:
  2974.         movi    eax, ERROR_DISK_FULL
  2975.         ret
  2976.  
  2977. .err3:
  2978.         movi    eax, ERROR_FS_FAIL
  2979.         add     esp, 20
  2980.         stc
  2981.         ret
  2982.  
  2983. .shrinkAttribute:
  2984.         add     ecx, edi
  2985.         inc     ecx
  2986.         add     esi, eax
  2987.         xor     edi, edi
  2988.         sub     esp, 20
  2989. @@:
  2990.         mov     [esp+16], esi
  2991.         call    ntfs_decode_mcb_entry
  2992.         jnc     .err3
  2993.         add     edi, [esp+8]
  2994.         sub     ecx, [esp]
  2995.         jnc     @b
  2996.         mov     ebx, ecx
  2997.         add     ecx, [esp]
  2998.         mov     eax, [esp+8]
  2999.         mov     [ebp+NTFS.fileDataSize], ecx
  3000.         mov     [ebp+NTFS.fileDataStart], eax
  3001.         push    edi
  3002.         add     edi, ecx
  3003.         neg     ebx
  3004.         call    ntfsSpaceFree
  3005.         pop     edi
  3006.         jc      .end
  3007. @@:
  3008.         call    ntfs_decode_mcb_entry
  3009.         jnc     .end
  3010.         cmp     dword[esp+8], 0
  3011.         jz      @b
  3012.         add     edi, [esp+8]
  3013.         mov     ebx, [esp]
  3014.         call    ntfsSpaceFree
  3015.         jnc     @b
  3016. .end:
  3017.         add     esp, 16
  3018.         pop     edi
  3019.         cmp     [ebp+NTFS.fileDataSize], 0
  3020.         jz      @f
  3021.         mov     esi, [ebp+NTFS.attr_offs]
  3022.         call    createMcbEntry
  3023.         mov     [ebp+NTFS.fileDataSize], 0
  3024. @@:
  3025.         ret
  3026.  
  3027. .resident:
  3028.         test    edx, edx
  3029.         jnz     .nonResident
  3030.         cmp     eax, 8000h
  3031.         jnc     .nonResident
  3032.         add     ax, [esi+attributeOffset]
  3033.         sub     eax, [esi+sizeWithHeader]
  3034.         jc      @f
  3035.         mov     edi, [ebp+NTFS.frs_buffer]
  3036.         mov     ecx, eax
  3037.         add     ecx, [edi+recordRealSize]
  3038.         cmp     [edi+recordAllocatedSize], ecx
  3039.         jc      .nonResident
  3040.         add     eax, 7
  3041.         and     eax, not 7
  3042.         add     [edi+recordRealSize], eax
  3043.         add     edi, [edi+recordRealSize]
  3044.         add     [esi+sizeWithHeader], eax
  3045.         add     esi, [esi+sizeWithHeader]
  3046.         mov     ecx, edi
  3047.         sub     ecx, esi
  3048.         shr     ecx, 2
  3049.         sub     edi, 4
  3050.         mov     esi, edi
  3051.         sub     esi, eax
  3052.         std
  3053.         rep movsd
  3054.         mov     ecx, eax
  3055.         shr     ecx, 2
  3056.         xor     eax, eax
  3057.         rep stosd
  3058.         cld
  3059.         mov     esi, [ebp+NTFS.attr_offs]
  3060. @@:
  3061.         mov     eax, dword [ebp+NTFS.attr_size]
  3062.         mov     [esi+sizeWithoutHeader], eax
  3063.         mov     [ebp+NTFS.fileDataSize], 0
  3064.         clc
  3065.         ret
  3066.  
  3067. .nonResident:   ; convert resident to non-resident
  3068.         mov     eax, dword [ebp+NTFS.attr_size]
  3069.         sub     eax, 1
  3070.         sbb     edx, 0
  3071.         mov     ecx, [ebp+NTFS.sectors_per_cluster]
  3072.         shl     ecx, 9
  3073.         div     ecx
  3074.         inc     eax
  3075.         mov     [ebp+NTFS.fileDataSize], eax
  3076.         mov     edi, [ebp+NTFS.BitmapStart]
  3077.         push    ecx
  3078.         call    ntfsSpaceAlloc
  3079.         pop     ecx
  3080.         jc      .err2
  3081.         mov     esi, [ebp+NTFS.attr_offs]
  3082.         xor     eax, eax
  3083.         xor     edx, edx
  3084. @@:
  3085.         add     eax, ecx
  3086.         inc     edx
  3087.         cmp     eax, [esi+sizeWithoutHeader]
  3088.         jc      @b
  3089.         push    edx
  3090.         push    eax
  3091.         stdcall kernel_alloc, eax
  3092.         mov     ecx, [esp]
  3093.         shr     ecx, 2
  3094.         mov     edi, eax
  3095.         mov     ebx, eax
  3096.         xor     eax, eax
  3097.         rep stosd
  3098.         mov     al, [esi+attributeOffset]
  3099.         mov     ecx, [esi+sizeWithoutHeader]
  3100.         add     esi, eax
  3101.         mov     edi, ebx
  3102.         rep movsb
  3103.         mov     eax, [ebp+NTFS.fileDataStart]
  3104.         mul     [ebp+NTFS.sectors_per_cluster]
  3105.         pop     ecx
  3106.         shr     ecx, 9
  3107.         call    fs_write64_app
  3108.         stdcall kernel_free, ebx
  3109.         mov     esi, [ebp+NTFS.attr_offs]
  3110.         add     esi, [esi+sizeWithHeader]
  3111.         mov     ecx, [ebp+NTFS.frs_buffer]
  3112.         add     ecx, [ecx+recordRealSize]
  3113.         sub     ecx, esi
  3114.         shr     ecx, 2
  3115.         lea     edi, [ebp+NTFS.bitmap_buf]
  3116.         push    ecx
  3117.         rep movsd
  3118.         mov     edi, [ebp+NTFS.attr_offs]
  3119.         add     edi, 16
  3120.         mov     cl, 6
  3121.         xor     eax, eax
  3122.         rep stosd
  3123.         mov     edi, [ebp+NTFS.attr_offs]
  3124.         mov     eax, [ebp+NTFS.fileDataSize]
  3125.         dec     eax
  3126.         mov     [edi+lastVCN], eax
  3127.         inc     eax
  3128.         mov     ecx, [ebp+NTFS.sectors_per_cluster]
  3129.         shl     ecx, 9
  3130.         mul     ecx
  3131.         mov     byte [edi+sizeWithHeader], 50h
  3132.         mov     byte [edi+nonResidentFlag], 1
  3133.         mov     byte [edi+dataRunsOffset], 40h
  3134.         mov     [edi+attributeAllocatedSize], eax
  3135.         mov     [edi+attributeAllocatedSize+4], edx
  3136.         mov     eax, dword [ebp+NTFS.attr_size]
  3137.         mov     edx, dword [ebp+NTFS.attr_size+4]
  3138.         mov     [edi+attributeRealSize], eax
  3139.         mov     [edi+attributeRealSize+4], edx
  3140.         mov     [edi+initialDataSize], eax
  3141.         mov     [edi+initialDataSize+4], edx
  3142.         mov     esi, edi
  3143.         add     edi, 40h
  3144.         call    createMcbEntry
  3145.         mov     eax, edi
  3146.         mov     edi, [ebp+NTFS.attr_offs]
  3147.         sub     eax, edi
  3148.         add     eax, 8
  3149.         and     eax, not 7
  3150.         mov     [edi+sizeWithHeader], eax
  3151.         pop     ecx
  3152.         lea     esi, [ebp+NTFS.bitmap_buf]
  3153.         add     edi, eax
  3154.         rep movsd
  3155.         mov     esi, [ebp+NTFS.frs_buffer]
  3156.         sub     edi, esi
  3157.         mov     [esi+recordRealSize], edi
  3158.         pop     edx
  3159.         sub     [ebp+NTFS.fileDataSize], edx
  3160.         add     [ebp+NTFS.fileDataStart], edx
  3161.         ret
  3162.  
  3163. .makeResident:  ; convert non-resident to empty resident
  3164.         movzx   eax, byte [esi+dataRunsOffset]
  3165.         mov     byte [esi+nonResidentFlag], 0
  3166.         mov     dword [esi+sizeWithoutHeader], 0
  3167.         mov     dword [esi+attributeOffset], 18h
  3168.         add     esi, eax
  3169.         xor     edi, edi
  3170.         sub     esp, 16
  3171. @@:
  3172.         call    ntfs_decode_mcb_entry
  3173.         jnc     @f
  3174.         cmp     dword[esp+8], 0
  3175.         jz      @b
  3176.         add     edi, [esp+8]
  3177.         mov     ebx, [esp]
  3178.         call    ntfsSpaceFree
  3179.         jnc     @b
  3180. @@:
  3181.         add     esp, 16
  3182.         mov     [ebp+NTFS.fileDataSize], 0
  3183.         ret
  3184.  
  3185. ntfsSpaceClean:
  3186. ; clean up to 16 Mb of disk space
  3187. ;   in:
  3188. ; [ebp+NTFS.fileDataStart] = block to clean
  3189. ; [ebp+NTFS.fileDataSize] = block size
  3190.         mov     eax, [ebp+NTFS.fileDataSize]
  3191.         test    eax, eax
  3192.         jz      @f
  3193.         mul     [ebp+NTFS.sectors_per_cluster]
  3194.         cmp     eax, 8001h
  3195.         jnc     @f
  3196.         push    eax
  3197.         shl     eax, 9
  3198.         stdcall kernel_alloc, eax
  3199.         pop     ecx
  3200.         test    eax, eax
  3201.         jz      @f
  3202.         push    ecx
  3203.         shl     ecx, 7
  3204.         mov     edi, eax
  3205.         mov     ebx, eax
  3206.         xor     eax, eax
  3207.         rep stosd
  3208.         mov     eax, [ebp+NTFS.fileDataStart]
  3209.         mul     [ebp+NTFS.sectors_per_cluster]
  3210.         mov     [ebp+NTFS.LastRead], eax
  3211.         pop     ecx
  3212.         call    fs_write64_app
  3213.         stdcall kernel_free, ebx
  3214. @@:
  3215.         ret
  3216.  
  3217. ntfsSpaceAlloc:
  3218. ; allocate disk space
  3219. ;   in:
  3220. ; edi = offset in bitmap to start search from
  3221. ; [ebp+NTFS.fileDataSize] = block size in clusters
  3222. ;   out:
  3223. ; [ebp+NTFS.fileDataStart] = allocated block starting cluster
  3224. ; CF=1 -> disk full
  3225.         push    eax
  3226.         mov     ecx, [ebp+NTFS.BitmapBuffer]
  3227.         add     edi, ecx
  3228.         add     ecx, [ebp+NTFS.BitmapSize]
  3229.         sub     ecx, edi
  3230.         jnc     @f
  3231.         call    bitmapBuffering
  3232.         shl     ecx, 2
  3233. @@:
  3234.         shr     ecx, 2
  3235.         mov     eax, [ebp+NTFS.fileDataSize]
  3236.         shr     eax, 5
  3237.         jz      .small
  3238.         mov     ebx, eax    ; bitmap dwords
  3239. .start:
  3240.         mov     ecx, [ebp+NTFS.BitmapBuffer]
  3241.         add     ecx, [ebp+NTFS.BitmapSize]
  3242.         sub     ecx, edi
  3243.         shr     ecx, 2
  3244. @@:
  3245.         xor     eax, eax
  3246.         repnz scasd         ; search for empty dword
  3247.         jz      @f
  3248.         call    bitmapBuffering
  3249.         jmp     @b
  3250. @@:
  3251.         cmp     ecx, ebx
  3252.         jnc     @f
  3253.         call    bitmapBuffering
  3254.         jmp     @b
  3255. @@:
  3256.         sub     edi, 4
  3257.         mov     ecx, ebx
  3258.         mov     esi, edi
  3259.         xor     eax, eax
  3260.         repz scasd          ; check following dwords
  3261.         jnz     .start
  3262.         sub     esi, 4
  3263.         mov     eax, [esi]
  3264.         xor     edx, edx
  3265.         bsr     edx, eax
  3266.         inc     edx
  3267.         push    edx         ; starting bit
  3268.         push    esi         ; starting dword
  3269.         add     esi, 4
  3270.         neg     edx
  3271.         add     edx, 32
  3272.         mov     eax, [ebp+NTFS.fileDataSize]
  3273.         sub     eax, edx
  3274.         mov     edx, eax
  3275.         shr     eax, 5
  3276.         shl     eax, 2
  3277.         add     esi, eax
  3278.         mov     eax, [esi]
  3279.         bsf     ecx, eax    ; check last dword
  3280.         jz      .done
  3281.         and     edx, 31
  3282.         cmp     ecx, edx
  3283.         jnc     .done
  3284.         add     esp, 8
  3285.         jmp     .start
  3286.  
  3287. .small:     ; less than 32 clusters
  3288.         mov     eax, -1
  3289.         repz scasd          ; search for zero bits
  3290.         test    ecx, ecx
  3291.         jnz     @f
  3292.         call    bitmapBuffering
  3293.         jmp     .small
  3294. @@:
  3295.         sub     edi, 4
  3296.         mov     eax, [edi]
  3297.         not     eax
  3298. @@:
  3299.         bsf     ebx, eax    ; first 0
  3300.         jz      .again
  3301.         not     eax
  3302.         shr     eax, cl
  3303.         shl     eax, cl
  3304.         bsf     edx, eax    ; next 1
  3305.         jz      @f
  3306.         sub     edx, ebx
  3307.         cmp     edx, [ebp+NTFS.fileDataSize]
  3308.         jnc     .got        ; fits inside
  3309.         bsf     ebx, eax
  3310.         not     eax
  3311.         shr     eax, cl
  3312.         shl     eax, cl
  3313.         jmp     @b
  3314. @@:         ; next dword
  3315.         mov     eax, [edi+4]
  3316.         bsf     edx, eax
  3317.         jz      .got        ; empty
  3318.         add     edx, 32
  3319.         sub     edx, ebx
  3320.         cmp     edx, [ebp+NTFS.fileDataSize]
  3321.         jnc     .got        ; share between dwords
  3322. .again:
  3323.         add     edi, 4
  3324.         jmp     .small
  3325.  
  3326. .got:
  3327.         push    ebx         ; starting bit
  3328.         push    edi         ; starting dword
  3329. .done:      ; mark space
  3330.         mov     ecx, [esp+4]
  3331.         cmp     ecx, 32
  3332.         jc      @f
  3333.         xor     ecx, ecx
  3334.         add     dword [esp], 4
  3335.         mov     [esp+4], ecx
  3336. @@:
  3337.         mov     edi, [esp]
  3338.         xor     eax, eax
  3339.         dec     eax
  3340.         shr     eax, cl
  3341.         shl     eax, cl
  3342.         neg     ecx
  3343.         add     ecx, 32
  3344.         sub     ecx, [ebp+NTFS.fileDataSize]
  3345.         jc      @f
  3346.         shl     eax, cl     ; fits inside dword
  3347.         shr     eax, cl
  3348.         or      [edi], eax
  3349.         jmp     .end
  3350.  
  3351. @@:
  3352.         or      [edi], eax
  3353.         neg     ecx
  3354.         push    ecx
  3355.         shr     ecx, 5
  3356.         add     edi, 4
  3357.         xor     eax, eax
  3358.         dec     eax
  3359.         rep stosd
  3360.         pop     ecx
  3361.         and     ecx, 31
  3362.         shr     eax, cl
  3363.         shl     eax, cl
  3364.         not     eax
  3365.         or      [edi], eax
  3366. .end:
  3367.         pop     eax
  3368.         pop     ecx
  3369.         sub     eax, [ebp+NTFS.BitmapBuffer]
  3370.         shl     eax, 3
  3371.         add     eax, ecx
  3372.         pop     ecx
  3373.         mov     ecx, [ebp+NTFS.fileDataSize]
  3374.         mov     [ebp+NTFS.fileDataStart], eax
  3375.         add     ecx, eax
  3376.         add     ecx, 4095
  3377.         shr     ecx, 3+9
  3378.         shr     eax, 3+9
  3379.         sub     ecx, eax
  3380.         mov     ebx, eax
  3381.         shl     ebx, 9
  3382.         add     eax, [ebp+NTFS.BitmapLocation]
  3383.         add     ebx, [ebp+NTFS.BitmapBuffer]
  3384.         xor     edx, edx
  3385.         jmp     fs_write64_app
  3386.  
  3387. ntfsSpaceFree:
  3388. ; free disk space
  3389. ;   in:
  3390. ; edi = starting cluster
  3391. ; ebx = size in clusters
  3392.         mov     eax, edi
  3393.         add     eax, ebx
  3394.         shr     eax, 3
  3395.         inc     eax
  3396.         cmp     eax, [ebp+NTFS.BitmapSize]
  3397.         jc      @f
  3398.         add     eax, [ebp+NTFS.BitmapBuffer]
  3399.         push    edi
  3400.         mov     edi, eax
  3401.         call    bitmapBuffering
  3402.         pop     edi
  3403. @@:
  3404.         push    edi
  3405.         mov     ecx, edi
  3406.         shr     edi, 5
  3407.         shl     edi, 2
  3408.         add     edi, [ebp+NTFS.BitmapBuffer]
  3409.         and     ecx, 31
  3410.         xor     eax, eax
  3411.         dec     eax
  3412.         shr     eax, cl
  3413.         shl     eax, cl
  3414.         neg     ecx
  3415.         add     ecx, 32
  3416.         sub     ecx, ebx
  3417.         jc      @f
  3418.         shl     eax, cl     ; fits inside dword
  3419.         shr     eax, cl
  3420.         not     eax
  3421.         and     [edi], eax
  3422.         jmp     .writeBitmap
  3423.  
  3424. @@:
  3425.         not     eax
  3426.         and     [edi], eax
  3427.         neg     ecx
  3428.         push    ecx
  3429.         shr     ecx, 5
  3430.         add     edi, 4
  3431.         xor     eax, eax
  3432.         rep stosd
  3433.         pop     ecx
  3434.         and     ecx, 31
  3435.         dec     eax
  3436.         shr     eax, cl
  3437.         shl     eax, cl
  3438.         and     [edi], eax
  3439. .writeBitmap:
  3440.         pop     eax
  3441.         mov     edi, eax
  3442.         lea     ecx, [eax+ebx+4095]
  3443.         shr     eax, 3+9
  3444.         shr     ecx, 3+9
  3445.         sub     ecx, eax
  3446.         mov     ebx, eax
  3447.         shl     ebx, 9
  3448.         add     eax, [ebp+NTFS.BitmapLocation]
  3449.         add     ebx, [ebp+NTFS.BitmapBuffer]
  3450.         xor     edx, edx
  3451.         jmp     fs_write64_app
  3452.  
  3453. bitmapBuffering:
  3454. ; Extend BitmapBuffer and read next 32kb of bitmap
  3455. ; Warning: $Bitmap fragmentation is not foreseen
  3456. ; in: edi -> position in bitmap buffer
  3457. ; out: ecx = number of buffered dwords left
  3458.         push    ebx
  3459.         mov     eax, [ebp+NTFS.BitmapTotalSize]
  3460.         cmp     eax, [ebp+NTFS.BitmapSize]
  3461.         jz      .end
  3462.         stdcall alloc_pages, 8
  3463.         test    eax, eax
  3464.         jz      .end
  3465.         add     eax, 3
  3466.         mov     ebx, [ebp+NTFS.BitmapBuffer]
  3467.         add     ebx, [ebp+NTFS.BitmapSize]
  3468.         push    ebx
  3469.         mov     ecx, 8
  3470.         call    commit_pages
  3471.         mov     eax, [ebp+NTFS.BitmapSize]
  3472.         shr     eax, 9
  3473.         add     eax, [ebp+NTFS.BitmapLocation]
  3474.         pop     ebx
  3475.         mov     ecx, 64
  3476.         xor     edx, edx
  3477.         call    fs_read64_app
  3478.         test    eax, eax
  3479.         jnz     .err
  3480.         add     [ebp+NTFS.BitmapSize], 8000h
  3481.         mov     eax, [ebp+NTFS.BitmapTotalSize]
  3482.         cmp     eax, [ebp+NTFS.BitmapSize]
  3483.         jnc     @f
  3484.         mov     [ebp+NTFS.BitmapSize], eax
  3485. @@:
  3486.         pop     ebx
  3487.         mov     ecx, [ebp+NTFS.BitmapBuffer]
  3488.         add     ecx, [ebp+NTFS.BitmapSize]
  3489.         sub     ecx, edi
  3490.         jc      bitmapBuffering
  3491.         shr     ecx, 2
  3492.         ret
  3493.  
  3494. .err:
  3495.         mov     eax, [ebp+NTFS.BitmapBuffer]
  3496.         add     eax, [ebp+NTFS.BitmapSize]
  3497.         mov     ecx, 8
  3498.         call    release_pages
  3499. .end:
  3500.         add     esp, 12     ; ret
  3501.         stc
  3502.         ret
  3503.  
  3504. ;----------------------------------------------------------------
  3505. ntfs_WriteFile:
  3506.         cmp     byte [esi], 0
  3507.         jnz     @f
  3508.         xor     ebx, ebx
  3509.         movi    eax, ERROR_ACCESS_DENIED
  3510.         ret
  3511. @@:
  3512.         call    ntfs_lock
  3513.         stdcall ntfs_find_lfn, [esp+4]
  3514.         jc      ntfsNotFound
  3515.         cmp     [ebp+NTFS.cur_iRecord], 16
  3516.         jc      ntfsDenied
  3517.         test    dword [eax+fileFlags], 10000001h
  3518.         jnz     ntfsDenied
  3519.         cmp     [ebp+NTFS.fragmentCount], 1
  3520.         jnz     ntfsUnsupported     ; record fragmented
  3521. ; edit directory node
  3522.         mov     edi, [ebp+NTFS.cur_index_buf]
  3523.         cmp     dword [edi], 'INDX'
  3524.         jz      @f
  3525.         mov     esi, [ebp+NTFS.frs_buffer]
  3526.         mov     ecx, [esi+recordRealSize]
  3527.         shr     ecx, 2
  3528.         rep movsd
  3529.         mov     esi, [ebp+NTFS.attr_offs]
  3530.         mov     cl, [esi+attributeOffset]
  3531.         sub     esi, [ebp+NTFS.frs_buffer]
  3532.         add     eax, ecx
  3533.         add     eax, esi
  3534. @@:
  3535.         mov     edi, eax
  3536.         mov     eax, [ebx+4]
  3537.         mov     edx, [ebx+8]
  3538.         add     eax, [ebx+12]
  3539.         adc     edx, 0
  3540.         mov     [edi+fileRealSize], eax
  3541.         mov     [edi+fileRealSize+4], edx
  3542.         push    edx eax ebx
  3543.         call    ntfsGetTime
  3544.         mov     [edi+fileModified], eax
  3545.         mov     [edi+fileModified+4], edx
  3546.         mov     [edi+recordModified], eax
  3547.         mov     [edi+recordModified+4], edx
  3548.         mov     [edi+fileAccessed], eax
  3549.         mov     [edi+fileAccessed+4], edx
  3550.         pop     ebx ecx edx
  3551.         mov     eax, [ebp+NTFS.LastRead]
  3552.         mov     [ebp+NTFS.nodeLastRead], eax
  3553.         mov     [ebp+NTFS.cur_attr], 0x80
  3554.         mov     [ebp+NTFS.cur_offs], 0
  3555.         mov     [ebp+NTFS.cur_size], 0
  3556.         call    ntfs_read_attr
  3557.         jc      ntfsFail
  3558.         mov     esi, edi
  3559.         mov     edi, [ebp+NTFS.frs_buffer]
  3560.         cmp     word [edi+baseRecordReuse], 0
  3561.         jnz     ntfsUnsupported     ; auxiliary record
  3562.         mov     al, [edi+attributeOffset]
  3563.         add     edi, eax
  3564.         mov     al, [edi+attributeOffset]
  3565.         add     edi, eax
  3566.         mov     eax, ecx
  3567.         mov     ecx, 6
  3568.         add     esi, fileModified
  3569.         add     edi, 8
  3570.         rep movsd
  3571.         mov     ecx, [ebp+NTFS.attr_offs]
  3572.         cmp     word [ecx+attributeFlags], 0
  3573.         jnz     ntfsUnsupported
  3574.         push    ebx
  3575.         cmp     byte [ecx+nonResidentFlag], 0
  3576.         jz      .resizeAttribute
  3577.         cmp     edx, [ecx+attributeRealSize+4]
  3578.         jc      .writeNode
  3579.         jnz     .resizeAttribute
  3580.         cmp     [ecx+attributeRealSize], eax
  3581.         jnc     .writeNode
  3582. .resizeAttribute:
  3583.         call    resizeAttribute
  3584.         jc      ntfsErrorPop
  3585.         mov     ecx, [ebp+NTFS.attr_offs]
  3586.         cmp     byte [ecx+nonResidentFlag], 1
  3587.         jz      @f
  3588.         mov     ebx, [esp]
  3589.         movzx   edi, byte [ecx+attributeOffset]
  3590.         add     edi, ecx
  3591.         add     edi, [ebx+4]
  3592.         mov     ecx, [ebx+12]
  3593.         mov     esi, [ebx+16]
  3594.         rep movsb
  3595. @@:
  3596.         mov     ebx, [ebp+NTFS.frs_buffer]
  3597.         mov     edx, [ebp+NTFS.mftLastRead]
  3598.         call    writeRecord     ; file
  3599.         call    ntfs_restore_usa_frs
  3600. .writeNode:
  3601.         mov     ebx, [ebp+NTFS.cur_index_buf]
  3602.         mov     edx, [ebp+NTFS.nodeLastRead]
  3603.         call    writeRecord     ; directory
  3604.         pop     ebx
  3605.         mov     ecx, [ebp+NTFS.attr_offs]
  3606.         cmp     byte [ecx+nonResidentFlag], 0
  3607.         jz      .done
  3608.         mov     ecx, [ebx+12]
  3609.         test    ecx, ecx
  3610.         jz      .done
  3611.         mov     eax, [ebx+4]
  3612.         mov     edx, [ebx+8]
  3613.         mov     esi, [ebx+16]
  3614.         shrd    eax, edx, 9
  3615.         test    dword[ebx+4], 1FFh
  3616.         jz      .aligned
  3617.         mov     [ebp+NTFS.cur_offs], eax
  3618.         mov     [ebp+NTFS.cur_size], 1
  3619.         lea     edi, [ebp+NTFS.bitmap_buf]
  3620.         mov     [ebp+NTFS.cur_buf], edi
  3621.         call    ntfs_read_attr.continue
  3622.         jc      ntfsDevice
  3623.         mov     eax, [ebx+4]
  3624.         and     eax, 1FFh
  3625.         add     edi, eax
  3626.         sub     eax, [ebp+NTFS.cur_read]
  3627.         neg     eax
  3628.         push    ecx
  3629.         cmp     ecx, eax
  3630.         jb      @f
  3631.         mov     ecx, eax
  3632. @@:
  3633.         sub     [esp], ecx
  3634.         rep movsb
  3635.         push    ebx
  3636.         mov     eax, [ebp+NTFS.LastRead]
  3637.         lea     ebx, [ebp+NTFS.bitmap_buf]
  3638.         mov     ecx, 1
  3639.         xor     edx, edx
  3640.         call    fs_write64_app
  3641.         pop     ebx
  3642.         pop     ecx
  3643.         test    ecx, ecx
  3644.         jz      .done
  3645.         mov     eax, [ebx+4]
  3646.         mov     edx, [ebx+8]
  3647.         shrd    eax, edx, 9
  3648.         inc     eax
  3649. .aligned:
  3650.         push    ecx
  3651.         shr     ecx, 9
  3652.         mov     [ebp+NTFS.cur_offs], eax
  3653.         mov     [ebp+NTFS.cur_size], ecx
  3654.         mov     [ebp+NTFS.cur_buf], esi
  3655.         add     eax, ecx
  3656.         push    eax
  3657.         mov     [ebp+NTFS.bWriteAttr], 1
  3658.         call    ntfs_read_attr.continue
  3659.         mov     [ebp+NTFS.bWriteAttr], 0
  3660.         pop     [ebp+NTFS.cur_offs]
  3661.         pop     ecx
  3662.         jc      ntfsDevice
  3663.         and     ecx, 1FFh
  3664.         jz      .done
  3665.         add     esi, [ebp+NTFS.cur_read]
  3666.         mov     [ebp+NTFS.cur_size], 1
  3667.         lea     edi, [ebp+NTFS.bitmap_buf]
  3668.         mov     [ebp+NTFS.cur_buf], edi
  3669.         call    ntfs_read_attr.continue
  3670.         jc      ntfsDevice
  3671.         rep movsb
  3672.         push    ebx
  3673.         mov     eax, [ebp+NTFS.LastRead]
  3674.         lea     ebx, [ebp+NTFS.bitmap_buf]
  3675.         mov     ecx, 1
  3676.         xor     edx, edx
  3677.         call    fs_write64_app
  3678.         pop     ebx
  3679. .done:
  3680.         mov     ebx, [ebx+12]
  3681.         jmp     ntfsDone
  3682.  
  3683. ;----------------------------------------------------------------
  3684. ntfs_Delete:
  3685.         cmp     byte [esi], 0
  3686.         jnz     @f
  3687.         xor     ebx, ebx
  3688.         movi    eax, ERROR_ACCESS_DENIED
  3689.         ret
  3690.  
  3691. @@:
  3692.         call    ntfs_lock
  3693.         stdcall ntfs_find_lfn, [esp+4]
  3694.         jc      ntfsNotFound
  3695.         cmp     [ebp+NTFS.cur_iRecord], 16
  3696.         jc      ntfsDenied
  3697.         test    byte [eax+fileFlags], 1
  3698.         jnz     ntfsDenied
  3699.         cmp     [ebp+NTFS.fragmentCount], 1
  3700.         jnz     ntfsUnsupported     ; record fragmented
  3701.         mov     ebx, [eax+directoryRecordReference]
  3702.         mov     [ebp+NTFS.newRecord], ebx
  3703.         mov     bx, [eax+fileReferenceReuse]
  3704.         mov     [ebp+NTFS.indexPointer], esi
  3705.         mov     eax, [ebp+NTFS.cur_iRecord]
  3706.         shr     eax, 3
  3707.         cmp     eax, [ebp+NTFS.mftBitmapSize]
  3708.         jnc     ntfsUnsupported
  3709. ; examine file record
  3710.         mov     [ebp+NTFS.cur_attr], 0x80   ; file?
  3711.         mov     [ebp+NTFS.cur_offs], 0
  3712.         mov     [ebp+NTFS.cur_size], 0
  3713.         call    ntfs_read_attr
  3714.         jnc     @f
  3715.         xor     eax, eax
  3716.         push    ebx eax eax eax eax
  3717.         mov     [esp+12], esp
  3718.         push    eax
  3719.         mov     ebx, esp
  3720.         mov     [ebp+NTFS.cur_attr], 0x90   ; folder?
  3721.         call    ntfs_ReadFolder.doit
  3722.         mov     edx, [esp+12]
  3723.         add     esp, 20
  3724.         pop     ebx
  3725.         test    eax, eax
  3726.         jnz     .ret
  3727.         cmp     edx, 2
  3728.         jnz     ntfsDenied      ; folder is not empty
  3729.         mov     [ebp+NTFS.cur_attr], 0xA0
  3730.         mov     [ebp+NTFS.cur_offs], 0
  3731.         mov     [ebp+NTFS.cur_size], 0
  3732.         call    ntfs_read_attr.newAttribute
  3733.         jc      .deleteFileRecord
  3734. @@:
  3735.         mov     esi, [ebp+NTFS.frs_buffer]
  3736.         cmp     word [esi+baseRecordReuse], 0
  3737.         jnz     ntfsUnsupported     ; auxiliary record
  3738.         cmp     word [esi+reuseCounter], bx
  3739.         jnz     .backToIndex        ; broken index
  3740.         test    byte [esi+recordFlags], 1
  3741.         jz      .writeBitmapMFT     ; record deleted
  3742.         cmp     byte [esi+hardLinkCounter], 3
  3743.         jnc     ntfsUnsupported
  3744.         mov     esi, [ebp+NTFS.attr_offs]
  3745.         cmp     byte [esi+nonResidentFlag], 0
  3746.         jz      .deleteFileRecord
  3747.         movzx   eax, byte [esi+dataRunsOffset]
  3748.         add     esi, eax
  3749.         xor     edi, edi
  3750.         sub     esp, 16
  3751. @@:
  3752.         call    ntfs_decode_mcb_entry
  3753.         jnc     @f
  3754.         cmp     dword[esp+8], 0
  3755.         jz      @b
  3756.         add     edi, [esp+8]
  3757.         mov     ebx, [esp]
  3758.         call    ntfsSpaceFree
  3759.         jnc     @b
  3760. @@:
  3761.         add     esp, 16
  3762. .deleteFileRecord:
  3763.         mov     ebx, [ebp+NTFS.frs_buffer]
  3764.         mov     byte [ebx+recordFlags], 0
  3765.         mov     edx, [ebp+NTFS.mftLastRead]
  3766.         call    writeRecord
  3767. .writeBitmapMFT:
  3768.         mov     eax, [ebp+NTFS.cur_iRecord]
  3769.         mov     ecx, eax
  3770.         shr     eax, 3
  3771.         and     ecx, 7
  3772.         mov     edi, [ebp+NTFS.mftBitmapBuffer]
  3773.         btr     [edi+eax], ecx
  3774.         shr     eax, 9
  3775.         mov     ebx, eax
  3776.         shl     ebx, 9
  3777.         add     eax, [ebp+NTFS.mftBitmapLocation]
  3778.         add     ebx, edi
  3779.         mov     ecx, 1
  3780.         xor     edx, edx
  3781.         call    fs_write64_sys
  3782. .backToIndex:
  3783.         mov     eax, [ebp+NTFS.newRecord]
  3784.         mov     [ebp+NTFS.cur_iRecord], eax
  3785.         mov     esi, [ebp+NTFS.indexPointer]
  3786.         stdcall ntfs_find_lfn.doit2, 0
  3787.         jc      ntfsFail
  3788.         mov     ebx, [ebp+NTFS.secondIndexBuffer]
  3789.         mov     byte [ebx], 0
  3790.         mov     ebx, [ebp+NTFS.LastRead]
  3791.         mov     [ebp+NTFS.nodeLastRead], ebx
  3792.         xor     ebx, ebx
  3793.         test    byte [eax+indexFlags], 1
  3794.         jz      .deleteIndex    ; no subnode
  3795.         mov     edi, eax
  3796.         call    .findSubindex
  3797.         jc      ntfsFail
  3798.         movzx   edx, word [edi+indexAllocatedSize]
  3799.         test    esi, esi
  3800.         jz      @f
  3801.         sub     edx, eax
  3802.         sub     edx, 8
  3803. @@:
  3804.         mov     eax, edi
  3805.         mov     ebx, esi
  3806.         jmp     @f
  3807.  
  3808. .deleteIndex:
  3809.         movzx   edx, word [eax+indexAllocatedSize]
  3810.         mov     ecx, [eax+fileRecordReference]
  3811.         cmp     [eax+edx+fileRecordReference], ecx
  3812.         jnz     @f
  3813.         add     dx, [eax+edx+indexAllocatedSize]
  3814. @@:
  3815.         mov     edi, [ebp+NTFS.cur_index_buf]
  3816.         cmp     dword [edi], 'INDX'
  3817.         jz      .indexRecord
  3818.         sub     eax, edi
  3819.         mov     edi, [ebp+NTFS.indexRoot]
  3820.         sub     [edi+sizeWithHeader], edx
  3821.         sub     [edi+sizeWithoutHeader], edx
  3822.         movzx   ecx, byte [edi+attributeOffset]
  3823.         add     edi, ecx
  3824.         add     eax, edi
  3825.         sub     [edi+rootNode+nodeRealSize], edx
  3826.         sub     [edi+rootNode+nodeAllocatedSize], edx
  3827.         mov     edi, [ebp+NTFS.frs_buffer]
  3828.         sub     [edi+recordRealSize], edx
  3829.         mov     ecx, [edi+recordRealSize]
  3830.         cmp     [edi+recordAllocatedSize], ecx
  3831.         jmp     @f
  3832.  
  3833. .indexRecord:
  3834.         add     edi, recordNode
  3835.         sub     [edi+nodeRealSize], edx
  3836.         mov     ecx, [edi+nodeRealSize]
  3837.         cmp     [edi+nodeAllocatedSize], ecx
  3838. @@:
  3839.         jc      ntfsUnsupported
  3840.         add     ecx, edi
  3841.         sub     ecx, eax
  3842.         mov     esi, eax
  3843.         add     esi, edx
  3844.         mov     edi, eax
  3845.         test    edx, edx
  3846.         jns     @f
  3847.         neg     edx
  3848.         add     edx, ecx
  3849.         sub     edx, 4
  3850.         add     esi, edx
  3851.         add     edi, edx
  3852.         std
  3853. @@:
  3854.         jz      @f
  3855.         shr     ecx, 2
  3856.         rep movsd
  3857.         cld
  3858. @@:
  3859.         test    ebx, ebx
  3860.         jz      .done
  3861. ; copy index from the subnode to replace deleted pointing index
  3862.         movzx   ecx, word [ebx+indexAllocatedSize]
  3863.         mov     edx, ecx
  3864.         test    byte [ebx+indexFlags], 1
  3865.         jz      @f
  3866.         sub     ecx, 8
  3867.         movzx   edi, word [ebx+edx+indexAllocatedSize]
  3868.         add     edi, edx
  3869.         mov     esi, [ebx+ecx]
  3870.         mov     [ebx+edi-8], esi
  3871.         mov     [ebx+indexAllocatedSize], cx
  3872. @@:
  3873.         shr     ecx, 2
  3874.         mov     esi, ebx
  3875.         mov     edi, eax
  3876.         rep movsd
  3877.         add     word [eax+indexAllocatedSize], 8
  3878.         mov     byte [eax+indexFlags], 1
  3879.         mov     edi, [ebp+NTFS.secondIndexBuffer]
  3880.         mov     eax, ebx
  3881.         xor     ebx, ebx
  3882.         jmp     .indexRecord
  3883.  
  3884. .done:
  3885.         mov     ebx, [ebp+NTFS.frs_buffer]
  3886.         mov     edx, [ebp+NTFS.rootLastRead]
  3887.         call    writeRecord
  3888.         mov     ebx, [ebp+NTFS.cur_index_buf]
  3889.         cmp     dword [ebx], 'INDX'
  3890.         jnz     @f
  3891.         mov     edx, [ebp+NTFS.nodeLastRead]
  3892.         call    writeRecord
  3893. @@:
  3894.         mov     ebx, [ebp+NTFS.secondIndexBuffer]
  3895.         cmp     byte [ebx], 0
  3896.         jz      ntfsDone
  3897.         mov     edx, [ebp+NTFS.LastRead]
  3898.         call    writeRecord
  3899.         jmp     ntfsDone
  3900.  
  3901. .findSubindex:
  3902. ; in: eax -> index
  3903. ;   out:
  3904. ; CF=1 -> error
  3905. ; esi=0 -> subnode deleted
  3906. ; esi -> replacement index
  3907. ; eax = index effective size
  3908.         movzx   edx, word [eax+indexAllocatedSize]
  3909.         mov     eax, [eax+edx-8]
  3910.         mov     edx, [ebp+NTFS.cur_size]
  3911.         push    edx
  3912.         cmp     edx, [ebp+NTFS.cur_subnode_size]
  3913.         jz      @f
  3914.         mul     [ebp+NTFS.sectors_per_cluster]
  3915. @@:
  3916.         mov     [ebp+NTFS.cur_attr], 0xA0
  3917.         mov     [ebp+NTFS.cur_offs], eax
  3918.         push    eax
  3919.         mov     ebx, [ebp+NTFS.secondIndexBuffer]
  3920.         mov     esi, ebx
  3921.         mov     [ebp+NTFS.cur_buf], ebx
  3922.         call    ntfs_read_attr.newAttribute
  3923.         pop     [ebp+NTFS.cur_offs]
  3924.         pop     eax
  3925.         jc      .ret
  3926.         cmp     dword [esi], 'INDX'
  3927.         stc
  3928.         jnz     .ret
  3929.         mov     [ebp+NTFS.cur_size], eax
  3930.         shl     eax, 9
  3931.         call    ntfs_restore_usa
  3932.         jc      .ret
  3933.         add     esi, recordNode
  3934.         add     esi, [esi+indexOffset]
  3935.         test    byte [esi+indexFlags], 2
  3936.         jnz     .emptyNode
  3937.         cmp     [ebp+NTFS.fragmentCount], 1
  3938.         stc
  3939.         jnz     .ret    ; record fragmented
  3940.         xor     eax, eax
  3941. @@:
  3942.         add     esi, eax
  3943.         mov     ax, [esi+indexAllocatedSize]
  3944.         test    byte [esi+eax+indexFlags], 2
  3945.         jz      @b
  3946.         test    byte [esi+indexFlags], 1
  3947.         jz      .ret
  3948.         add     eax, esi
  3949.         push    esi
  3950.         push    [ebp+NTFS.cur_offs]
  3951.         call    .findSubindex
  3952.         pop     [ebp+NTFS.cur_offs]
  3953.         pop     edx
  3954.         jc      .ret
  3955.         test    esi, esi
  3956.         jnz     .ret
  3957.         mov     esi, edx
  3958.         mov     ebx, [ebp+NTFS.secondIndexBuffer]
  3959.         mov     [ebp+NTFS.cur_buf], ebx
  3960.         push    [ebp+NTFS.cur_size]
  3961.         call    ntfs_read_attr.continue
  3962.         pop     eax
  3963.         jc      .ret
  3964.         shl     eax, 9
  3965.         call    ntfs_restore_usa
  3966.         jc      .ret
  3967.         movzx   eax, word [esi+indexAllocatedSize]
  3968.         sub     eax, 8
  3969. .ret:
  3970.         ret
  3971.  
  3972. .emptyNode:
  3973.         test    byte [esi+indexFlags], 1
  3974.         jz      @f
  3975.         mov     eax, esi
  3976.         push    [ebp+NTFS.cur_offs]
  3977.         call    .findSubindex
  3978.         pop     [ebp+NTFS.cur_offs]
  3979.         jc      .ret
  3980.         test    esi, esi
  3981.         jnz     .ret
  3982. @@:         ; delete node
  3983.         mov     esi, [ebp+NTFS.attr_offs]
  3984.         add     esi, [esi+sizeWithHeader]
  3985.         cmp     byte [esi], 0xB0
  3986.         stc
  3987.         jnz     .ret
  3988.         movzx   eax, byte [esi+attributeOffset]
  3989.         add     esi, eax
  3990.         mov     eax, [ebp+NTFS.cur_offs]
  3991.         xor     edx, edx
  3992.         div     [ebp+NTFS.cur_size]
  3993.         mov     edx, eax
  3994.         shr     eax, 3
  3995.         and     edx, 7
  3996.         btr     [esi+eax], edx
  3997.         mov     esi, [ebp+NTFS.secondIndexBuffer]
  3998.         mov     byte [esi], 0
  3999.         xor     esi, esi
  4000.         ret
  4001.  
  4002. ;----------------------------------------------------------------
  4003. ntfs_SetFileEnd:
  4004.         cmp     byte [esi], 0
  4005.         jnz     @f
  4006.         xor     ebx, ebx
  4007.         movi    eax, ERROR_ACCESS_DENIED
  4008.         ret
  4009. @@:
  4010.         call    ntfs_lock
  4011.         stdcall ntfs_find_lfn, [esp+4]
  4012.         jc      ntfsNotFound
  4013.         cmp     [ebp+NTFS.cur_iRecord], 16
  4014.         jc      ntfsDenied
  4015.         test    dword [eax+fileFlags], 10000001h
  4016.         jnz     ntfsDenied
  4017.         cmp     [ebp+NTFS.fragmentCount], 1
  4018.         jnz     ntfsUnsupported     ; record fragmented
  4019. ; edit directory node
  4020.         mov     edi, [ebp+NTFS.cur_index_buf]
  4021.         cmp     dword [edi], 'INDX'
  4022.         jz      @f
  4023.         mov     esi, [ebp+NTFS.frs_buffer]
  4024.         mov     ecx, [esi+recordRealSize]
  4025.         shr     ecx, 2
  4026.         rep movsd
  4027.         mov     esi, [ebp+NTFS.attr_offs]
  4028.         mov     cl, [esi+attributeOffset]
  4029.         sub     esi, [ebp+NTFS.frs_buffer]
  4030.         add     eax, ecx
  4031.         add     eax, esi
  4032. @@:
  4033.         mov     edi, eax
  4034.         mov     eax, [ebx+4]
  4035.         mov     edx, [ebx+8]
  4036.         mov     [edi+fileRealSize], eax
  4037.         mov     [edi+fileRealSize+4], edx
  4038.         push    edx eax ebx
  4039.         call    ntfsGetTime
  4040.         mov     [edi+fileModified], eax
  4041.         mov     [edi+fileModified+4], edx
  4042.         mov     [edi+recordModified], eax
  4043.         mov     [edi+recordModified+4], edx
  4044.         mov     [edi+fileAccessed], eax
  4045.         mov     [edi+fileAccessed+4], edx
  4046.         pop     ebx ecx edx
  4047.         mov     eax, [ebp+NTFS.LastRead]
  4048.         mov     [ebp+NTFS.nodeLastRead], eax
  4049.         mov     [ebp+NTFS.cur_attr], 0x80
  4050.         mov     [ebp+NTFS.cur_offs], 0
  4051.         mov     [ebp+NTFS.cur_size], 0
  4052.         call    ntfs_read_attr
  4053.         jc      ntfsFail
  4054.         mov     esi, edi
  4055.         mov     edi, [ebp+NTFS.frs_buffer]
  4056.         cmp     word [edi+baseRecordReuse], 0
  4057.         jnz     ntfsUnsupported     ; auxiliary record
  4058.         mov     al, [edi+attributeOffset]
  4059.         add     edi, eax
  4060.         mov     al, [edi+attributeOffset]
  4061.         add     edi, eax
  4062.         mov     eax, ecx
  4063.         mov     ecx, 6
  4064.         add     esi, fileModified
  4065.         add     edi, 8
  4066.         rep movsd
  4067.         mov     ecx, [ebp+NTFS.attr_offs]
  4068.         cmp     word [ecx+attributeFlags], 0
  4069.         jnz     ntfsUnsupported
  4070.         cmp     byte [ecx+nonResidentFlag], 0
  4071.         jz      .resizeAttribute
  4072.         cmp     [ecx+attributeRealSize+4], edx
  4073.         jnz     .resizeAttribute
  4074.         cmp     [ecx+attributeRealSize], eax
  4075.         jnc     .resizeAttribute
  4076.         mov     eax, [ecx+attributeRealSize]
  4077.         mov     ecx, [ebp+NTFS.sectors_per_cluster]
  4078.         mov     [ebp+NTFS.cur_size], ecx
  4079.         shl     ecx, 9
  4080.         div     ecx
  4081.         test    edx, edx
  4082.         jz      .aligned
  4083.         push    edx
  4084.         push    ecx
  4085.         mul     [ebp+NTFS.sectors_per_cluster]
  4086.         mov     [ebp+NTFS.cur_offs], eax
  4087.         stdcall kernel_alloc, ecx
  4088.         pop     ecx
  4089.         pop     edi
  4090.         mov     esi, eax
  4091.         sub     ecx, edi
  4092.         add     edi, eax
  4093.         mov     [ebp+NTFS.cur_buf], eax
  4094.         call    ntfs_read_attr.continue
  4095.         jc      @f
  4096.         xor     eax, eax
  4097.         rep stosb
  4098.         push    ebx
  4099.         mov     eax, [ebp+NTFS.LastRead]
  4100.         mov     ebx, esi
  4101.         mov     ecx, [ebp+NTFS.sectors_per_cluster]
  4102.         xor     edx, edx
  4103.         call    fs_write64_app
  4104.         pop     ebx
  4105. @@:
  4106.         stdcall kernel_free, esi
  4107. .aligned:
  4108.         mov     eax, [ebx+4]
  4109.         mov     edx, [ebx+8]
  4110. .resizeAttribute:
  4111.         call    resizeAttribute
  4112.         jc      ntfsError
  4113.         mov     ebx, [ebp+NTFS.frs_buffer]
  4114.         mov     edx, [ebp+NTFS.mftLastRead]
  4115.         call    writeRecord     ; file
  4116.         mov     ebx, [ebp+NTFS.cur_index_buf]
  4117.         mov     edx, [ebp+NTFS.nodeLastRead]
  4118.         call    writeRecord     ; directory
  4119.         call    ntfsSpaceClean
  4120.         jmp     ntfsDone
  4121.  
  4122. ntfsGetTime:
  4123.         call    fsGetTime
  4124.         jmp     @f
  4125.  
  4126. ntfsCalculateTime:
  4127. ; in: esi -> data block
  4128. ; out: edx:eax = seconds since 01.01.1601 x10000000
  4129.         call    fsCalculateTime
  4130. @@:
  4131.         mov     edx, 10000000
  4132.         mul     edx
  4133.         add     eax, 3365781504
  4134.         adc     edx, 29389701
  4135.         ret
  4136.  
  4137. ;----------------------------------------------------------------
  4138. ntfs_SetFileInfo:
  4139.         cmp     byte [esi], 0
  4140.         jnz     @f
  4141.         movi    eax, ERROR_UNSUPPORTED_FS
  4142.         ret
  4143. @@:
  4144.         call    ntfs_lock
  4145.         stdcall ntfs_find_lfn, [esp+4]
  4146.         jnc     @f
  4147.         test    eax, eax
  4148.         jz      ntfsFail
  4149.         jmp     ntfsNotFound
  4150.  
  4151. @@:
  4152.         cmp     [ebp+NTFS.fragmentCount], 1
  4153.         jnz     ntfsUnsupported     ; record fragmented
  4154.         mov     esi, [ebp+NTFS.cur_index_buf]
  4155.         cmp     dword [esi], 'INDX'
  4156.         jz      @f
  4157.         sub     eax, esi
  4158.         mov     esi, [ebp+NTFS.indexRoot]
  4159.         movzx   edx, byte [esi+attributeOffset]
  4160.         add     eax, esi
  4161.         add     eax, edx
  4162. @@:
  4163.         mov     esi, [ebx+16]
  4164.         mov     edi, eax
  4165.         mov     eax, [esi]
  4166.         and     eax, 27h
  4167.         and     byte [edi+fileFlags], -28h
  4168.         or      [edi+fileFlags], al
  4169.         add     esi, 8
  4170.         call    ntfsCalculateTime
  4171.         mov     [edi+fileCreated], eax
  4172.         mov     [edi+fileCreated+4], edx
  4173.         add     esi, 8
  4174.         call    ntfsCalculateTime
  4175.         mov     [edi+fileAccessed], eax
  4176.         mov     [edi+fileAccessed+4], edx
  4177.         add     esi, 8
  4178.         call    ntfsCalculateTime
  4179.         mov     [edi+fileModified], eax
  4180.         mov     [edi+fileModified+4], edx
  4181.         mov     ebx, [ebp+NTFS.cur_index_buf]
  4182.         cmp     dword [ebx], 'INDX'
  4183.         jz      @f
  4184.         mov     ebx, [ebp+NTFS.frs_buffer]
  4185. @@:
  4186.         mov     edx, [ebp+NTFS.LastRead]
  4187.         call    writeRecord
  4188.         jmp     ntfsDone
  4189.  
  4190. ntfsUnsupported:
  4191.         push    ERROR_UNSUPPORTED_FS
  4192.         jmp     ntfsOut
  4193. ntfsDevice:
  4194.         push    ERROR_DEVICE
  4195.         jmp     ntfsOut
  4196. ntfsNotFound:
  4197.         push    ERROR_FILE_NOT_FOUND
  4198.         jmp     ntfsOut
  4199. ntfsDenied:
  4200.         push    ERROR_ACCESS_DENIED
  4201.         jmp     ntfsOut
  4202. ntfsFail:
  4203.         push    ERROR_FS_FAIL
  4204.         jmp     ntfsOut
  4205. ntfsDiskFull:
  4206.         push    ERROR_DISK_FULL
  4207.         jmp     ntfsOut
  4208. ntfsErrorPop5:
  4209.         pop     ebx
  4210.         pop     ebx
  4211. ntfsErrorPop3:
  4212.         pop     ebx
  4213. ntfsErrorPop2:
  4214.         pop     ebx
  4215. ntfsErrorPop:
  4216.         pop     ebx
  4217. ntfsError:
  4218.         push    eax
  4219. ntfsOut:
  4220.         call    ntfs_unlock
  4221.         xor     ebx, ebx
  4222.         pop     eax
  4223.         ret
  4224.