Subversion Repositories Kolibri OS

Rev

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