Subversion Repositories Kolibri OS

Rev

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