Subversion Repositories Kolibri OS

Rev

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