Subversion Repositories Kolibri OS

Rev

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