Subversion Repositories Kolibri OS

Rev

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