Subversion Repositories Kolibri OS

Rev

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