Subversion Repositories Kolibri OS

Rev

Rev 6869 | 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: 6876 $
  9.  
  10. ; NTFS external functions
  11. ;   in:
  12. ; ebx -> parameter structure of sysfunc 70
  13. ; ebp -> NTFS structure
  14. ; esi -> path string in UTF-8
  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. mft_retrieval       rb  512
  171. align0  rb  1024-NTFS.align0
  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. ntfs_find_lfn:
  1165. ; in: esi -> path string in UTF-8
  1166. ;   out:
  1167. ; [ebp+NTFS.cur_iRecord] = target fileRecord
  1168. ; eax -> target index in the node
  1169. ; [ebp+NTFS.LastRead] = target node location
  1170. ; [ebp+NTFS.indexPointer] -> index, that points the target subnode
  1171. ; [ebp+NTFS.nodeLastRead] = branch node location
  1172. ; [ebp+NTFS.indexRoot] -> attribute
  1173. ; [ebp+NTFS.rootLastRead] = directory fileRecord location
  1174. ; [ebp+NTFS.cur_size] = index record size in sectors
  1175. ; [ebp+NTFS.cur_subnode_size] = index record size in clusters or sectors
  1176. ; CF=1 -> file not found, eax=0 -> error
  1177.         mov     [ebp+NTFS.cur_iRecord], 5   ; start from root directory
  1178. .doit2:
  1179.         mov     [ebp+NTFS.cur_attr], 0x90   ; $INDEX_ROOT
  1180.         and     [ebp+NTFS.cur_offs], 0
  1181.         mov     eax, [ebp+NTFS.cur_index_size]
  1182.         mov     [ebp+NTFS.cur_size], eax
  1183.         mov     eax, [ebp+NTFS.cur_index_buf]
  1184.         mov     [ebp+NTFS.cur_buf], eax
  1185.         call    ntfs_read_attr
  1186.         mov     eax, 0
  1187.         jc      .ret
  1188.         cmp     [ebp+NTFS.cur_read], 0x20
  1189.         jc      .ret
  1190.         push    esi
  1191.         pushad
  1192.         mov     esi, [ebp+NTFS.cur_index_buf]
  1193.         mov     eax, [esi+indexRecordSize]
  1194.         shr     eax, 9
  1195.         cmp     [ebp+NTFS.cur_index_size], eax
  1196.         jc      .realloc
  1197.         mov     [ebp+NTFS.cur_size], eax
  1198.         mov     al, [esi+indexRecordSizeClus]
  1199.         mov     [ebp+NTFS.cur_subnode_size], eax
  1200.         add     esi, rootNode
  1201.         mov     eax, [esi+nodeRealSize]
  1202.         add     eax, rootNode
  1203.         cmp     [ebp+NTFS.cur_read], eax
  1204.         jc      .err
  1205.         mov     eax, [ebp+NTFS.mftLastRead]
  1206.         mov     [ebp+NTFS.rootLastRead], eax
  1207.         mov     eax, [ebp+NTFS.attr_offs]
  1208.         mov     [ebp+NTFS.indexRoot], eax
  1209. .scanloop:  ; esi -> current index node
  1210.         add     esi, [esi+indexOffset]
  1211. .scanloopint:
  1212.         push    esi
  1213.         test    byte [esi+indexFlags], 2
  1214.         jnz     .subnode
  1215.         movzx   ecx, byte [esi+fileNameLength]
  1216.         lea     edi, [esi+fileName]
  1217.         mov     esi, [esp+8]
  1218. @@:
  1219.         call    utf8to16
  1220.         cmp     ax, '/'
  1221.         jz      .subnode
  1222.         call    utf16toUpper
  1223.         push    eax
  1224.         mov     ax, [edi]
  1225.         call    utf16toUpper
  1226.         cmp     [esp], ax
  1227.         pop     eax
  1228.         jc      .subnode
  1229.         jnz     .scanloopcont
  1230.         add     edi, 2
  1231.         loop    @b
  1232.         call    utf8to16
  1233.         cmp     ax, '/'
  1234.         jz      .found
  1235.         test    ax, ax
  1236.         jz      .found
  1237. .scanloopcont:
  1238.         pop     esi
  1239.         movzx   eax, word [esi+indexAllocatedSize]
  1240.         add     esi, eax
  1241.         jmp     .scanloopint
  1242.  
  1243. .realloc:
  1244.         mov     edi, eax
  1245.         mov     eax, [esi+indexRecordSize]
  1246.         shl     eax, 1
  1247.         stdcall kernel_alloc, eax
  1248.         test    eax, eax
  1249.         jz      .err
  1250.         mov     edx, [ebp+NTFS.cur_index_buf]
  1251.         cmp     edx, [ebp+NTFS.secondIndexBuffer]
  1252.         jc      @f
  1253.         mov     edx, [ebp+NTFS.secondIndexBuffer]
  1254. @@:
  1255.         mov     [ebp+NTFS.cur_index_buf], eax
  1256.         add     eax, [esi+indexRecordSize]
  1257.         mov     [ebp+NTFS.secondIndexBuffer], eax
  1258.         mov     [ebp+NTFS.cur_index_size], edi
  1259.         stdcall kernel_free, edx
  1260.         popad
  1261.         pop     eax
  1262.         jmp     .doit2
  1263.  
  1264. .notfound:
  1265.         mov     [esp+28], esi
  1266. .err:
  1267.         popad
  1268.         stc
  1269. .ret2:
  1270.         pop     esi
  1271. .ret:
  1272.         ret
  1273.  
  1274. .subnode:
  1275.         pop     esi
  1276.         test    byte [esi+indexFlags], 1
  1277.         jz      .notfound
  1278.         mov     eax, [ebp+NTFS.LastRead]
  1279.         mov     [ebp+NTFS.nodeLastRead], eax
  1280.         mov     [ebp+NTFS.indexPointer], esi
  1281.         movzx   eax, word [esi+indexAllocatedSize]
  1282.         mov     eax, [esi+eax-8]
  1283.         mov     edx, [ebp+NTFS.cur_size]
  1284.         push    edx
  1285.         cmp     edx, [ebp+NTFS.cur_subnode_size]
  1286.         jz      @f
  1287.         mul     [ebp+NTFS.sectors_per_cluster]
  1288. @@:
  1289.         mov     esi, [ebp+NTFS.cur_index_buf]
  1290.         xchg    [ebp+NTFS.secondIndexBuffer], esi
  1291.         mov     [ebp+NTFS.cur_index_buf], esi
  1292.         mov     [ebp+NTFS.cur_buf], esi
  1293.         mov     [ebp+NTFS.cur_attr], 0xA0   ; $INDEX_ALLOCATION
  1294.         mov     [ebp+NTFS.cur_offs], eax
  1295.         call    ntfs_read_attr.newAttribute
  1296.         pop     eax
  1297.         mov     [ebp+NTFS.cur_size], eax
  1298.         shl     eax, 9
  1299.         cmp     [ebp+NTFS.cur_read], eax
  1300.         jnz     .err
  1301.         cmp     dword [esi], 'INDX'
  1302.         jnz     .err
  1303.         mov     ebx, esi
  1304.         call    ntfs_restore_usa
  1305.         jc      .err
  1306.         add     esi, recordNode
  1307.         jmp     .scanloop
  1308.  
  1309. .found:
  1310.         mov     [esp+8], esi
  1311.         pop     eax
  1312.         mov     [esp+28], eax
  1313.         mov     eax, [eax+fileRecordReference]
  1314.         mov     [ebp+NTFS.cur_iRecord], eax
  1315.         popad
  1316.         cmp     byte [esi-1], 0
  1317.         jz      .ret2
  1318.         pop     eax
  1319.         jmp     .doit2
  1320.  
  1321. ;----------------------------------------------------------------
  1322. ntfs_ReadFile:
  1323.         call    ntfs_lock
  1324.         call    ntfs_find_lfn
  1325.         jc      ntfsNotFound
  1326.         mov     [ebp+NTFS.cur_attr], 0x80   ; $DATA
  1327.         and     [ebp+NTFS.cur_offs], 0
  1328.         and     [ebp+NTFS.cur_size], 0
  1329.         call    ntfs_read_attr
  1330.         jc      ntfsDenied
  1331.         xor     eax, eax
  1332.         push    eax
  1333.         cmp     dword [ebx+8], 0x200
  1334.         jnc     .eof
  1335.         mov     ecx, [ebx+12]
  1336.         mov     edx, [ebx+16]
  1337.         mov     eax, [ebx+4]
  1338.         test    eax, 0x1FF
  1339.         jz      .alignedstart
  1340.         push    edx
  1341.         mov     edx, [ebx+8]
  1342.         shrd    eax, edx, 9
  1343.         pop     edx
  1344.         mov     [ebp+NTFS.cur_offs], eax
  1345.         mov     [ebp+NTFS.cur_size], 1
  1346.         lea     eax, [ebp+NTFS.bitmap_buf]
  1347.         mov     [ebp+NTFS.cur_buf], eax
  1348.         call    ntfs_read_attr.continue
  1349.         mov     eax, [ebx+4]
  1350.         and     eax, 0x1FF
  1351.         lea     esi, [ebp+NTFS.bitmap_buf+eax]
  1352.         sub     eax, [ebp+NTFS.cur_read]
  1353.         jae     .eof
  1354.         neg     eax
  1355.         push    ecx
  1356.         cmp     ecx, eax
  1357.         jb      @f
  1358.         mov     ecx, eax
  1359. @@:
  1360.         mov     [esp+4], ecx
  1361.         mov     edi, edx
  1362.         rep movsb
  1363.         mov     edx, edi
  1364.         pop     ecx
  1365.         sub     ecx, [esp]
  1366.         jz      .retok
  1367.         cmp     [ebp+NTFS.cur_read], 0x200
  1368.         jnz     .eof
  1369. .alignedstart:
  1370.         mov     eax, [ebx+4]
  1371.         push    edx
  1372.         mov     edx, [ebx+8]
  1373.         add     eax, 511
  1374.         adc     edx, 0
  1375.         shrd    eax, edx, 9
  1376.         pop     edx
  1377.         mov     [ebp+NTFS.cur_offs], eax
  1378.         mov     [ebp+NTFS.cur_buf], edx
  1379.         mov     eax, ecx
  1380.         shr     eax, 9
  1381.         mov     [ebp+NTFS.cur_size], eax
  1382.         add     eax, [ebp+NTFS.cur_offs]
  1383.         push    eax
  1384.         call    ntfs_read_attr.continue
  1385.         pop     [ebp+NTFS.cur_offs]
  1386.         mov     eax, [ebp+NTFS.cur_read]
  1387.         add     [esp], eax
  1388.         mov     eax, ecx
  1389.         and     eax, not 0x1FF
  1390.         cmp     [ebp+NTFS.cur_read], eax
  1391.         jnz     .eof
  1392.         and     ecx, 0x1FF
  1393.         jz      .retok
  1394.         add     edx, [ebp+NTFS.cur_read]
  1395.         mov     [ebp+NTFS.cur_size], 1
  1396.         lea     eax, [ebp+NTFS.bitmap_buf]
  1397.         mov     [ebp+NTFS.cur_buf], eax
  1398.         call    ntfs_read_attr.continue
  1399.         cmp     [ebp+NTFS.cur_read], ecx
  1400.         jb      @f
  1401.         mov     [ebp+NTFS.cur_read], ecx
  1402. @@:
  1403.         xchg    ecx, [ebp+NTFS.cur_read]
  1404.         push    ecx
  1405.         mov     edi, edx
  1406.         lea     esi, [ebp+NTFS.bitmap_buf]
  1407.         add     [esp+4], ecx
  1408.         rep movsb
  1409.         pop     ecx
  1410.         cmp     ecx, [ebp+NTFS.cur_read]
  1411.         jnz     .eof
  1412. .retok:
  1413.         pushd   0
  1414. .ret:
  1415.         call    ntfs_unlock
  1416.         pop     eax ebx
  1417.         ret
  1418.  
  1419. .eof:
  1420.         push    ERROR_END_OF_FILE
  1421.         jmp     .ret
  1422.  
  1423. ;----------------------------------------------------------------
  1424. ntfs_ReadFolder:
  1425.         call    ntfs_lock
  1426.         mov     [ebp+NTFS.cur_iRecord], 5   ; root directory
  1427.         cmp     byte [esi], 0
  1428.         jz      @f
  1429.         call    ntfs_find_lfn
  1430.         jc      ntfsNotFound
  1431. @@:
  1432.         mov     [ebp+NTFS.cur_attr], 0x10   ; $STANDARD_INFORMATION
  1433.         and     [ebp+NTFS.cur_offs], 0
  1434.         mov     [ebp+NTFS.cur_size], 1
  1435.         lea     eax, [ebp+NTFS.bitmap_buf]
  1436.         mov     [ebp+NTFS.cur_buf], eax
  1437.         call    ntfs_read_attr
  1438.         jc      ntfsFail
  1439.         mov     [ebp+NTFS.cur_attr], 0x90   ; $INDEX_ROOT
  1440. .doit:
  1441.         mov     eax, [ebp+NTFS.cur_index_size]
  1442.         mov     [ebp+NTFS.cur_size], eax
  1443.         mov     eax, [ebp+NTFS.cur_index_buf]
  1444.         mov     [ebp+NTFS.cur_buf], eax
  1445.         call    ntfs_read_attr.newAttribute
  1446.         jc      ntfsFail
  1447.         cmp     [ebp+NTFS.cur_read], 0x20
  1448.         jc      ntfsFail
  1449.         mov     esi, [ebp+NTFS.cur_index_buf]
  1450.         mov     eax, [esi+indexRecordSize]
  1451.         shr     eax, 9
  1452.         cmp     [ebp+NTFS.cur_index_size], eax
  1453.         jc      .realloc
  1454.         mov     [ebp+NTFS.cur_subnode_size], eax
  1455.         add     esi, rootNode
  1456.         mov     eax, [esi+nodeRealSize]
  1457.         add     eax, rootNode
  1458.         cmp     [ebp+NTFS.cur_read], eax
  1459.         jc      ntfsFail
  1460.         mov     edi, [ebx+16]
  1461.         mov     ecx, [ebx+12]
  1462.         pushd   [ebx]
  1463.         pushd   [ebx+8]     ; read ANSI/UNICODE name
  1464.         push    edi
  1465.         mov     edx, esp
  1466.         mov     ebx, [ebx+4]
  1467. ; init header
  1468.         xor     eax, eax
  1469.         mov     [edi+8], eax
  1470.         mov     [edi+4], eax
  1471.         inc     eax
  1472.         mov     [edi], eax      ; version
  1473.         add     edi, 32
  1474. ; edi -> BDFE, esi -> current index data, ebx = first wanted block,
  1475. ; ecx = number of blocks to read
  1476. ; edx -> parameters block: dd <output>, dd <flags>
  1477.         cmp     [ebp+NTFS.cur_iRecord], 5
  1478.         jz      .skip_specials
  1479. ; dot and dotdot entries
  1480.         push    esi
  1481.         xor     esi, esi
  1482.         call    .add_special_entry
  1483.         inc     esi
  1484.         call    .add_special_entry
  1485.         pop     esi
  1486. .skip_specials:
  1487. ; at first, dump index root
  1488.         add     esi, [esi+indexOffset]
  1489. .dump_root:
  1490.         test    byte [esi+indexFlags], 2
  1491.         jnz     .dump_root_done
  1492.         call    .add_entry
  1493.         movzx   eax, word [esi+indexAllocatedSize]
  1494.         add     esi, eax
  1495.         jmp     .dump_root
  1496.  
  1497. .realloc:
  1498.         mov     edi, eax
  1499.         mov     eax, [esi+indexRecordSize]
  1500.         shl     eax, 1
  1501.         stdcall kernel_alloc, eax
  1502.         test    eax, eax
  1503.         jz      ntfsFail
  1504.         mov     edx, [ebp+NTFS.cur_index_buf]
  1505.         cmp     edx, [ebp+NTFS.secondIndexBuffer]
  1506.         jc      @f
  1507.         mov     edx, [ebp+NTFS.secondIndexBuffer]
  1508. @@:
  1509.         mov     [ebp+NTFS.cur_index_buf], eax
  1510.         add     eax, [esi+indexRecordSize]
  1511.         mov     [ebp+NTFS.secondIndexBuffer], eax
  1512.         mov     [ebp+NTFS.cur_index_size], edi
  1513.         stdcall kernel_free, edx
  1514.         jmp     .doit
  1515.  
  1516. .dump_root_done:
  1517. ; now dump all subnodes
  1518.         push    ecx edi
  1519.         lea     edi, [ebp+NTFS.bitmap_buf]
  1520.         mov     [ebp+NTFS.cur_buf], edi
  1521.         mov     ecx, 0x400/4
  1522.         xor     eax, eax
  1523.         rep stosd
  1524.         mov     [ebp+NTFS.cur_attr], 0xB0   ; $BITMAP
  1525.         and     [ebp+NTFS.cur_offs], 0
  1526.         mov     [ebp+NTFS.cur_size], 2
  1527.         call    ntfs_read_attr.newAttribute
  1528.         pop     edi ecx
  1529.         push    0       ; save offset in $BITMAP attribute
  1530.         and     [ebp+NTFS.cur_offs], 0
  1531. .dumploop:
  1532.         mov     [ebp+NTFS.cur_attr], 0xA0
  1533.         mov     eax, [ebp+NTFS.cur_subnode_size]
  1534.         mov     [ebp+NTFS.cur_size], eax
  1535.         mov     esi, [ebp+NTFS.cur_index_buf]
  1536.         mov     [ebp+NTFS.cur_buf], esi
  1537.         mov     eax, [ebp+NTFS.cur_offs]
  1538.         push    eax
  1539.         imul    eax, [ebp+NTFS.cur_subnode_size]
  1540.         mov     [ebp+NTFS.cur_offs], eax
  1541.         call    ntfs_read_attr.newAttribute
  1542.         pop     [ebp+NTFS.cur_offs]
  1543.         mov     eax, [ebp+NTFS.cur_subnode_size]
  1544.         shl     eax, 9
  1545.         cmp     [ebp+NTFS.cur_read], eax
  1546.         jnz     .done
  1547.         push    eax
  1548.         mov     eax, [ebp+NTFS.cur_offs]
  1549.         and     eax, 0x400*8-1
  1550.         bt      dword [ebp+NTFS.bitmap_buf], eax
  1551.         pop     eax
  1552.         jnc     .dump_subnode_done
  1553.         cmp     dword [esi], 'INDX'
  1554.         jnz     .dump_subnode_done
  1555.         push    ebx
  1556.         mov     ebx, esi
  1557.         call    ntfs_restore_usa
  1558.         pop     ebx
  1559.         jc      .dump_subnode_done
  1560.         add     esi, recordNode
  1561.         add     esi, [esi+indexOffset]
  1562. .dump_subnode:
  1563.         test    byte [esi+indexFlags], 2
  1564.         jnz     .dump_subnode_done
  1565.         call    .add_entry
  1566.         movzx   eax, word [esi+indexAllocatedSize]
  1567.         add     esi, eax
  1568.         jmp     .dump_subnode
  1569.  
  1570. .dump_subnode_done:
  1571.         inc     [ebp+NTFS.cur_offs]
  1572.         test    [ebp+NTFS.cur_offs], 0x400*8-1
  1573.         jnz     .dumploop
  1574.         mov     [ebp+NTFS.cur_attr], 0xB0
  1575.         push    ecx edi
  1576.         lea     edi, [ebp+NTFS.bitmap_buf]
  1577.         mov     [ebp+NTFS.cur_buf], edi
  1578.         mov     ecx, 0x400/4
  1579.         xor     eax, eax
  1580.         rep stosd
  1581.         pop     edi ecx
  1582.         pop     eax
  1583.         push    [ebp+NTFS.cur_offs]
  1584.         inc     eax
  1585.         mov     [ebp+NTFS.cur_offs], eax
  1586.         mov     [ebp+NTFS.cur_size], 2
  1587.         push    eax
  1588.         call    ntfs_read_attr.newAttribute
  1589.         pop     eax
  1590.         pop     [ebp+NTFS.cur_offs]
  1591.         push    eax
  1592.         jmp     .dumploop
  1593.  
  1594. .done:
  1595.         pop     eax
  1596.         pop     eax
  1597.         mov     ebx, [eax+4]
  1598.         pop     eax
  1599.         pop     eax
  1600.         test    eax, eax
  1601.         jz      .ret
  1602.         xor     eax, eax
  1603.         dec     ecx
  1604.         js      @f
  1605.         mov     al, ERROR_END_OF_FILE
  1606. @@:
  1607.         push    eax
  1608.         call    ntfs_unlock
  1609.         pop     eax
  1610.         ret
  1611.  
  1612. .add_special_entry:
  1613.         mov     eax, [edx]
  1614.         inc     dword [eax+8]   ; new file found
  1615.         dec     ebx
  1616.         jns     .ret
  1617.         dec     ecx
  1618.         js      .ret
  1619.         inc     dword [eax+4]   ; new file block copied
  1620.         mov     eax, [edx+4]
  1621.         mov     [edi+4], eax
  1622.         mov     eax, 0x10
  1623.         stosd
  1624.         scasd
  1625.         push    ebx ecx edx
  1626.         mov     eax, dword [ebp+NTFS.bitmap_buf]
  1627.         mov     edx, dword [ebp+NTFS.bitmap_buf+4]
  1628.         call    ntfs_datetime_to_bdfe
  1629.         mov     eax, dword [ebp+NTFS.bitmap_buf+0x18]
  1630.         mov     edx, dword [ebp+NTFS.bitmap_buf+0x1C]
  1631.         call    ntfs_datetime_to_bdfe
  1632.         mov     eax, dword [ebp+NTFS.bitmap_buf+8]
  1633.         mov     edx, dword [ebp+NTFS.bitmap_buf+0xC]
  1634.         call    ntfs_datetime_to_bdfe
  1635.         pop     edx ecx ebx
  1636.         xor     eax, eax
  1637.         stosd
  1638.         stosd
  1639.         mov     al, '.'
  1640.         push    edi ecx
  1641.         lea     ecx, [esi+1]
  1642.         cmp     dword[edi-36], 2
  1643.         jz      .utf16sp
  1644.         rep stosb
  1645.         mov     byte [edi], 0
  1646.         pop     ecx edi
  1647.         cmp     dword[edi-36], 3
  1648.         jz      @f
  1649.         add     edi, 264
  1650.         ret
  1651.  
  1652. .utf16sp:
  1653.         rep stosw
  1654.         mov     word [edi], 0
  1655.         pop     ecx edi
  1656. @@:
  1657.         add     edi, 520
  1658. .ret:
  1659.         ret
  1660.  
  1661. .add_entry:
  1662. ; do not return DOS 8.3 names
  1663.         cmp     byte [esi+namespace], 2
  1664.         jz      .ret
  1665. ; do not return system files
  1666.         cmp     dword[esi+fileRecordReference], 16
  1667.         jb      .ret
  1668.         cmp     byte [esi+fileNameLength], 0
  1669.         jz      .ret
  1670.         mov     eax, [edx]
  1671.         inc     dword [eax+8]   ; new file found
  1672.         dec     ebx
  1673.         jns     .ret
  1674.         dec     ecx
  1675.         js      .ret
  1676.         inc     dword [eax+4]   ; new file block copied
  1677.         mov     eax, [edx+4]    ; flags
  1678.         call    ntfs_direntry_to_bdfe
  1679.         push    ecx esi edi
  1680.         movzx   ecx, byte [esi+fileNameLength]
  1681.         add     esi, fileName
  1682.         cmp     dword[edi-36], 2
  1683.         jz      .utf16
  1684.         cmp     dword[edi-36], 3
  1685.         jz      .utf8
  1686. @@:
  1687.         lodsw
  1688.         call    uni2ansi_char
  1689.         stosb
  1690.         loop    @b
  1691.         mov     byte [edi], 0
  1692.         pop     edi esi ecx
  1693.         add     edi, 264
  1694.         ret
  1695.  
  1696. .utf8:
  1697.         push    ecx
  1698.         mov     cx, 519
  1699. @@:
  1700.         lodsw
  1701.         call    UTF16to8
  1702.         js      @f
  1703.         dec     dword[esp]
  1704.         jnz     @b
  1705. @@:
  1706.         mov     byte [edi], 0
  1707.         pop     edi
  1708. @@:
  1709.         pop     edi esi ecx
  1710.         add     edi, 520
  1711.         ret
  1712.  
  1713. .utf16:
  1714.         rep movsw
  1715.         mov     word [edi], 0
  1716.         jmp     @b
  1717.  
  1718. ntfs_direntry_to_bdfe:
  1719.         mov     [edi+4], eax    ; ANSI/UNICODE name
  1720.         mov     eax, [esi+fileFlags]
  1721.         test    eax, 0x10000000
  1722.         jz      @f
  1723.         and     eax, not 0x10000000
  1724.         or      al, 0x10
  1725. @@:
  1726.         stosd
  1727.         scasd
  1728.         push    ebx ecx edx
  1729.         mov     eax, [esi+fileCreated]
  1730.         mov     edx, [esi+fileCreated+4]
  1731.         call    ntfs_datetime_to_bdfe
  1732.         mov     eax, [esi+fileAccessed]
  1733.         mov     edx, [esi+fileAccessed+4]
  1734.         call    ntfs_datetime_to_bdfe
  1735.         mov     eax, [esi+fileModified]
  1736.         mov     edx, [esi+fileModified+4]
  1737.         call    ntfs_datetime_to_bdfe
  1738.         pop     edx ecx ebx
  1739.         mov     eax, [esi+fileRealSize]
  1740.         stosd
  1741.         mov     eax, [esi+fileRealSize+4]
  1742.         stosd
  1743.         ret
  1744.  
  1745. ntfs_datetime_to_bdfe:
  1746. ; in: edx:eax = seconds since 01.01.1601 x10000000
  1747. ; edi -> data block
  1748. ; out: edi = edi+8
  1749.         sub     eax, 3365781504
  1750.         sbb     edx, 29389701
  1751.         mov     ecx, 10000000
  1752.         cmp     edx, ecx
  1753.         jc      @f
  1754.         xor     edx, edx
  1755. @@:
  1756.         div     ecx
  1757.         jmp     fsTime2bdfe
  1758.  
  1759. ;----------------------------------------------------------------
  1760. ntfs_GetFileInfo:
  1761.         mov     edi, [ebx+16]
  1762.         cmp     byte [esi], 0
  1763.         jz      .volume
  1764.         call    ntfs_lock
  1765.         call    ntfs_find_lfn
  1766.         jnc     .found
  1767.         test    eax, eax
  1768.         jz      ntfsFail
  1769.         jmp     ntfsNotFound
  1770.  
  1771. .found:
  1772.         mov     esi, eax
  1773.         xor     eax, eax
  1774.         call    ntfs_direntry_to_bdfe
  1775. .end:
  1776.         call    ntfs_unlock
  1777.         xor     eax, eax
  1778. @@:
  1779.         ret
  1780.  
  1781. .volume:
  1782.         mov     eax, dword [ebp+NTFS.Length]
  1783.         mov     edx, dword [ebp+NTFS.Length+4]
  1784.         shld    edx, eax, 9
  1785.         shl     eax, 9
  1786.         mov     [edi+36], edx
  1787.         mov     [edi+32], eax
  1788.         mov     eax, [ebx+8]
  1789.         mov     byte [edi], 8
  1790.         mov     [edi+4], eax
  1791.         test    eax, eax
  1792.         jz      @b
  1793.         call    ntfs_lock
  1794.         add     edi, 40
  1795.         mov     [ebp+NTFS.cur_buf], edi
  1796.         mov     [ebp+NTFS.cur_iRecord], 3
  1797.         mov     [ebp+NTFS.cur_attr], 0x60
  1798.         mov     [ebp+NTFS.cur_offs], 0
  1799.         mov     [ebp+NTFS.cur_size], 1
  1800.         call    ntfs_read_attr
  1801.         jc      ntfsFail
  1802.         mov     ecx, [ebp+NTFS.cur_read]
  1803.         mov     [edi+ecx], ax
  1804.         cmp     byte [ebx+8], 2
  1805.         jz      .end
  1806.         shr     ecx, 1
  1807.         jz      .end
  1808.         mov     esi, edi
  1809.         cmp     byte [ebx+8], 3
  1810.         jnz     @f
  1811.         shl     ecx, 1
  1812.         call    UTF16to8_string
  1813.         mov     byte [edi], 0
  1814.         jmp     .end
  1815.  
  1816. @@:
  1817.         lodsw
  1818.         call    uni2ansi_char
  1819.         stosb
  1820.         loop    @b
  1821.         mov     byte [edi], 0
  1822.         jmp     .end
  1823.  
  1824. ;----------------------------------------------------------------
  1825. ntfs_CreateFolder:
  1826.         mov     [ebp+NTFS.bFolder], 1
  1827.         jmp     @f
  1828.  
  1829. ntfs_CreateFile:
  1830.         mov     [ebp+NTFS.bFolder], 0
  1831. @@: ; 1. Search file
  1832.         call    ntfs_lock
  1833.         call    ntfs_find_lfn
  1834.         jc      .notFound
  1835. ; found, rewrite
  1836.         cmp     [ebp+NTFS.cur_iRecord], 16
  1837.         jc      ntfsDenied
  1838.         cmp     [ebp+NTFS.bFolder], 1
  1839.         jz      .folder
  1840.         test    byte [eax+fileFlags], 1
  1841.         jnz     ntfsDenied
  1842.         cmp     [ebp+NTFS.fragmentCount], 1
  1843.         jnz     ntfsUnsupported     ; record fragmented
  1844. ; edit directory node
  1845.         mov     edi, [ebp+NTFS.cur_index_buf]
  1846.         cmp     dword [edi], 'INDX'
  1847.         jz      @f
  1848.         mov     esi, [ebp+NTFS.frs_buffer]
  1849.         mov     ecx, [esi+recordRealSize]
  1850.         shr     ecx, 2
  1851.         rep movsd
  1852.         mov     esi, [ebp+NTFS.attr_offs]
  1853.         mov     cl, [esi+attributeOffset]
  1854.         sub     esi, [ebp+NTFS.frs_buffer]
  1855.         add     eax, ecx
  1856.         add     eax, esi
  1857. @@:
  1858.         mov     edi, eax
  1859.         mov     eax, [ebx+12]
  1860.         mov     [edi+fileRealSize], eax
  1861.         mov     dword [edi+fileRealSize+4], 0
  1862.         push    ebx eax
  1863.         call    ntfsGetTime
  1864.         mov     [edi+fileModified], eax
  1865.         mov     [edi+fileModified+4], edx
  1866.         mov     [edi+recordModified], eax
  1867.         mov     [edi+recordModified+4], edx
  1868.         mov     [edi+fileAccessed], eax
  1869.         mov     [edi+fileAccessed+4], edx
  1870.         pop     edx ebx
  1871.         mov     eax, [ebp+NTFS.LastRead]
  1872.         mov     [ebp+NTFS.nodeLastRead], eax
  1873.         mov     [ebp+NTFS.cur_attr], 0x80
  1874.         mov     [ebp+NTFS.cur_offs], 0
  1875.         mov     [ebp+NTFS.cur_size], 0
  1876.         call    ntfs_read_attr
  1877.         jc      ntfsFail
  1878.         mov     esi, edi
  1879.         mov     edi, [ebp+NTFS.frs_buffer]
  1880.         cmp     word [edi+baseRecordReuse], 0
  1881.         jnz     ntfsUnsupported     ; auxiliary record
  1882.         mov     al, [edi+attributeOffset]
  1883.         add     edi, eax
  1884.         mov     al, [edi+attributeOffset]
  1885.         add     edi, eax
  1886.         mov     ecx, 6
  1887.         add     esi, fileModified
  1888.         add     edi, 8
  1889.         rep movsd
  1890.         mov     eax, edx
  1891.         xor     edx, edx
  1892.         mov     ecx, [ebp+NTFS.attr_offs]
  1893.         cmp     word [ecx+attributeFlags], 0
  1894.         jnz     ntfsUnsupported
  1895.         push    ebx
  1896.         cmp     byte [ecx+nonResidentFlag], 0
  1897.         jz      @f
  1898.         cmp     [ecx+attributeRealSize+4], edx
  1899.         jnz     @f
  1900.         cmp     [ecx+attributeRealSize], eax
  1901.         jz      ntfs_WriteFile.writeNode
  1902. @@:
  1903.         jmp     ntfs_WriteFile.resizeAttribute
  1904.  
  1905. .folder:
  1906.         bt      dword [eax+fileFlags], 28
  1907.         jnc     ntfsDenied
  1908.         push    0
  1909.         jmp     ntfsOut
  1910.  
  1911. .notFound:  ; create
  1912.         test    eax, eax
  1913.         jz      ntfsFail
  1914.         cmp     [ebp+NTFS.fragmentCount], 1
  1915.         jnz     ntfsUnsupported     ; record fragmented
  1916. ; 2. Prepare directory record
  1917.         mov     edi, esi
  1918.         mov     edx, eax
  1919.         xor     ecx, ecx
  1920. @@:         ; count characters
  1921.         call    utf8to16
  1922.         cmp     ax, '/'
  1923.         jz      ntfsNotFound    ; path folder not found
  1924.         inc     ecx
  1925.         test    ax, ax
  1926.         jnz     @b
  1927.         dec     ecx
  1928.         push    ecx     ; name length in chars
  1929.         push    edi
  1930.         shl     ecx, 1
  1931.         add     ecx, fileName+7
  1932.         and     ecx, not 7
  1933.         mov     edi, [ebp+NTFS.cur_index_buf]
  1934.         mov     eax, [ebx+12]
  1935.         mov     [ebp+NTFS.fileRealSize], eax
  1936.         mov     eax, [ebx+16]
  1937.         mov     [ebp+NTFS.fileDataBuffer], eax
  1938.         push    ecx     ; index length
  1939.         mov     eax, edx
  1940.         mov     edx, ecx
  1941.         cmp     dword [edi], 'INDX'
  1942.         jz      .indexRecord
  1943.         mov     esi, [ebp+NTFS.frs_buffer]  ; indexRoot
  1944.         mov     ecx, [esi+recordRealSize]
  1945.         add     edx, ecx
  1946.         cmp     [esi+recordAllocatedSize], edx
  1947.         jc      .growTree
  1948.         mov     [esi+recordRealSize], edx
  1949.         shr     ecx, 2
  1950.         rep movsd
  1951.         mov     edi, [ebp+NTFS.indexRoot]
  1952.         sub     edi, [ebp+NTFS.frs_buffer]
  1953.         add     edi, [ebp+NTFS.cur_index_buf]
  1954.         mov     esi, [esp]
  1955.         add     [edi+sizeWithHeader], esi
  1956.         add     [edi+sizeWithoutHeader], esi
  1957.         mov     cl, [edi+attributeOffset]
  1958.         add     edi, ecx
  1959.         add     [edi+rootNode+nodeRealSize], esi
  1960.         add     [edi+rootNode+nodeAllocatedSize], esi
  1961.         sub     eax, [ebp+NTFS.cur_index_buf]
  1962.         add     eax, edi
  1963.         mov     edi, [ebp+NTFS.cur_index_buf]
  1964.         jmp     .common
  1965.  
  1966. .growTree:  ; create indexRecord
  1967.         mov     edi, [ebp+NTFS.cur_index_buf]
  1968.         mov     ecx, 10
  1969.         xor     eax, eax
  1970.         rep stosd
  1971.         mov     esi, [ebp+NTFS.indexRoot]
  1972.         mov     al, [esi+attributeOffset]
  1973.         add     esi, eax
  1974.         rdtsc
  1975.         stosw
  1976.         mov     eax, [esi+indexRecordSize]
  1977.         cmp     eax, [ebp+NTFS.frs_size]
  1978.         jc      .errorPop3
  1979.         shr     eax, 9
  1980.         inc     eax
  1981.         mov     edi, [ebp+NTFS.cur_index_buf]
  1982.         mov     dword[edi], 'INDX'
  1983.         mov     byte [edi+updateSequenceOffset], 28h
  1984.         mov     [edi+updateSequenceSize], al
  1985.         add     edi, recordNode
  1986.         shl     eax, 1
  1987.         add     eax, 28h-recordNode+7
  1988.         and     eax, not 7
  1989.         mov     [edi+indexOffset], eax
  1990.         mov     ecx, [esi+indexRecordSize]
  1991.         sub     ecx, recordNode
  1992.         mov     [edi+nodeAllocatedSize], ecx
  1993.         add     esi, rootNode
  1994.         push    esi
  1995.         mov     ecx, [esi+nodeRealSize]
  1996.         sub     ecx, [esi+indexOffset]
  1997.         add     eax, ecx
  1998.         mov     [edi+nodeRealSize], eax
  1999.         mov     eax, [esi+nonLeafFlag]
  2000.         mov     [edi+nonLeafFlag], eax
  2001.         shr     ecx, 2
  2002.         add     esi, [esi+indexOffset]
  2003.         add     edi, [edi+indexOffset]
  2004.         rep movsd       ; copy root indexes
  2005. ; clear root node
  2006.         mov     cl, 10
  2007.         mov     edi, [esp]
  2008.         xor     eax, eax
  2009.         rep stosd
  2010.         pop     edi
  2011.         mov     byte [edi+indexOffset], 16
  2012.         mov     byte [edi+nodeRealSize], 28h
  2013.         mov     byte [edi+nodeAllocatedSize], 28h
  2014.         mov     byte [edi+nonLeafFlag], 1
  2015.         mov     byte [edi+16+indexAllocatedSize], 18h
  2016.         mov     byte [edi+16+indexFlags], 3
  2017.         mov     esi, [ebp+NTFS.indexRoot]
  2018.         add     edi, 28h
  2019.         mov     eax, edi
  2020.         sub     eax, esi
  2021.         mov     word [esi+sizeWithoutHeader], 38h
  2022.         xchg    [esi+sizeWithHeader], eax
  2023.         add     esi, eax
  2024.         mov     [ebp+NTFS.attr_offs], edi
  2025.         cmp     byte [esi], 0xA0
  2026.         jnz     @f
  2027.         cmp     dword [esi+attributeAllocatedSize], 0
  2028.         jz      @f
  2029.         mov     eax, [ebp+NTFS.frs_buffer]
  2030.         mov     ecx, eax
  2031.         add     ecx, [eax+recordRealSize]
  2032.         sub     ecx, esi
  2033.         shr     ecx, 2
  2034.         rep movsd
  2035.         sub     edi, eax
  2036.         mov     [eax+recordRealSize], edi
  2037.         call    .ntfsNodeAlloc
  2038.         jc      ntfsErrorPop3
  2039.         mov     eax, [ebp+NTFS.newRecord]
  2040.         mov     edi, [ebp+NTFS.cur_index_buf]
  2041.         mov     [edi+recordVCN], eax
  2042.         mov     edi, [ebp+NTFS.attr_offs]
  2043.         mov     [edi-8], eax
  2044.         jmp     .refresh
  2045.  
  2046. @@:
  2047.         mov     cl, 32
  2048.         xor     eax, eax
  2049.         rep stosd
  2050.         mov     eax, [ebp+NTFS.cur_subnode_size]
  2051.         cmp     eax, [ebp+NTFS.cur_size]
  2052.         jnz     @f
  2053.         cmp     [ebp+NTFS.sectors_per_cluster], 1
  2054.         jz      @f
  2055.         mov     al, 1
  2056. @@:
  2057.         mov     [ebp+NTFS.fileDataSize], eax
  2058.         mov     edi, [ebp+NTFS.BitmapStart]
  2059.         call    ntfsSpaceAlloc
  2060.         movi    eax, ERROR_DISK_FULL
  2061.         jc      ntfsErrorPop3
  2062. ; create $IndexAllocation
  2063.         mov     edi, [ebp+NTFS.attr_offs]
  2064.         mov     byte [edi+attributeType], 0xA0
  2065.         mov     byte [edi+nonResidentFlag], 1
  2066.         mov     byte [edi+nameLength], 4
  2067.         mov     byte [edi+nameOffset], 40h
  2068.         mov     byte [edi+dataRunsOffset], 48h
  2069.         mov     byte [edi+sizeWithHeader], 50h
  2070.         mov     eax, [ebp+NTFS.fileDataSize]
  2071.         dec     eax
  2072.         mov     [edi+lastVCN], eax
  2073.         inc     eax
  2074.         mul     [ebp+NTFS.sectors_per_cluster]
  2075.         shl     eax, 9
  2076.         mov     [edi+attributeAllocatedSize], eax
  2077.         mov     [edi+attributeRealSize], eax
  2078.         mov     [edi+initialDataSize], eax
  2079.         mov     dword[edi+40h], 490024h     ; unicode $I30
  2080.         mov     dword[edi+40h+4], 300033h
  2081.         push    edi
  2082.         mov     esi, edi
  2083.         add     edi, 48h
  2084.         call    createMcbEntry
  2085.         mov     esi, [ebp+NTFS.frs_buffer]
  2086.         pop     edi
  2087.         mov     al, [esi+newAttributeID]
  2088.         mov     [edi+attributeID], al
  2089.         add     edi, 50h
  2090.         inc     eax
  2091. ; create $Bitmap
  2092.         mov     [edi+attributeID], al
  2093.         inc     eax
  2094.         mov     [esi+newAttributeID], al
  2095.         mov     byte [edi+attributeType], 0xB0
  2096.         mov     byte [edi+nameLength], 4
  2097.         mov     byte [edi+nameOffset], 18h
  2098.         mov     byte [edi+attributeOffset], 20h
  2099.         mov     byte [edi+sizeWithoutHeader], 8
  2100.         mov     byte [edi+sizeWithHeader], 28h
  2101.         mov     dword[edi+18h], 490024h     ; unicode $I30
  2102.         mov     dword[edi+18h+4], 300033h
  2103.         mov     byte [edi+20h], 1
  2104.         mov     dword[edi+28h], -1
  2105.         add     edi, 30h
  2106.         sub     edi, esi
  2107.         mov     [esi+recordRealSize], edi
  2108.         mov     eax, [ebp+NTFS.fileDataStart]
  2109.         mul     [ebp+NTFS.sectors_per_cluster]
  2110.         mov     edx, eax
  2111.         jmp     @f
  2112.  
  2113. .refresh:
  2114.         mov     [ebp+NTFS.cur_size], 0
  2115.         call    ntfs_read_attr.continue
  2116.         movi    eax, ERROR_FS_FAIL
  2117.         jc      ntfsErrorPop3
  2118.         mov     edx, [ebp+NTFS.LastRead]
  2119. @@:
  2120.         mov     ebx, [ebp+NTFS.cur_index_buf]
  2121.         call    writeRecord
  2122.         mov     ebx, [ebp+NTFS.frs_buffer]
  2123.         mov     edx, [ebp+NTFS.rootLastRead]
  2124.         call    writeRecord
  2125.         mov     esi, [esp+4]
  2126.         call    ntfs_find_lfn.doit2
  2127.         test    eax, eax
  2128.         jz      .errorPop3
  2129.         mov     edi, [ebp+NTFS.cur_index_buf]
  2130.         mov     edx, [esp]
  2131. .indexRecord:
  2132.         add     edi, recordNode
  2133.         add     edx, [edi+nodeRealSize]
  2134.         cmp     [edi+nodeAllocatedSize], edx
  2135.         jc      .arborizeTree
  2136.         mov     [edi+nodeRealSize], edx
  2137.         jmp     .common
  2138.  
  2139. .errorPop3:
  2140.         add     esp, 12
  2141.         jmp     ntfsUnsupported
  2142.  
  2143. .ntfsNodeAlloc:
  2144. ; in: [ebp+NTFS.attr_offs] -> $IndexAllocation
  2145. ;   out:
  2146. ; [ebp+NTFS.newRecord] = node VCN
  2147. ; [ebp+NTFS.cur_offs]
  2148. ; CF=1 -> eax = error code
  2149.         mov     esi, [ebp+NTFS.attr_offs]
  2150.         add     esi, [esi+sizeWithHeader]
  2151.         cmp     byte [esi], 0xB0
  2152.         jnz     .ret
  2153.         movzx   ecx, word [esi+sizeWithoutHeader]
  2154.         shr     ecx, 2
  2155.         movzx   edi, byte [esi+attributeOffset]
  2156.         add     edi, esi
  2157.         mov     edx, edi
  2158.         or      eax, -1
  2159.         repz scasd
  2160.         jnz     @f
  2161.         cmp     [edi], eax
  2162.         jnz     .ret
  2163. ; extend folder $Bitmap
  2164.         add     word [esi+sizeWithHeader], 8
  2165.         add     word [esi+sizeWithoutHeader], 8
  2166.         mov     esi, [ebp+NTFS.frs_buffer]
  2167.         mov     eax, [esi+recordRealSize]
  2168.         add     eax, 8
  2169.         cmp     [esi+recordAllocatedSize], eax
  2170.         jc      .ret
  2171.         mov     [esi+recordRealSize], eax
  2172.         xor     eax, eax
  2173.         stosd
  2174.         mov     [edi], eax
  2175.         mov     [edi+8], eax
  2176.         dec     eax
  2177.         mov     [edi+4], eax
  2178. @@:
  2179.         sub     edi, 4
  2180.         mov     eax, [edi]
  2181.         not     eax
  2182.         bsf     eax, eax
  2183.         bts     [edi], eax
  2184.         sub     edi, edx
  2185.         shl     edi, 3
  2186.         add     eax, edi
  2187.         mul     [ebp+NTFS.cur_subnode_size]
  2188.         mov     [ebp+NTFS.newRecord], eax
  2189.         mov     ecx, [ebp+NTFS.cur_size]
  2190.         cmp     ecx, [ebp+NTFS.cur_subnode_size]
  2191.         jz      @f
  2192.         mul     [ebp+NTFS.sectors_per_cluster]
  2193. @@:
  2194.         mov     [ebp+NTFS.cur_offs], eax
  2195.         add     eax, ecx
  2196.         shl     eax, 9
  2197.         mov     esi, [ebp+NTFS.attr_offs]
  2198.         cmp     [esi+attributeAllocatedSize], eax
  2199.         jnc     @f
  2200.         xor     edx, edx
  2201.         jmp     resizeAttribute
  2202.  
  2203. .ret:
  2204.         movi    eax, ERROR_UNSUPPORTED_FS
  2205.         stc
  2206. @@:
  2207.         ret
  2208.  
  2209. .arborizeTree:      ; find median index
  2210.         mov     ecx, [edi+nodeRealSize]
  2211.         sub     ecx, [edi+indexOffset]
  2212.         shr     ecx, 1
  2213.         add     edi, [edi+indexOffset]
  2214.         xor     eax, eax
  2215. @@:
  2216.         add     edi, eax
  2217.         mov     ax, [edi+indexAllocatedSize]
  2218.         sub     ecx, eax
  2219.         jnc     @b
  2220.         add     eax, 8
  2221.         mov     esi, [ebp+NTFS.secondIndexBuffer]
  2222.         cmp     dword [esi], 'INDX'
  2223.         jz      @f
  2224. ; move index to the root node
  2225.         mov     esi, [ebp+NTFS.frs_buffer]
  2226.         mov     ecx, eax
  2227.         add     ecx, 8
  2228.         add     ecx, [esi+recordRealSize]
  2229.         cmp     [esi+recordAllocatedSize], ecx
  2230.         jc      .growTree
  2231.         push    edi eax
  2232.         call    .ntfsNodeAlloc
  2233.         jc      ntfsErrorPop5
  2234.         pop     eax
  2235.         mov     edi, [ebp+NTFS.indexRoot]
  2236.         add     [ebp+NTFS.attr_offs], eax
  2237.         add     [edi+sizeWithHeader], eax
  2238.         add     [edi+sizeWithoutHeader], eax
  2239.         movzx   ecx, byte [edi+attributeOffset]
  2240.         add     ecx, edi
  2241.         add     [ecx+rootNode+nodeRealSize], eax
  2242.         add     [ecx+rootNode+nodeAllocatedSize], eax
  2243.         add     ecx, [ebp+NTFS.indexPointer]
  2244.         sub     ecx, [ebp+NTFS.secondIndexBuffer]
  2245.         mov     esi, [ebp+NTFS.frs_buffer]
  2246.         add     [esi+recordRealSize], eax
  2247.         add     esi, [esi+recordRealSize]
  2248.         mov     edi, esi
  2249.         sub     esi, eax
  2250.         neg     ecx
  2251.         add     ecx, esi
  2252.         shr     ecx, 2
  2253.         sub     esi, 4
  2254.         sub     edi, 4
  2255.         std
  2256.         rep movsd   ; make space
  2257.         mov     [edi], ecx
  2258.         mov     edi, esi
  2259.         add     edi, 4
  2260.         mov     esi, [esp]
  2261.         add     word [esi+indexAllocatedSize], 8
  2262.         mov     byte [esi+indexFlags], 1
  2263.         mov     ecx, eax
  2264.         sub     ecx, 8
  2265.         shr     ecx, 2
  2266.         cld
  2267.         rep movsd   ; insert index
  2268.         mov     eax, [ebp+NTFS.newRecord]
  2269.         stosd
  2270.         jmp     .splitNode
  2271.  
  2272. .growBranch:    ; move node and replace it with empty one
  2273.         mov     esi, [ebp+NTFS.cur_index_buf]
  2274.         mov     edi, [ebp+NTFS.secondIndexBuffer]
  2275.         mov     eax, [esi+recordVCN]
  2276.         mov     [edi+recordVCN], eax
  2277.         add     edi, recordNode
  2278.         mov     eax, [edi+indexOffset]
  2279.         add     eax, 18h
  2280.         mov     [edi+nodeRealSize], eax
  2281.         add     edi, [edi+indexOffset]
  2282.         mov     ecx, 6
  2283.         xor     eax, eax
  2284.         mov     [ebp+NTFS.indexPointer], edi
  2285.         push    edi
  2286.         rep stosd
  2287.         pop     edi
  2288.         mov     eax, [ebp+NTFS.newRecord]
  2289.         mov     byte [edi+indexAllocatedSize], 18h
  2290.         mov     byte [edi+indexFlags], 3
  2291.         mov     [edi+16], eax
  2292.         mov     [esi+recordVCN], eax
  2293.         mov     eax, [ebp+NTFS.LastRead]
  2294.         mov     [ebp+NTFS.nodeLastRead], eax
  2295.         push    [ebp+NTFS.cur_size]
  2296.         mov     [ebp+NTFS.cur_size], 0
  2297.         call    ntfs_read_attr.continue
  2298.         pop     [ebp+NTFS.cur_size]
  2299.         movi    eax, ERROR_FS_FAIL
  2300.         jc      ntfsErrorPop5
  2301.         pop     eax edi
  2302. @@:         ; move index to the branch node
  2303.         push    edi eax
  2304.         call    .ntfsNodeAlloc
  2305.         jc      ntfsErrorPop5
  2306.         mov     eax, [esp]
  2307.         mov     esi, [ebp+NTFS.secondIndexBuffer]
  2308.         add     esi, recordNode
  2309.         mov     ecx, [esi+nodeRealSize]
  2310.         add     eax, ecx
  2311.         cmp     [esi+nodeAllocatedSize], eax
  2312.         jc      .growBranch
  2313.         mov     [esi+nodeRealSize], eax
  2314.         lea     edi, [esi+eax-4]
  2315.         add     esi, ecx
  2316.         mov     ecx, esi
  2317.         sub     ecx, [ebp+NTFS.indexPointer]
  2318.         shr     ecx, 2
  2319.         sub     esi, 4
  2320.         std
  2321.         rep movsd   ; make space
  2322.         mov     [edi], ecx
  2323.         pop     ecx
  2324.         sub     ecx, 8
  2325.         shr     ecx, 2
  2326.         mov     edi, esi
  2327.         add     edi, 4
  2328.         mov     esi, [esp]
  2329.         add     word [esi+indexAllocatedSize], 8
  2330.         mov     byte [esi+indexFlags], 1
  2331.         cld
  2332.         rep movsd   ; insert index
  2333.         mov     eax, [ebp+NTFS.newRecord]
  2334.         stosd
  2335.         mov     ebx, [ebp+NTFS.secondIndexBuffer]
  2336.         mov     edx, [ebp+NTFS.nodeLastRead]
  2337.         push    esi
  2338.         call    writeRecord
  2339.         pop     esi
  2340. .splitNode:
  2341.         mov     edi, [ebp+NTFS.cur_index_buf]
  2342.         mov     eax, edi
  2343.         add     eax, recordNode
  2344.         add     eax, [edi+recordNode+nodeRealSize]
  2345.         sub     eax, esi
  2346.         push    eax
  2347.         mov     ecx, [edi+recordNode+indexOffset]
  2348.         add     eax, ecx
  2349.         add     ecx, recordNode
  2350.         shr     ecx, 2
  2351.         push    esi
  2352.         mov     esi, edi
  2353.         mov     edi, [ebp+NTFS.secondIndexBuffer]
  2354.         rep movsd
  2355.         pop     esi
  2356.         pop     ecx
  2357.         shr     ecx, 2
  2358.         rep movsd
  2359.         mov     edi, [ebp+NTFS.secondIndexBuffer]
  2360.         mov     [edi+recordNode+nodeRealSize], eax
  2361.         pop     edi
  2362.         mov     cl, 4
  2363.         xor     eax, eax
  2364.         mov     esi, edi
  2365.         rep stosd
  2366.         mov     byte [esi+indexAllocatedSize], 16
  2367.         mov     byte [esi+indexFlags], 2
  2368.         mov     esi, [ebp+NTFS.cur_index_buf]
  2369.         mov     eax, [ebp+NTFS.newRecord]
  2370.         mov     [esi+recordVCN], eax
  2371.         add     esi, recordNode
  2372.         sub     edi, esi
  2373.         mov     [esi+nodeRealSize], edi
  2374.         mov     ebx, [ebp+NTFS.secondIndexBuffer]
  2375.         mov     edx, [ebp+NTFS.LastRead]
  2376.         call    writeRecord
  2377.         jmp     .refresh
  2378.  
  2379. .common:
  2380.         add     edi, edx
  2381.         sub     edi, 4
  2382.         mov     esi, edi
  2383.         sub     esi, [esp]
  2384.         mov     ecx, esi
  2385.         sub     ecx, eax    ; eax = pointer in the record
  2386.         shr     ecx, 2
  2387.         inc     ecx
  2388.         std
  2389.         rep movsd           ; move forward, make space
  2390.         mov     ecx, [esp]
  2391.         shr     ecx, 2
  2392.         xor     eax, eax
  2393.         rep stosd
  2394.         cld
  2395.         add     edi, 4
  2396.         call    ntfsGetTime
  2397.         mov     [edi+fileCreated], eax
  2398.         mov     [edi+fileCreated+4], edx
  2399.         mov     [edi+fileModified], eax
  2400.         mov     [edi+fileModified+4], edx
  2401.         mov     [edi+recordModified], eax
  2402.         mov     [edi+recordModified+4], edx
  2403.         mov     [edi+fileAccessed],