Subversion Repositories Kolibri OS

Rev

Rev 5994 | Rev 6080 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2. ;;                                                              ;;
  3. ;; Copyright (C) KolibriOS team 2004-2015. All rights reserved. ;;
  4. ;; Distributed under terms of the GNU General Public License    ;;
  5. ;;                                                              ;;
  6. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  7.  
  8. $Revision: 6019 $
  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. updateSequenceOffset = 4
  33. updateSequenceSize = 6
  34. reuseCounter = 16
  35. hardLinkCounter = 12h
  36. attributeOffset = 14h
  37. recordFlags = 16h
  38. recordRealSize = 18h
  39. recordAllocatedSize = 1ch
  40. baseRecordReference = 20h       ; for auxiliary records
  41. baseRecordReuse = 26h
  42. newAttributeID = 28h
  43.     ; attribute header
  44. attributeType = 0
  45. sizeWithHeader = 4
  46. nonResidentFlag = 8
  47. nameLength = 9
  48. nameOffset = 10
  49. attributeFlags = 12
  50. attributeID = 14
  51. sizeWithoutHeader = 16
  52. indexedFlag = 16h
  53.     ; non resident attribute header
  54. lastVCN = 18h
  55. dataRunsOffset = 20h
  56. attributeAllocatedSize = 28h
  57. attributeRealSize = 30h
  58. initialDataSize = 38h
  59.     ; $IndexRoot
  60. collationRule = 4
  61. indexRecordSize = 8
  62. indexRecordSizeClus = 12
  63.     ; node header
  64. indexOffset = 0
  65. nodeRealSize = 4
  66. nodeAllocatedSize = 8
  67.     ; $Filename index
  68. fileRecordReference = 0
  69. fileReferenceReuse = 6
  70. indexAllocatedSize = 8
  71. indexRawSize = 10
  72. indexFlags = 12
  73. directoryRecordReference = 16
  74. directoryReferenceReuse = 16h
  75. fileAllocatedSize = 38h
  76. fileRealSize = 40h
  77. fileFlags = 48h
  78. fileNameLength = 50h
  79.  
  80. struct NTFS PARTITION
  81. Lock                MUTEX   ?   ; Currently operations with one partition
  82. ; can not be executed in parallel since the legacy code is not ready.
  83. sectors_per_cluster     dd  ?
  84. mft_cluster             dd  ?   ; location
  85. mftmirr_cluster         dd  ?   ; location
  86. frs_size                dd  ?   ; in bytes
  87. frs_buffer              dd  ?   ; MFT fileRecord buffer
  88. mft_retrieval           dd  ?
  89. mft_retrieval_size      dd  ?
  90. mft_retrieval_alloc     dd  ?
  91. mft_retrieval_end       dd  ?
  92. cur_index_size          dd  ?   ; in sectors
  93. cur_index_buf           dd  ?   ; index node buffer
  94. BitmapBuffer            dd  ?
  95. BitmapTotalSize         dd  ?   ; bytes reserved
  96. BitmapSize              dd  ?   ; bytes readen
  97. BitmapLocation          dd  ?   ; starting sector
  98. BitmapStart             dd  ?   ; first byte after area, reserved for MFT
  99. mftBitmapBuffer         dd  ?   ; one cluster
  100. mftBitmapSize           dd  ?   ; bytes readen
  101. mftBitmapLocation       dd  ?   ; starting sector
  102.  
  103. ntfs_cur_attr           dd  ?   ; attribute type
  104. ntfs_cur_iRecord        dd  ?   ; number of fileRecord in MFT
  105. ntfs_cur_offs           dd  ?   ; attribute VCN in sectors
  106. ntfs_cur_size           dd  ?   ; max sectors to read
  107. ntfs_cur_buf            dd  ?
  108. ntfs_cur_read           dd  ?   ; bytes readen
  109. ntfsLastRead            dd  ?   ; last readen block of sectors
  110. newMftRecord            dd  ?   ; number of fileRecord in MFT
  111. fileDataStart           dd  ?   ; starting cluster
  112. fileDataSize            dd  ?   ; in clusters
  113. fileRealSize            dd  ?   ; in bytes
  114. indexOffset             dd  ?
  115. nodeLastRead            dd  ?
  116. ntfs_bCanContinue       db  ?
  117. ntfsFolder              db  ?
  118. ntfsWriteAttr           db  ?   ; Warning: Don't forget to turn off!!!
  119. ntfsFragmentCount       db  ?
  120.  
  121. cur_subnode_size        dd  ?
  122. ntfs_attr_iRecord       dd  ?
  123. ntfs_attr_iBaseRecord   dd  ?
  124. ntfs_attr_offs          dd  ?
  125. ntfs_attr_list          dd  ?
  126. ntfs_attr_size          dq  ?
  127. ntfs_cur_tail           dd  ?
  128.  
  129. ntfs_attrlist_buf       rb  0x400
  130. ntfs_attrlist_mft_buf   rb  0x400
  131. ntfs_bitmap_buf         rb  0x400
  132. ends
  133.  
  134. ; NTFS external functions
  135. ;   in:
  136. ; ebx -> parameter structure of sysfunc 70
  137. ; ebp -> NTFS structure
  138. ; [esi]+[esp+4] = name
  139. ;   out:
  140. ; eax, ebx = return values for sysfunc 70
  141. iglobal
  142. align 4
  143. ntfs_user_functions:
  144.         dd      ntfs_free
  145.         dd      (ntfs_user_functions_end - ntfs_user_functions - 4) / 4
  146.         dd      ntfs_ReadFile
  147.         dd      ntfs_ReadFolder
  148.         dd      ntfs_CreateFile
  149.         dd      ntfs_WriteFile
  150.         dd      ntfs_SetFileEnd
  151.         dd      ntfs_GetFileInfo
  152.         dd      ntfs_SetFileInfo
  153.         dd      0
  154.         dd      ntfs_Delete
  155.         dd      ntfs_CreateFolder
  156. ntfs_user_functions_end:
  157. endg
  158.  
  159. ntfs_test_bootsec:
  160. ; in: ebx -> buffer, edx = size of partition
  161. ; out: CF=1 -> invalid
  162. ; 1. Name=='NTFS    '
  163.         cmp     dword [ebx+3], 'NTFS'
  164.         jnz     .no
  165.         cmp     dword [ebx+7], '    '
  166.         jnz     .no
  167. ; 2. Number of bytes per sector is the same as for physical device
  168. ; (that is, 0x200 for hard disk)
  169.         cmp     word [ebx+11], 0x200
  170.         jnz     .no
  171. ; 3. Number of sectors per cluster must be power of 2
  172.         movzx   eax, byte [ebx+13]
  173.         dec     eax
  174.         js      .no
  175.         test    al, [ebx+13]
  176.         jnz     .no
  177. ; 4. FAT parameters must be zero
  178.         cmp     word [ebx+14], 0
  179.         jnz     .no
  180.         cmp     dword [ebx+16], 0
  181.         jnz     .no
  182.         cmp     byte [ebx+20], 0
  183.         jnz     .no
  184.         cmp     word [ebx+22], 0
  185.         jnz     .no
  186.         cmp     dword [ebx+32], 0
  187.         jnz     .no
  188. ; 5. Number of sectors <= partition size
  189.         cmp     dword [ebx+0x2C], 0
  190.         ja      .no
  191.         cmp     [ebx+0x28], edx
  192.         ja      .no
  193. ; 6. $MFT and $MFTMirr clusters must be within partition
  194.         cmp     dword [ebx+0x34], 0
  195.         ja      .no
  196.         push    edx
  197.         movzx   eax, byte [ebx+13]
  198.         mul     dword [ebx+0x30]
  199.         test    edx, edx
  200.         pop     edx
  201.         jnz     .no
  202.         cmp     eax, edx
  203.         ja      .no
  204.         cmp     dword [ebx+0x3C], 0
  205.         ja      .no
  206.         push    edx
  207.         movzx   eax, byte [ebx+13]
  208.         mul     dword [ebx+0x38]
  209.         test    edx, edx
  210.         pop     edx
  211.         jnz     .no
  212.         cmp     eax, edx
  213.         ja      .no
  214. ; 7. Clusters per FRS must be either power of 2 or between -31 and -9
  215.         movsx   eax, byte [ebx+0x40]
  216.         cmp     al, -31
  217.         jl      .no
  218.         cmp     al, -9
  219.         jle     @f
  220.         dec     eax
  221.         js      .no
  222.         test    [ebx+0x40], al
  223.         jnz     .no
  224. @@:         ; 8. Same for clusters per IndexAllocationBuffer
  225.         movsx   eax, byte [ebx+0x44]
  226.         cmp     al, -31
  227.         jl      .no
  228.         cmp     al, -9
  229.         jle     @f
  230.         dec     eax
  231.         js      .no
  232.         test    [ebx+0x44], al
  233.         jnz     .no
  234. @@:         ; OK, this is correct NTFS bootsector
  235.         clc
  236.         ret
  237. .no:        ; No, this bootsector isn't NTFS
  238.         stc
  239.         ret
  240.  
  241. ntfs_create_partition:
  242.         cmp     dword [esi+DISK.MediaInfo.SectorSize], 512
  243.         jnz     .nope
  244.         mov     edx, dword [ebp+PARTITION.Length]
  245.         cmp     dword [esp+4], 0
  246.         jz      .boot_read_ok
  247.         add     ebx, 512
  248.         lea     eax, [edx-1]
  249.         call    fs_read32_sys
  250.         test    eax, eax
  251.         jnz     @f
  252.         call    ntfs_test_bootsec
  253.         jnc     .ntfs_setup
  254. @@:
  255.         mov     eax, edx
  256.         shr     eax, 1
  257.         call    fs_read32_sys
  258.         test    eax, eax
  259.         jnz     .nope
  260. .boot_read_ok:
  261.         call    ntfs_test_bootsec
  262.         jnc     .ntfs_setup
  263. .nope:
  264.         xor     eax, eax
  265.         jmp     .exit
  266. ; By given bootsector, initialize some NTFS variables
  267. .ntfs_setup:
  268.         movi    eax, sizeof.NTFS
  269.         call    malloc
  270.         test    eax, eax
  271.         jz      .exit
  272.         mov     ecx, dword [ebp+PARTITION.FirstSector]
  273.         mov     dword [eax+NTFS.FirstSector], ecx
  274.         mov     ecx, dword [ebp+PARTITION.FirstSector+4]
  275.         mov     dword [eax+NTFS.FirstSector+4], ecx
  276.         mov     ecx, [ebp+PARTITION.Disk]
  277.         mov     [eax+NTFS.Disk], ecx
  278.         mov     [eax+NTFS.FSUserFunctions], ntfs_user_functions
  279.         mov     [eax+NTFS.ntfsWriteAttr], 0
  280.  
  281.         push    ebx ebp esi
  282.         mov     ebp, eax
  283.         lea     ecx, [ebp+NTFS.Lock]
  284.         call    mutex_init
  285.         movzx   eax, byte [ebx+13]
  286.         mov     [ebp+NTFS.sectors_per_cluster], eax
  287.         mov     eax, [ebx+0x28]
  288.         mov     dword [ebp+NTFS.Length], eax
  289.         and     dword [ebp+NTFS.Length+4], 0
  290.         mov     eax, [ebx+0x30]
  291.         mov     [ebp+NTFS.mft_cluster], eax
  292.         mov     eax, [ebx+0x38]
  293.         mov     [ebp+NTFS.mftmirr_cluster], eax
  294.         movsx   eax, byte [ebx+0x40]
  295.         test    eax, eax
  296.         js      @f
  297.         mul     [ebp+NTFS.sectors_per_cluster]
  298.         shl     eax, 9
  299.         jmp     .1
  300. @@:
  301.         neg     eax
  302.         mov     ecx, eax
  303.         mov     eax, 1
  304.         shl     eax, cl
  305. .1:
  306.         mov     [ebp+NTFS.frs_size], eax
  307.         stdcall kernel_alloc, eax
  308.         test    eax, eax
  309.         jz      .fail_free
  310.         mov     [ebp+NTFS.frs_buffer], eax
  311. ; read $MFT disposition
  312.         mov     eax, [ebp+NTFS.mft_cluster]
  313.         mul     [ebp+NTFS.sectors_per_cluster]
  314.         call    ntfs_read_frs_sector
  315.         test    eax, eax
  316.         jnz     .usemirr
  317.         cmp     dword [ebx], 'FILE'
  318.         jnz     .usemirr
  319.         call    ntfs_restore_usa_frs
  320.         jnc     .mftok
  321. .usemirr:
  322.         mov     eax, [ebp+NTFS.mftmirr_cluster]
  323.         mul     [ebp+NTFS.sectors_per_cluster]
  324.         call    ntfs_read_frs_sector
  325.         test    eax, eax
  326.         jnz     .fail_free_frs
  327.         cmp     dword [ebx], 'FILE'
  328.         jnz     .fail_free_frs
  329.         call    ntfs_restore_usa_frs
  330.         jc      .fail_free_frs
  331. .mftok:
  332. ; read $MFT table retrieval information
  333. ; start with one page, increase if not enough (when MFT too fragmented)
  334.         push    ebx
  335.         stdcall kernel_alloc, 0x1000
  336.         pop     ebx
  337.         test    eax, eax
  338.         jz      .fail_free_frs
  339.         mov     [ebp+NTFS.mft_retrieval], eax
  340.         and     [ebp+NTFS.mft_retrieval_size], 0
  341.         mov     [ebp+NTFS.mft_retrieval_alloc], 0x1000/8
  342. ; $MFT base record must contain unnamed non-resident $DATA attribute
  343.         movzx   eax, word [ebx+14h]
  344.         add     eax, ebx
  345. .scandata:
  346.         cmp     dword [eax], -1
  347.         jz      .fail_free_mft
  348.         cmp     dword [eax], 0x80
  349.         jnz     @f
  350.         cmp     byte [eax+9], 0
  351.         jz      .founddata
  352. @@:
  353.         add     eax, [eax+4]
  354.         jmp     .scandata
  355. .founddata:
  356.         cmp     byte [eax+8], 0
  357.         jz      .fail_free_mft
  358. ; load first portion of $DATA attribute retrieval information
  359.         mov     edx, [eax+0x18]
  360.         mov     [ebp+NTFS.mft_retrieval_end], edx
  361.         mov     esi, eax
  362.         movzx   eax, word [eax+0x20]
  363.         add     esi, eax
  364.         sub     esp, 10h
  365. .scanmcb:
  366.         call    ntfs_decode_mcb_entry
  367.         jnc     .scanmcbend
  368.         call    .get_mft_retrieval_ptr
  369.         mov     edx, [esp]      ; block length
  370.         mov     [eax], edx
  371.         mov     edx, [esp+8]    ; block addr (relative)
  372.         mov     [eax+4], edx
  373.         inc     [ebp+NTFS.mft_retrieval_size]
  374.         jmp     .scanmcb
  375. .scanmcbend:
  376.         add     esp, 10h
  377. ; there may be other portions of $DATA attribute in auxiliary records;
  378. ; if they will be needed, they will be loaded later
  379.         mov     [ebp+NTFS.cur_index_size], 0x1000/0x200
  380.         stdcall kernel_alloc, 0x1000
  381.         test    eax, eax
  382.         jz      .fail_free_mft
  383.         mov     [ebp+NTFS.cur_index_buf], eax
  384. ; reserve adress space for bitmap buffer and load some part of bitmap
  385.         mov     eax, dword [ebp+NTFS.Length]
  386.         xor     edx, edx
  387.         div     [ebp+NTFS.sectors_per_cluster]
  388.         shr     eax, 3
  389.         mov     [ebp+NTFS.BitmapTotalSize], eax
  390.         add     eax, 7FFFh
  391.         and     eax, not 7FFFh
  392.         push    eax
  393.         call    alloc_kernel_space
  394.         test    eax, eax
  395.         jz      .failFreeIndex
  396.         mov     [ebp+NTFS.BitmapBuffer], eax
  397.         mov     [ebp+NTFS.ntfs_cur_buf], eax
  398.         mov     eax, [ebp+NTFS.BitmapTotalSize]
  399.         add     eax, [ebp+NTFS.mft_cluster]
  400.         shr     eax, 3+2        ; reserve 1/8 of partition for $MFT
  401.         shl     eax, 2
  402.         mov     [ebp+NTFS.BitmapStart], eax
  403.         shr     eax, 15
  404.         inc     eax
  405.         shl     eax, 3
  406.         push    eax
  407.         push    eax
  408.         shl     eax, 3
  409.         mov     [ebp+NTFS.ntfs_cur_size], eax
  410.         call    alloc_pages
  411.         test    eax, eax
  412.         pop     ecx
  413.         jz      .failFreeBitmap
  414.         add     eax, 3
  415.         mov     ebx, [ebp+NTFS.BitmapBuffer]
  416.         call    commit_pages
  417.         mov     [ebp+NTFS.ntfs_cur_iRecord], 6
  418.         mov     [ebp+NTFS.ntfs_cur_attr], 0x80
  419.         mov     [ebp+NTFS.ntfs_cur_offs], 0
  420.         call    ntfs_read_attr
  421.         jc      .failFreeBitmap
  422.         mov     eax, [ebp+NTFS.ntfs_cur_read]
  423.         mov     [ebp+NTFS.BitmapSize], eax
  424.         mov     eax, [ebp+NTFS.ntfsLastRead]
  425.         mov     [ebp+NTFS.BitmapLocation], eax
  426. ; read MFT $BITMAP attribute
  427.         mov     eax, [ebp+NTFS.sectors_per_cluster]
  428.         mov     [ebp+NTFS.ntfs_cur_size], eax
  429.         shl     eax, 9
  430.         stdcall kernel_alloc, eax
  431.         test    eax, eax
  432.         jz      .failFreeBitmap
  433.         mov     [ebp+NTFS.mftBitmapBuffer], eax
  434.         mov     [ebp+NTFS.ntfs_cur_buf], eax
  435.         mov     [ebp+NTFS.ntfs_cur_iRecord], 0
  436.         mov     [ebp+NTFS.ntfs_cur_attr], 0xB0
  437.         mov     [ebp+NTFS.ntfs_cur_offs], 0
  438.         call    ntfs_read_attr
  439.         mov     eax, [ebp+NTFS.ntfs_cur_read]
  440.         cmp     eax, 4
  441.         jc      .failFreeBitmapMFT
  442.         mov     [ebp+NTFS.mftBitmapSize], eax
  443.         mov     eax, [ebp+NTFS.ntfsLastRead]
  444.         mov     [ebp+NTFS.mftBitmapLocation], eax
  445.  
  446.         mov     eax, ebp
  447. .pop_exit:
  448.         pop     esi ebp ebx
  449. .exit:
  450.         cmp     dword [esp+4], 0
  451.         jz      @f
  452.         sub     ebx, 512
  453. @@:
  454.         ret
  455.  
  456. .failFreeBitmapMFT:
  457.         stdcall kernel_free, [ebx+NTFS.mftBitmapBuffer]
  458. .failFreeBitmap:
  459.         stdcall kernel_free, [ebx+NTFS.BitmapBuffer]
  460. .failFreeIndex:
  461.         stdcall kernel_free, [ebp+NTFS.cur_index_buf]
  462. .fail_free_mft:
  463.         stdcall kernel_free, [ebp+NTFS.mft_retrieval]
  464. .fail_free_frs:
  465.         stdcall kernel_free, [ebp+NTFS.frs_buffer]
  466. .fail_free:
  467.         mov     eax, ebp
  468.         call    free
  469.         xor     eax, eax
  470.         jmp     .pop_exit
  471.  
  472. .get_mft_retrieval_ptr:
  473.         pushad
  474.         mov     eax, [ebp+NTFS.mft_retrieval_size]
  475.         cmp     eax, [ebp+NTFS.mft_retrieval_alloc]
  476.         jnz     .ok
  477.         add     eax, 0x1000/8
  478.         mov     [ebp+NTFS.mft_retrieval_alloc], eax
  479.         shl     eax, 3
  480.         stdcall kernel_alloc, eax
  481.         test    eax, eax
  482.         jnz     @f
  483.         popad
  484.         add     esp, 14h
  485.         jmp     .fail_free_mft
  486. @@:
  487.         mov     esi, [ebp+NTFS.mft_retrieval]
  488.         mov     edi, eax
  489.         mov     ecx, [ebp+NTFS.mft_retrieval_size]
  490.         add     ecx, ecx
  491.         rep movsd
  492.         push    [ebp+NTFS.mft_retrieval]
  493.         mov     [ebp+NTFS.mft_retrieval], eax
  494.         call    kernel_free
  495.         mov     eax, [ebp+NTFS.mft_retrieval_size]
  496. .ok:
  497.         shl     eax, 3
  498.         add     eax, [ebp+NTFS.mft_retrieval]
  499.         mov     [esp+28], eax
  500.         popad
  501.         ret
  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.mft_retrieval]
  508.         stdcall kernel_free, [ebx+NTFS.cur_index_buf]
  509.         stdcall kernel_free, [ebx+NTFS.mftBitmapBuffer]
  510.         stdcall kernel_free, [ebx+NTFS.BitmapBuffer]
  511.         mov     eax, ebx
  512.         pop     ebx
  513.         jmp     free
  514.  
  515. ntfs_lock:
  516.         lea     ecx, [ebp+NTFS.Lock]
  517.         jmp     mutex_lock
  518.  
  519. ntfs_unlock:
  520.         lea     ecx, [ebp+NTFS.Lock]
  521.         jmp     mutex_unlock
  522.  
  523. ntfs_read_frs_sector:
  524.         push    ecx
  525.         mov     ebx, [ebp+NTFS.frs_buffer]
  526.         push    ebx
  527.         mov     ecx, [ebp+NTFS.frs_size]
  528.         shr     ecx, 9
  529.         push    ecx
  530.         mov     ecx, eax
  531. @@:
  532.         mov     eax, ecx
  533.         call    fs_read32_sys
  534.         test    eax, eax
  535.         jnz     .fail
  536.         add     ebx, 0x200
  537.         inc     ecx
  538.         dec     dword [esp]
  539.         jnz     @b
  540.         pop     eax
  541. .fail:
  542.         pop     ebx
  543.         pop     ecx
  544.         ret
  545.  
  546. ntfs_read_attr:
  547. ; [ebp+NTFS.ntfsWriteAttr]=1 -> write attribute
  548. ;   in:
  549. ; [ebp+NTFS.ntfs_cur_iRecord] = number of fileRecord
  550. ; [ebp+NTFS.ntfs_cur_attr] = attribute type
  551. ; [ebp+NTFS.ntfs_cur_offs] = attribute VCN in sectors
  552. ; [ebp+NTFS.ntfs_cur_buf] -> buffer for data
  553. ; [ebp+NTFS.ntfs_cur_size] = max sectors to read
  554. ;   out:
  555. ; [ebp+NTFS.ntfs_cur_read] = bytes readen
  556. ; CF=1 -> failed, eax = disk error code, eax=0 -> something with FS
  557.         xor     eax, eax
  558.         pushad
  559.         and     [ebp+NTFS.ntfs_cur_read], 0
  560.         cmp     [ebp+NTFS.ntfs_cur_iRecord], 0
  561.         jnz     .nomft
  562.         cmp     [ebp+NTFS.ntfs_cur_attr], 0x80
  563.         jnz     .nomft
  564.         mov     eax, [ebp+NTFS.mft_retrieval_end]
  565.         inc     eax
  566.         mul     [ebp+NTFS.sectors_per_cluster]
  567.         cmp     eax, [ebp+NTFS.ntfs_cur_offs]
  568.         jbe     .nomft
  569. ; precalculated part of $Mft $DATA
  570.         mov     esi, [ebp+NTFS.mft_retrieval]
  571.         mov     eax, [ebp+NTFS.ntfs_cur_offs]
  572.         xor     edx, edx
  573.         div     [ebp+NTFS.sectors_per_cluster]
  574. ; eax = VCN, edx = offset in sectors from beginning of cluster
  575.         xor     ecx, ecx        ; ecx will contain LCN
  576. .mftscan:
  577.         add     ecx, [esi+4]
  578.         sub     eax, [esi]
  579.         jb      @f
  580.         add     esi, 8
  581.         push    eax
  582.         mov     eax, [ebp+NTFS.mft_retrieval_end]
  583.         shl     eax, 3
  584.         add     eax, [ebp+NTFS.mft_retrieval]
  585.         cmp     eax, esi
  586.         pop     eax
  587.         jnz     .mftscan
  588.         jmp     .nomft
  589. @@:
  590.         push    ecx
  591.         add     ecx, eax
  592.         add     ecx, [esi]
  593.         push    eax
  594.         push    edx
  595.         mov     eax, [ebp+NTFS.sectors_per_cluster]
  596.         mul     ecx
  597. ; eax = sector on partition
  598.         pop     edx
  599.         add     eax, edx
  600.         mov     ebx, [ebp+NTFS.ntfs_cur_buf]
  601.         pop     ecx
  602.         neg     ecx
  603.         imul    ecx, [ebp+NTFS.sectors_per_cluster]
  604.         sub     ecx, edx
  605.         mov     [ebp+NTFS.ntfsLastRead], eax
  606.         cmp     ecx, [ebp+NTFS.ntfs_cur_size]
  607.         jb      @f
  608.         mov     ecx, [ebp+NTFS.ntfs_cur_size]
  609. @@:
  610. ; ecx = number of sequential sectors to read
  611.         push    eax
  612.         call    fs_read32_sys
  613.         pop     edx
  614.         test    eax, eax
  615.         jnz     .errread
  616.         add     [ebp+NTFS.ntfs_cur_read], 0x200
  617.         dec     [ebp+NTFS.ntfs_cur_size]
  618.         inc     [ebp+NTFS.ntfs_cur_offs]
  619.         add     ebx, 0x200
  620.         mov     [ebp+NTFS.ntfs_cur_buf], ebx
  621.         lea     eax, [edx+1]
  622.         loop    @b
  623.         pop     ecx
  624.         xor     eax, eax
  625.         xor     edx, edx
  626.         cmp     [ebp+NTFS.ntfs_cur_size], eax
  627.         jz      @f
  628.         add     esi, 8
  629.         push    eax
  630.         mov     eax, [ebp+NTFS.mft_retrieval_end]
  631.         shl     eax, 3
  632.         add     eax, [ebp+NTFS.mft_retrieval]
  633.         cmp     eax, esi
  634.         pop     eax
  635.         jz      .nomft
  636.         jmp     .mftscan
  637. @@:
  638.         popad
  639.         ret
  640. .errread:
  641.         pop     ecx
  642. .errret:
  643.         mov     [esp+28], eax
  644.         stc
  645.         popad
  646.         ret
  647. .nomft:
  648. ; 1. Read file record.
  649. ; N.B. This will do recursive call of read_attr for $MFT::$Data.
  650.         mov     eax, [ebp+NTFS.ntfs_cur_iRecord]
  651.         mov     [ebp+NTFS.ntfs_attr_iRecord], eax
  652.         and     [ebp+NTFS.ntfs_attr_list], 0
  653.         or      dword [ebp+NTFS.ntfs_attr_size], -1
  654.         or      dword [ebp+NTFS.ntfs_attr_size+4], -1
  655.         or      [ebp+NTFS.ntfs_attr_iBaseRecord], -1
  656.         call    ntfs_read_file_record
  657.         jc      .errret
  658. ; 2. Find required attribute.
  659.         mov     eax, [ebp+NTFS.frs_buffer]
  660. ; a) For auxiliary records, read base record
  661. ; N.B. If base record is present,
  662. ;      base iRecord may be 0 (for $Mft), but SequenceNumber is nonzero
  663.         cmp     dword [eax+24h], 0
  664.         jz      @f
  665.         mov     eax, [eax+20h]
  666. ;        test    eax, eax
  667. ;        jz      @f
  668. .beginfindattr:
  669.         mov     [ebp+NTFS.ntfs_attr_iRecord], eax
  670.         call    ntfs_read_file_record
  671.         jc      .errret
  672. @@:
  673. ; b) Scan for required attribute and for $ATTR_LIST
  674.         mov     eax, [ebp+NTFS.frs_buffer]
  675.         movzx   ecx, word [eax+14h]
  676.         add     eax, ecx
  677.         mov     ecx, [ebp+NTFS.ntfs_cur_attr]
  678.         and     [ebp+NTFS.ntfs_attr_offs], 0
  679. .scanattr:
  680.         cmp     dword [eax], -1
  681.         jz      .scandone
  682.         cmp     dword [eax], ecx
  683.         jz      .okattr
  684.         cmp     [ebp+NTFS.ntfs_attr_iBaseRecord], -1
  685.         jnz     .scancont
  686.         cmp     dword [eax], 0x20       ; $ATTR_LIST
  687.         jnz     .scancont
  688.         mov     [ebp+NTFS.ntfs_attr_list], eax
  689.         jmp     .scancont
  690. .okattr:
  691. ; ignore named $DATA attributes (aka NTFS streams)
  692.         cmp     ecx, 0x80
  693.         jnz     @f
  694.         cmp     byte [eax+9], 0
  695.         jnz     .scancont
  696. @@:
  697.         mov     [ebp+NTFS.ntfs_attr_offs], eax
  698. .scancont:
  699.         add     eax, [eax+4]
  700.         jmp     .scanattr
  701. .continue:
  702.         pushad
  703.         and     [ebp+NTFS.ntfs_cur_read], 0
  704. .scandone:
  705. ; c) Check for required offset and length
  706.         mov     ecx, [ebp+NTFS.ntfs_attr_offs]
  707.         jecxz   .noattr
  708.         push    [ebp+NTFS.ntfs_cur_size]
  709.         push    [ebp+NTFS.ntfs_cur_read]
  710.         call    .doreadattr
  711.         pop     edx
  712.         pop     ecx
  713.         jc      @f
  714.         cmp     [ebp+NTFS.ntfs_bCanContinue], 0
  715.         jz      @f
  716.         sub     edx, [ebp+NTFS.ntfs_cur_read]
  717.         neg     edx
  718.         shr     edx, 9
  719.         sub     ecx, edx
  720.         mov     [ebp+NTFS.ntfs_cur_size], ecx
  721.         jnz     .not_in_cur
  722. @@:
  723.         popad
  724.         ret
  725. .noattr:
  726. .not_in_cur:
  727.         cmp     [ebp+NTFS.ntfs_cur_attr], 0x20
  728.         jz      @f
  729.         mov     ecx, [ebp+NTFS.ntfs_attr_list]
  730.         test    ecx, ecx
  731.         jnz     .lookattr
  732. .ret_is_attr:
  733.         and     dword [esp+28], 0
  734.         cmp     [ebp+NTFS.ntfs_attr_offs], 1     ; CF set <=> ntfs_attr_offs == 0
  735.         popad
  736.         ret
  737. .lookattr:
  738. ; required attribute or required offset was not found in base record;
  739. ; it may be present in auxiliary records;
  740. ; scan $ATTR_LIST
  741.         mov     eax, [ebp+NTFS.ntfs_attr_iBaseRecord]
  742.         cmp     eax, -1
  743.         jz      @f
  744.         call    ntfs_read_file_record
  745.         jc      .errret
  746.         or      [ebp+NTFS.ntfs_attr_iBaseRecord], -1
  747. @@:
  748.         push    [ebp+NTFS.ntfs_cur_offs]
  749.         push    [ebp+NTFS.ntfs_cur_size]
  750.         push    [ebp+NTFS.ntfs_cur_read]
  751.         push    [ebp+NTFS.ntfs_cur_buf]
  752.         push    dword [ebp+NTFS.ntfs_attr_size]
  753.         push    dword [ebp+NTFS.ntfs_attr_size+4]
  754.         or      dword [ebp+NTFS.ntfs_attr_size], -1
  755.         or      dword [ebp+NTFS.ntfs_attr_size+4], -1
  756.         and     [ebp+NTFS.ntfs_cur_offs], 0
  757.         mov     [ebp+NTFS.ntfs_cur_size], 2
  758.         and     [ebp+NTFS.ntfs_cur_read], 0
  759.         lea     eax, [ebp+NTFS.ntfs_attrlist_buf]
  760.         cmp     [ebp+NTFS.ntfs_cur_iRecord], 0
  761.         jnz     @f
  762.         lea     eax, [ebp+NTFS.ntfs_attrlist_mft_buf]
  763. @@:
  764.         mov     [ebp+NTFS.ntfs_cur_buf], eax
  765.         push    eax
  766.         call    .doreadattr
  767.         pop     esi
  768.         mov     edx, 1
  769.         pop     dword [ebp+NTFS.ntfs_attr_size+4]
  770.         pop     dword [ebp+NTFS.ntfs_attr_size]
  771.         mov     ecx, [ebp+NTFS.ntfs_cur_read]
  772.         pop     [ebp+NTFS.ntfs_cur_buf]
  773.         pop     [ebp+NTFS.ntfs_cur_read]
  774.         pop     [ebp+NTFS.ntfs_cur_size]
  775.         pop     [ebp+NTFS.ntfs_cur_offs]
  776.         jc      .errret
  777.         or      edi, -1
  778.         lea     ecx, [ecx+esi-1Ah]
  779. .scanliststart:
  780.         push    ecx
  781.         mov     eax, [ebp+NTFS.ntfs_cur_attr]
  782. .scanlist:
  783.         cmp     esi, [esp]
  784.         jae     .scanlistdone
  785.         cmp     eax, [esi]
  786.         jz      @f
  787. .scanlistcont:
  788.         movzx   ecx, word [esi+4]
  789.         add     esi, ecx
  790.         jmp     .scanlist
  791. @@:
  792. ; ignore named $DATA attributes (aka NTFS streams)
  793.         cmp     eax, 0x80
  794.         jnz     @f
  795.         cmp     byte [esi+6], 0
  796.         jnz     .scanlistcont
  797. @@:
  798.         push    eax
  799.         mov     eax, [esi+8]
  800.         test    eax, eax
  801.         jnz     .testf
  802.         mov     eax, dword [ebp+NTFS.ntfs_attr_size]
  803.         and     eax, dword [ebp+NTFS.ntfs_attr_size+4]
  804.         cmp     eax, -1
  805.         jnz     .testfz
  806. ; if attribute is in auxiliary records, its size is defined only in first
  807.         mov     eax, [esi+10h]
  808.         call    ntfs_read_file_record
  809.         jnc     @f
  810. .errret_pop:
  811.         pop     ecx ecx
  812.         jmp     .errret
  813. .errret2_pop:
  814.         xor     eax, eax
  815.         jmp     .errret_pop
  816. @@:
  817.         mov     eax, [ebp+NTFS.frs_buffer]
  818.         movzx   ecx, word [eax+14h]
  819.         add     eax, ecx
  820.         mov     ecx, [ebp+NTFS.ntfs_cur_attr]
  821. @@:
  822.         cmp     dword [eax], -1
  823.         jz      .errret2_pop
  824.         cmp     dword [eax], ecx
  825.         jz      @f
  826. .l1:
  827.         add     eax, [eax+4]
  828.         jmp     @b
  829. @@:
  830.         cmp     eax, 0x80
  831.         jnz     @f
  832.         cmp     byte [eax+9], 0
  833.         jnz     .l1
  834. @@:
  835.         cmp     byte [eax+8], 0
  836.         jnz     .sdnores
  837.         mov     eax, [eax+10h]
  838.         mov     dword [ebp+NTFS.ntfs_attr_size], eax
  839.         and     dword [ebp+NTFS.ntfs_attr_size+4], 0
  840.         jmp     .testfz
  841. .sdnores:
  842.         mov     ecx, [eax+30h]
  843.         mov     dword [ebp+NTFS.ntfs_attr_size], ecx
  844.         mov     ecx, [eax+34h]
  845.         mov     dword [ebp+NTFS.ntfs_attr_size+4], ecx
  846. .testfz:
  847.         xor     eax, eax
  848. .testf:
  849.         imul    eax, [ebp+NTFS.sectors_per_cluster]
  850.         cmp     eax, [ebp+NTFS.ntfs_cur_offs]
  851.         pop     eax
  852.         ja      @f
  853.         mov     edi, [esi+10h]  ; keep previous iRecord
  854.         jmp     .scanlistcont
  855. @@:
  856.         pop     ecx
  857. .scanlistfound:
  858.         cmp     edi, -1
  859.         jnz     @f
  860.         popad
  861.         ret
  862. @@:
  863.         mov     eax, [ebp+NTFS.ntfs_cur_iRecord]
  864.         mov     [ebp+NTFS.ntfs_attr_iBaseRecord], eax
  865.         mov     eax, edi
  866.         jmp     .beginfindattr
  867. .scanlistdone:
  868.         pop     ecx
  869.         sub     ecx, ebp
  870.         sub     ecx, NTFS.ntfs_attrlist_buf-1Ah
  871.         cmp     [ebp+NTFS.ntfs_cur_iRecord], 0
  872.         jnz     @f
  873.         sub     ecx, NTFS.ntfs_attrlist_mft_buf-NTFS.ntfs_attrlist_buf
  874. @@:
  875.         cmp     ecx, 0x400
  876.         jnz     .scanlistfound
  877.         inc     edx
  878.         push    esi edi
  879.         lea     esi, [ebp+NTFS.ntfs_attrlist_buf+0x200]
  880.         lea     edi, [ebp+NTFS.ntfs_attrlist_buf]
  881.         cmp     [ebp+NTFS.ntfs_cur_iRecord], 0
  882.         jnz     @f
  883.         lea     esi, [ebp+NTFS.ntfs_attrlist_mft_buf+0x200]
  884.         lea     edi, [ebp+NTFS.ntfs_attrlist_mft_buf]
  885. @@:
  886.         mov     ecx, 0x200/4
  887.         rep movsd
  888.         mov     eax, edi
  889.         pop     edi esi
  890.         sub     esi, 0x200
  891.         push    [ebp+NTFS.ntfs_cur_offs]
  892.         push    [ebp+NTFS.ntfs_cur_size]
  893.         push    [ebp+NTFS.ntfs_cur_read]
  894.         push    [ebp+NTFS.ntfs_cur_buf]
  895.         push    dword [ebp+NTFS.ntfs_attr_size]
  896.         push    dword [ebp+NTFS.ntfs_attr_size+4]
  897.         or      dword [ebp+NTFS.ntfs_attr_size], -1
  898.         or      dword [ebp+NTFS.ntfs_attr_size+4], -1
  899.         mov     [ebp+NTFS.ntfs_cur_offs], edx
  900.         mov     [ebp+NTFS.ntfs_cur_size], 1
  901.         and     [ebp+NTFS.ntfs_cur_read], 0
  902.         mov     [ebp+NTFS.ntfs_cur_buf], eax
  903.         mov     ecx, [ebp+NTFS.ntfs_attr_list]
  904.         push    esi edx edi
  905.         call    .doreadattr
  906.         pop     edi edx esi
  907.         mov     ecx, [ebp+NTFS.ntfs_cur_read]
  908.         pop     dword [ebp+NTFS.ntfs_attr_size+4]
  909.         pop     dword [ebp+NTFS.ntfs_attr_size]
  910.         pop     [ebp+NTFS.ntfs_cur_buf]
  911.         pop     [ebp+NTFS.ntfs_cur_read]
  912.         pop     [ebp+NTFS.ntfs_cur_size]
  913.         pop     [ebp+NTFS.ntfs_cur_offs]
  914.         jc      .errret
  915.         lea     ecx, [ecx+ebp+NTFS.ntfs_attrlist_buf+0x200-0x1A]
  916.         cmp     [ebp+NTFS.ntfs_cur_iRecord], 0
  917.         jnz     .scanliststart
  918.         add     ecx, NTFS.ntfs_attrlist_mft_buf-NTFS.ntfs_attrlist_buf
  919.         jmp     .scanliststart
  920.  
  921. .doreadattr:
  922.         mov     [ebp+NTFS.ntfs_bCanContinue], 0
  923.         cmp     byte [ecx+8], 0
  924.         jnz     .nonresident
  925.         mov     eax, [ecx+10h]  ; length
  926.         mov     esi, eax
  927.         mov     edx, [ebp+NTFS.ntfs_cur_offs]
  928.         shr     eax, 9
  929.         cmp     eax, edx
  930.         jb      .okret
  931.         shl     edx, 9
  932.         sub     esi, edx
  933.         movzx   eax, word [ecx+14h]
  934.         add     edx, eax
  935.         add     edx, ecx        ; edx -> data
  936.         mov     eax, [ebp+NTFS.ntfs_cur_size]
  937.         cmp     eax, (0xFFFFFFFF shr 9)+1
  938.         jbe     @f
  939.         mov     eax, (0xFFFFFFFF shr 9)+1
  940. @@:
  941.         shl     eax, 9
  942.         cmp     eax, esi
  943.         jbe     @f
  944.         mov     eax, esi
  945. @@:
  946. ; eax = length, edx -> data
  947.         mov     [ebp+NTFS.ntfs_cur_read], eax
  948.         mov     ecx, eax
  949.         mov     eax, edx
  950.         mov     ebx, [ebp+NTFS.ntfs_cur_buf]
  951.         call    memmove
  952.         and     [ebp+NTFS.ntfs_cur_size], 0      ; CF=0
  953.         ret
  954. .nonresident:
  955. ; Not all auxiliary records contain correct FileSize info
  956.         mov     eax, dword [ebp+NTFS.ntfs_attr_size]
  957.         mov     edx, dword [ebp+NTFS.ntfs_attr_size+4]
  958.         push    eax
  959.         and     eax, edx
  960.         cmp     eax, -1
  961.         pop     eax
  962.         jnz     @f
  963.         mov     eax, [ecx+30h]  ; FileSize
  964.         mov     edx, [ecx+34h]
  965.         mov     dword [ebp+NTFS.ntfs_attr_size], eax
  966.         mov     dword [ebp+NTFS.ntfs_attr_size+4], edx
  967. @@:
  968.         add     eax, 0x1FF
  969.         adc     edx, 0
  970.         shrd    eax, edx, 9
  971.         sub     eax, [ebp+NTFS.ntfs_cur_offs]
  972.         ja      @f
  973. ; return with nothing read
  974.         and     [ebp+NTFS.ntfs_cur_size], 0
  975. .okret:
  976.         clc
  977.         ret
  978. @@:
  979. ; reduce read length
  980.         and     [ebp+NTFS.ntfs_cur_tail], 0
  981.         cmp     [ebp+NTFS.ntfs_cur_size], eax
  982.         jb      @f
  983.         mov     [ebp+NTFS.ntfs_cur_size], eax
  984.         mov     eax, dword [ebp+NTFS.ntfs_attr_size]
  985.         and     eax, 0x1FF
  986.         mov     [ebp+NTFS.ntfs_cur_tail], eax
  987. @@:
  988.         cmp     [ebp+NTFS.ntfs_cur_size], 0
  989.         jz      .okret
  990.         mov     eax, [ebp+NTFS.ntfs_cur_offs]
  991.         xor     edx, edx
  992.         div     [ebp+NTFS.sectors_per_cluster]
  993.         sub     eax, [ecx+10h]  ; first_vbo
  994.         jb      .okret
  995. ; eax = cluster, edx = starting sector
  996.         cmp     [ebp+NTFS.ntfs_cur_attr], 0x80
  997.         jnz     .sys
  998.         cmp     [ebp+NTFS.ntfs_cur_iRecord], 0
  999.         jz      .sys
  1000.         push    fs_read64_app
  1001.         cmp     [ebp+NTFS.ntfsWriteAttr], 1
  1002.         jnz     @f
  1003.         mov     dword[esp], fs_write64_app
  1004.         jmp     @f
  1005. .sys:
  1006.         push    fs_read64_sys
  1007. @@:
  1008.         sub     esp, 10h
  1009.         movzx   esi, word [ecx+20h]     ; mcb_info_ofs
  1010.         add     esi, ecx
  1011.         xor     edi, edi
  1012.         mov     [ebp+NTFS.ntfsFragmentCount], 0
  1013. .readloop:
  1014.         call    ntfs_decode_mcb_entry
  1015.         jnc     .break
  1016.         add     edi, [esp+8]
  1017.         sub     eax, [esp]
  1018.         jae     .readloop
  1019.         push    ecx
  1020.         push    eax
  1021.         add     eax, [esp+8]
  1022.         add     eax, edi
  1023.         imul    eax, [ebp+NTFS.sectors_per_cluster]
  1024.         add     eax, edx
  1025.         pop     ecx
  1026.         neg     ecx
  1027.         imul    ecx, [ebp+NTFS.sectors_per_cluster]
  1028.         sub     ecx, edx
  1029.         cmp     ecx, [ebp+NTFS.ntfs_cur_size]
  1030.         jb      @f
  1031.         mov     ecx, [ebp+NTFS.ntfs_cur_size]
  1032. @@:
  1033.         mov     ebx, [ebp+NTFS.ntfs_cur_buf]
  1034.         mov     [ebp+NTFS.ntfsLastRead], eax
  1035.         push    ecx
  1036.         xor     edx, edx
  1037.         call    dword[esp+18h]
  1038.         pop     ecx
  1039.         test    eax, eax
  1040.         jnz     .errread2
  1041.         sub     [ebp+NTFS.ntfs_cur_size], ecx
  1042.         add     [ebp+NTFS.ntfs_cur_offs], ecx
  1043.         shl     ecx, 9
  1044.         add     [ebp+NTFS.ntfs_cur_read], ecx
  1045.         add     [ebp+NTFS.ntfs_cur_buf], ecx
  1046.         inc     [ebp+NTFS.ntfsFragmentCount]
  1047.         pop     ecx
  1048.         xor     eax, eax
  1049.         xor     edx, edx
  1050.         cmp     [ebp+NTFS.ntfs_cur_size], 0
  1051.         jnz     .readloop
  1052.         add     esp, 14h
  1053.         mov     eax, [ebp+NTFS.ntfs_cur_tail]
  1054.         test    eax, eax
  1055.         jz      @f
  1056.         sub     eax, 0x200
  1057.         add     [ebp+NTFS.ntfs_cur_read], eax
  1058. @@:
  1059.         clc
  1060.         ret
  1061. .errread2:
  1062.         pop     ecx
  1063.         add     esp, 14h
  1064.         stc
  1065.         ret
  1066. .break:
  1067.         add     esp, 14h        ; CF=0
  1068.         mov     [ebp+NTFS.ntfs_bCanContinue], 1
  1069.         ret
  1070.  
  1071. ntfs_read_file_record:
  1072. ; in: eax = iRecord
  1073. ; out: [ebp+NTFS.frs_buffer] = record data
  1074. ; CF=1 -> failed, eax = disk error code, eax=0 -> something with FS
  1075.     ; Read attr $DATA of $Mft, starting from eax*[ebp+NTFS.frs_size]
  1076.         push    ecx edx
  1077.         mov     ecx, [ebp+NTFS.frs_size]
  1078.         mul     ecx
  1079.         shrd    eax, edx, 9
  1080.         shr     edx, 9
  1081.         jnz     .errret
  1082.         push    [ebp+NTFS.ntfs_attr_iRecord]
  1083.         push    [ebp+NTFS.ntfs_attr_iBaseRecord]
  1084.         push    [ebp+NTFS.ntfs_attr_offs]
  1085.         push    [ebp+NTFS.ntfs_attr_list]
  1086.         push    dword [ebp+NTFS.ntfs_attr_size+4]
  1087.         push    dword [ebp+NTFS.ntfs_attr_size]
  1088.         push    [ebp+NTFS.ntfs_cur_iRecord]
  1089.         push    [ebp+NTFS.ntfs_cur_attr]
  1090.         push    [ebp+NTFS.ntfs_cur_offs]
  1091.         push    [ebp+NTFS.ntfs_cur_size]
  1092.         push    [ebp+NTFS.ntfs_cur_buf]
  1093.         push    [ebp+NTFS.ntfs_cur_read]
  1094.         mov     [ebp+NTFS.ntfs_cur_attr], 0x80   ; $DATA
  1095.         and     [ebp+NTFS.ntfs_cur_iRecord], 0   ; $Mft
  1096.         mov     [ebp+NTFS.ntfs_cur_offs], eax
  1097.         shr     ecx, 9
  1098.         mov     [ebp+NTFS.ntfs_cur_size], ecx
  1099.         mov     eax, [ebp+NTFS.frs_buffer]
  1100.         mov     [ebp+NTFS.ntfs_cur_buf], eax
  1101.         call    ntfs_read_attr
  1102.         mov     edx, [ebp+NTFS.ntfs_cur_read]
  1103.         pop     [ebp+NTFS.ntfs_cur_read]
  1104.         pop     [ebp+NTFS.ntfs_cur_buf]
  1105.         pop     [ebp+NTFS.ntfs_cur_size]
  1106.         pop     [ebp+NTFS.ntfs_cur_offs]
  1107.         pop     [ebp+NTFS.ntfs_cur_attr]
  1108.         pop     [ebp+NTFS.ntfs_cur_iRecord]
  1109.         pop     dword [ebp+NTFS.ntfs_attr_size]
  1110.         pop     dword [ebp+NTFS.ntfs_attr_size+4]
  1111.         pop     [ebp+NTFS.ntfs_attr_list]
  1112.         pop     [ebp+NTFS.ntfs_attr_offs]
  1113.         pop     [ebp+NTFS.ntfs_attr_iBaseRecord]
  1114.         pop     [ebp+NTFS.ntfs_attr_iRecord]
  1115.         jc      .ret
  1116.         cmp     edx, [ebp+NTFS.frs_size]
  1117.         jnz     .errret
  1118.         mov     eax, [ebp+NTFS.frs_buffer]
  1119.         cmp     dword [eax], 'FILE'
  1120.         jnz     .errret
  1121.         push    ebx
  1122.         mov     ebx, eax
  1123.         call    ntfs_restore_usa_frs
  1124.         pop     ebx
  1125.         jc      .errret
  1126. .ret:
  1127.         pop     edx ecx
  1128.         ret
  1129. .errret:
  1130.         pop     edx ecx
  1131.         xor     eax, eax
  1132.         stc
  1133.         ret
  1134.  
  1135. ntfs_restore_usa_frs:
  1136.         mov     eax, [ebp+NTFS.frs_size]
  1137. ntfs_restore_usa:
  1138.         pushad
  1139.         shr     eax, 9
  1140.         mov     ecx, eax
  1141.         inc     eax
  1142.         cmp     [ebx+6], ax
  1143.         jnz     .err
  1144.         movzx   eax, word [ebx+4]
  1145.         lea     esi, [eax+ebx]
  1146.         lodsw
  1147.         mov     edx, eax
  1148.         lea     edi, [ebx+0x1FE]
  1149. @@:
  1150.         cmp     [edi], dx
  1151.         jnz     .err
  1152.         lodsw
  1153.         stosw
  1154.         add     edi, 0x1FE
  1155.         loop    @b
  1156.         popad
  1157.         clc
  1158.         ret
  1159. .err:
  1160.         popad
  1161.         stc
  1162.         ret
  1163.  
  1164. ntfs_decode_mcb_entry:
  1165. ;   in:
  1166. ; esi -> mcb entry
  1167. ; esp -> buffer (16 bytes)
  1168. ;   out:
  1169. ; esi -> next mcb entry
  1170. ; esp -> data run size
  1171. ; esp+8 -> cluster (delta)
  1172. ; CF=0 -> mcb end
  1173.         push    eax ecx edi
  1174.         lea     edi, [esp+16]
  1175.         xor     eax, eax
  1176.         lodsb
  1177.         test    al, al
  1178.         jz      .end
  1179.         mov     ecx, eax
  1180.         and     ecx, 0xF
  1181.         cmp     ecx, 8
  1182.         ja      .end
  1183.         push    ecx
  1184.         rep movsb
  1185.         pop     ecx
  1186.         sub     ecx, 8
  1187.         neg     ecx
  1188.         cmp     byte [esi-1], 80h
  1189.         jae     .end
  1190.         push    eax
  1191.         xor     eax, eax
  1192.         rep stosb
  1193.         pop     ecx
  1194.         shr     ecx, 4
  1195.         cmp     ecx, 8
  1196.         ja      .end
  1197.         push    ecx
  1198.         rep movsb
  1199.         pop     ecx
  1200.         sub     ecx, 8
  1201.         neg     ecx
  1202.         cmp     byte [esi-1], 80h
  1203.         cmc
  1204.         sbb     eax, eax
  1205.         rep stosb
  1206.         stc
  1207. .end:
  1208.         pop     edi ecx eax
  1209.         ret
  1210.  
  1211. unichar_toupper:
  1212.         push    eax
  1213.         call    uni2ansi_char
  1214.         cmp     al, '_'
  1215.         jz      .unk
  1216.         add     esp, 4
  1217.         call    char_toupper
  1218.         jmp     ansi2uni_char
  1219. .unk:
  1220.         pop     eax
  1221.         ret
  1222.  
  1223. ntfs_find_lfn:
  1224. ; in: [esi]+[esp+4] = name
  1225. ;   out:
  1226. ; [ebp+NTFS.ntfs_cur_iRecord] = number of MFT fileRecord
  1227. ; eax -> index in the parent index node
  1228. ; CF=1 -> file not found, eax=0 -> error
  1229.         mov     [ebp+NTFS.ntfs_cur_iRecord], 5   ; start parse from root cluster
  1230. .doit2:
  1231.         mov     [ebp+NTFS.ntfs_cur_attr], 0x90   ; $INDEX_ROOT
  1232.         and     [ebp+NTFS.ntfs_cur_offs], 0
  1233.         mov     eax, [ebp+NTFS.cur_index_size]
  1234.         mov     [ebp+NTFS.ntfs_cur_size], eax
  1235.         mov     eax, [ebp+NTFS.cur_index_buf]
  1236.         mov     [ebp+NTFS.ntfs_cur_buf], eax
  1237.         call    ntfs_read_attr
  1238.         mov     eax, 0
  1239.         jnc     @f
  1240. .ret:
  1241.         ret     4
  1242. @@:
  1243.         cmp     [ebp+NTFS.ntfs_cur_read], 0x20
  1244.         jc      .ret
  1245.         pushad
  1246.         mov     esi, [ebp+NTFS.cur_index_buf]
  1247.         mov     eax, [esi+14h]
  1248.         add     eax, 10h
  1249.         cmp     [ebp+NTFS.ntfs_cur_read], eax
  1250.         jae     .readok1
  1251.         add     eax, 1FFh
  1252.         shr     eax, 9
  1253.         cmp     eax, [ebp+NTFS.cur_index_size]
  1254.         ja      @f
  1255. .stc_ret:
  1256.         popad
  1257.         stc
  1258.         ret     4
  1259. @@:
  1260. ; reallocate
  1261.         push    eax
  1262.         stdcall kernel_free, [ebp+NTFS.cur_index_buf]
  1263.         pop     eax
  1264.         mov     [ebp+NTFS.cur_index_size], eax
  1265.         stdcall kernel_alloc, eax
  1266.         test    eax, eax
  1267.         jnz     @f
  1268.         and     [ebp+NTFS.cur_index_size], 0
  1269.         and     [ebp+NTFS.cur_index_buf], 0
  1270.         jmp     .stc_ret
  1271. @@:
  1272.         mov     [ebp+NTFS.cur_index_buf], eax
  1273.         popad
  1274.         jmp     .doit2
  1275. .readok1:
  1276.         mov     edx, [esi+8]    ; subnode_size
  1277.         shr     edx, 9
  1278.         cmp     edx, [ebp+NTFS.cur_index_size]
  1279.         jbe     .ok2
  1280.         push    esi edx
  1281.         stdcall kernel_alloc, edx
  1282.         pop     edx esi
  1283.         test    eax, eax
  1284.         jz      .stc_ret
  1285.         mov     edi, eax
  1286.         mov     ecx, [ebp+NTFS.cur_index_size]
  1287.         shl     ecx, 9-2
  1288.         rep movsd
  1289.         mov     esi, eax
  1290.         mov     [ebp+NTFS.cur_index_size], edx
  1291.         push    esi edx
  1292.         stdcall kernel_free, [ebp+NTFS.cur_index_buf]
  1293.         pop     edx esi
  1294.         mov     [ebp+NTFS.cur_index_buf], esi
  1295. .ok2:
  1296.         add     esi, 10h
  1297.         mov     edi, [esp+4]
  1298. ; edi -> name, esi -> current index data, edx = subnode size
  1299. .scanloop:
  1300.         add     esi, [esi]
  1301. .scanloopint:
  1302.         test    byte [esi+0Ch], 2
  1303.         jnz     .subnode
  1304.         push    esi
  1305.         add     esi, 0x52
  1306.         movzx   ecx, byte [esi-2]
  1307.         push    edi
  1308. @@:
  1309.         lodsw
  1310.         call    unichar_toupper
  1311.         push    eax
  1312.         mov     al, [edi]
  1313.         inc     edi
  1314.         cmp     al, '/'
  1315.         jz      .slash
  1316.         call    char_toupper
  1317.         call    ansi2uni_char
  1318.         cmp     ax, [esp]
  1319.         pop     eax
  1320.         loopz   @b
  1321.         jz      .found
  1322.         pop     edi
  1323.         pop     esi
  1324.         jb      .subnode
  1325. .scanloopcont:
  1326.         movzx   eax, word [esi+8]
  1327.         add     esi, eax
  1328.         jmp     .scanloopint
  1329. .slash:
  1330.         pop     eax
  1331.         pop     edi
  1332.         pop     esi
  1333. .subnode:
  1334.         test    byte [esi+0Ch], 1
  1335.         jz      .notfound
  1336.         movzx   eax, word [esi+8]
  1337.         mov     eax, [esi+eax-8]
  1338.         imul    eax, [ebp+NTFS.sectors_per_cluster]
  1339.         mov     [ebp+NTFS.ntfs_cur_offs], eax
  1340.         mov     [ebp+NTFS.ntfs_cur_attr], 0xA0   ; $INDEX_ALLOCATION
  1341.         mov     [ebp+NTFS.ntfs_cur_size], edx
  1342.         mov     eax, [ebp+NTFS.cur_index_buf]
  1343.         mov     esi, eax
  1344.         mov     [ebp+NTFS.ntfs_cur_buf], eax
  1345.         push    edx
  1346.         call    ntfs_read_attr
  1347.         pop     edx
  1348.         mov     eax, edx
  1349.         shl     eax, 9
  1350.         cmp     [ebp+NTFS.ntfs_cur_read], eax
  1351.         jnz     .err
  1352.         cmp     dword [esi], 'INDX'
  1353.         jnz     .err
  1354.         mov     [ebp+NTFS.ntfs_cur_buf], esi
  1355.         mov     ebx, esi
  1356.         call    ntfs_restore_usa
  1357.         jc      .err
  1358.         add     esi, 0x18
  1359.         jmp     .scanloop
  1360. .notfound:
  1361.         mov     [esp+1Ch], esi
  1362. .err:
  1363.         popad
  1364.         stc
  1365.         ret     4
  1366. .found:
  1367.         cmp     byte [edi], 0
  1368.         jz      .done
  1369.         cmp     byte [edi], '/'
  1370.         jz      .next
  1371.         pop     edi
  1372.         pop     esi
  1373.         jmp     .scanloopcont
  1374. .done:
  1375. .next:
  1376.         pop     esi
  1377.         pop     esi
  1378.         mov     eax, [esi]
  1379.         mov     [ebp+NTFS.ntfs_cur_iRecord], eax
  1380.         mov     [esp+1Ch], esi
  1381.         mov     [esp+4], edi
  1382.         popad
  1383.         inc     esi
  1384.         cmp     byte [esi-1], 0
  1385.         jnz     .doit2
  1386.         cmp     dword [esp+4], 0
  1387.         jz      @f
  1388.         mov     esi, [esp+4]
  1389.         mov     dword [esp+4], 0
  1390.         jmp     .doit2
  1391. @@:
  1392.         ret     4
  1393.  
  1394. ;----------------------------------------------------------------
  1395. ntfs_ReadFile:
  1396.         cmp     byte [esi], 0
  1397.         jnz     @f
  1398.         or      ebx, -1
  1399.         movi    eax, ERROR_ACCESS_DENIED
  1400.         ret
  1401. @@:
  1402.         call    ntfs_lock
  1403.         stdcall ntfs_find_lfn, [esp+4]
  1404.         jnc     .found
  1405.         call    ntfs_unlock
  1406.         or      ebx, -1
  1407.         movi    eax, ERROR_FILE_NOT_FOUND
  1408.         ret
  1409. .found:
  1410.         mov     [ebp+NTFS.ntfs_cur_attr], 0x80   ; $DATA
  1411.         and     [ebp+NTFS.ntfs_cur_offs], 0
  1412.         and     [ebp+NTFS.ntfs_cur_size], 0
  1413.         call    ntfs_read_attr
  1414.         jnc     @f
  1415.         call    ntfs_unlock
  1416.         or      ebx, -1
  1417.         movi    eax, ERROR_ACCESS_DENIED
  1418.         ret
  1419. @@:
  1420.         pushad
  1421.         and     dword [esp+10h], 0
  1422.         xor     eax, eax
  1423.         cmp     dword [ebx+8], 0x200
  1424.         jb      @f
  1425. .eof0:
  1426.         popad
  1427.         xor     ebx, ebx
  1428. .eof:
  1429.         push    ERROR_END_OF_FILE
  1430.         call    ntfs_unlock
  1431.         pop     eax
  1432.         ret
  1433. @@:
  1434.         mov     ecx, [ebx+12]
  1435.         mov     edx, [ebx+16]
  1436.         mov     eax, [ebx+4]
  1437.         test    eax, 0x1FF
  1438.         jz      .alignedstart
  1439.         push    edx
  1440.         mov     edx, [ebx+8]
  1441.         shrd    eax, edx, 9
  1442.         pop     edx
  1443.         mov     [ebp+NTFS.ntfs_cur_offs], eax
  1444.         mov     [ebp+NTFS.ntfs_cur_size], 1
  1445.         lea     eax, [ebp+NTFS.ntfs_bitmap_buf]
  1446.         mov     [ebp+NTFS.ntfs_cur_buf], eax
  1447.         call    ntfs_read_attr.continue
  1448.         mov     eax, [ebx+4]
  1449.         and     eax, 0x1FF
  1450.         lea     esi, [ebp+NTFS.ntfs_bitmap_buf+eax]
  1451.         sub     eax, [ebp+NTFS.ntfs_cur_read]
  1452.         jae     .eof0
  1453.         neg     eax
  1454.         push    ecx
  1455.         cmp     ecx, eax
  1456.         jb      @f
  1457.         mov     ecx, eax
  1458. @@:
  1459.         mov     [esp+10h+4], ecx
  1460.         mov     edi, edx
  1461.         rep movsb
  1462.         mov     edx, edi
  1463.         pop     ecx
  1464.         sub     ecx, [esp+10h]
  1465.         jnz     @f
  1466. .retok:
  1467.         popad
  1468.         call    ntfs_unlock
  1469.         xor     eax, eax
  1470.         ret
  1471. @@:
  1472.         cmp     [ebp+NTFS.ntfs_cur_read], 0x200
  1473.         jz      .alignedstart
  1474. .eof_ebx:
  1475.         popad
  1476.         jmp     .eof
  1477. .alignedstart:
  1478.         mov     eax, [ebx+4]
  1479.         push    edx
  1480.         mov     edx, [ebx+8]
  1481.         add     eax, 511
  1482.         adc     edx, 0
  1483.         shrd    eax, edx, 9
  1484.         pop     edx
  1485.         mov     [ebp+NTFS.ntfs_cur_offs], eax
  1486.         mov     [ebp+NTFS.ntfs_cur_buf], edx
  1487.         mov     eax, ecx
  1488.         shr     eax, 9
  1489.         mov     [ebp+NTFS.ntfs_cur_size], eax
  1490.         add     eax, [ebp+NTFS.ntfs_cur_offs]
  1491.         push    eax
  1492.         call    ntfs_read_attr.continue
  1493.         pop     [ebp+NTFS.ntfs_cur_offs]
  1494.         mov     eax, [ebp+NTFS.ntfs_cur_read]
  1495.         add     [esp+10h], eax
  1496.         mov     eax, ecx
  1497.         and     eax, not 0x1FF
  1498.         cmp     [ebp+NTFS.ntfs_cur_read], eax
  1499.         jnz     .eof_ebx
  1500.         and     ecx, 0x1FF
  1501.         jz      .retok
  1502.         add     edx, [ebp+NTFS.ntfs_cur_read]
  1503.         mov     [ebp+NTFS.ntfs_cur_size], 1
  1504.         lea     eax, [ebp+NTFS.ntfs_bitmap_buf]
  1505.         mov     [ebp+NTFS.ntfs_cur_buf], eax
  1506.         call    ntfs_read_attr.continue
  1507.         cmp     [ebp+NTFS.ntfs_cur_read], ecx
  1508.         jb      @f
  1509.         mov     [ebp+NTFS.ntfs_cur_read], ecx
  1510. @@:
  1511.         xchg    ecx, [ebp+NTFS.ntfs_cur_read]
  1512.         push    ecx
  1513.         mov     edi, edx
  1514.         lea     esi, [ebp+NTFS.ntfs_bitmap_buf]
  1515.         add     [esp+10h+4], ecx
  1516.         rep movsb
  1517.         pop     ecx
  1518.         xor     eax, eax
  1519.         cmp     ecx, [ebp+NTFS.ntfs_cur_read]
  1520.         jz      @f
  1521.         mov     al, ERROR_END_OF_FILE
  1522. @@:
  1523.         mov     [esp+1Ch], eax
  1524.         call    ntfs_unlock
  1525.         popad
  1526.         ret
  1527.  
  1528. ;----------------------------------------------------------------
  1529. ntfs_ReadFolder:
  1530.         call    ntfs_lock
  1531.         mov     eax, 5          ; root cluster
  1532.         cmp     byte [esi], 0
  1533.         jz      .doit
  1534.         stdcall ntfs_find_lfn, [esp+4]
  1535.         jnc     .doit2
  1536. .notfound:
  1537.         or      ebx, -1
  1538.         push    ERROR_FILE_NOT_FOUND
  1539. .pop_ret:
  1540.         call    ntfs_unlock
  1541.         pop     eax
  1542.         ret
  1543. .doit:
  1544.         mov     [ebp+NTFS.ntfs_cur_iRecord], eax
  1545. .doit2:
  1546.         mov     [ebp+NTFS.ntfs_cur_attr], 0x10   ; $STANDARD_INFORMATION
  1547.         and     [ebp+NTFS.ntfs_cur_offs], 0
  1548.         mov     [ebp+NTFS.ntfs_cur_size], 1
  1549.         lea     eax, [ebp+NTFS.ntfs_bitmap_buf]
  1550.         mov     [ebp+NTFS.ntfs_cur_buf], eax
  1551.         call    ntfs_read_attr
  1552.         jc      .notfound
  1553.         mov     [ebp+NTFS.ntfs_cur_attr], 0x90   ; $INDEX_ROOT
  1554.         and     [ebp+NTFS.ntfs_cur_offs], 0
  1555.         mov     eax, [ebp+NTFS.cur_index_size]
  1556.         mov     [ebp+NTFS.ntfs_cur_size], eax
  1557.         mov     eax, [ebp+NTFS.cur_index_buf]
  1558.         mov     [ebp+NTFS.ntfs_cur_buf], eax
  1559.         call    ntfs_read_attr
  1560.         jnc     .ok
  1561.         test    eax, eax
  1562.         jz      .notfound
  1563.         or      ebx, -1
  1564.         push    ERROR_DEVICE
  1565.         jmp     .pop_ret
  1566. .ok:
  1567.         cmp     [ebp+NTFS.ntfs_cur_read], 0x20
  1568.         jae     @f
  1569.         or      ebx, -1
  1570. .fserr:
  1571.         push    ERROR_FAT_TABLE
  1572.         jmp     .pop_ret
  1573. @@:
  1574.         pushad
  1575.         mov     esi, [ebp+NTFS.cur_index_buf]
  1576.         mov     eax, [esi+14h]
  1577.         add     eax, 10h
  1578.         cmp     [ebp+NTFS.ntfs_cur_read], eax
  1579.         jae     .readok1
  1580.         add     eax, 1FFh
  1581.         shr     eax, 9
  1582.         cmp     eax, [ebp+NTFS.cur_index_size]
  1583.         ja      @f
  1584.         popad
  1585.         jmp     .fserr
  1586. @@:
  1587. ; reallocate
  1588.         push    eax
  1589.         stdcall kernel_free, [ebp+NTFS.cur_index_buf]
  1590.         pop     eax
  1591.         mov     [ebp+NTFS.cur_index_size], eax
  1592.         stdcall kernel_alloc, eax
  1593.         test    eax, eax
  1594.         jnz     @f
  1595.         and     [ebp+NTFS.cur_index_size], 0
  1596.         and     [ebp+NTFS.cur_index_buf], 0
  1597. .nomem:
  1598.         call    ntfs_unlock
  1599.         popad
  1600.         or      ebx, -1
  1601.         movi    eax, ERROR_OUT_OF_MEMORY
  1602.         ret
  1603. @@:
  1604.         mov     [ebp+NTFS.cur_index_buf], eax
  1605.         popad
  1606.         jmp     .doit2
  1607. .readok1:
  1608.         mov     edx, [esi+8]    ; subnode_size
  1609.         shr     edx, 9
  1610.         mov     [ebp+NTFS.cur_subnode_size], edx
  1611.         cmp     edx, [ebp+NTFS.cur_index_size]
  1612.         jbe     .ok2
  1613.         push    esi edx
  1614.         stdcall kernel_alloc, edx
  1615.         pop     edx esi
  1616.         test    eax, eax
  1617.         jz      .nomem
  1618.         mov     edi, eax
  1619.         mov     ecx, [ebp+NTFS.cur_index_size]
  1620.         shl     ecx, 9-2
  1621.         rep movsd
  1622.         mov     esi, eax
  1623.         mov     [ebp+NTFS.cur_index_size], edx
  1624.         stdcall kernel_free, [ebp+NTFS.cur_index_buf]
  1625.         mov     [ebp+NTFS.cur_index_buf], esi
  1626. .ok2:
  1627.         add     esi, 10h
  1628.         mov     edx, [ebx+16]
  1629.         push    dword [ebx+8]   ; read ANSI/UNICODE name
  1630. ; init header
  1631.         mov     edi, edx
  1632.         mov     ecx, 32/4
  1633.         xor     eax, eax
  1634.         rep stosd
  1635.         mov     byte [edx], 1   ; version
  1636.         mov     ecx, [ebx+12]
  1637.         mov     ebx, [ebx+4]
  1638.         push    edx
  1639.         mov     edx, esp
  1640. ; edi -> BDFE, esi -> current index data, ebx = first wanted block,
  1641. ; ecx = number of blocks to read
  1642. ; edx -> parameters block: dd <output>, dd <flags>
  1643.         cmp     [ebp+NTFS.ntfs_cur_iRecord], 5
  1644.         jz      .skip_specials
  1645. ; dot and dotdot entries
  1646.         push    esi
  1647.         xor     esi, esi
  1648.         call    .add_special_entry
  1649.         inc     esi
  1650.         call    .add_special_entry
  1651.         pop     esi
  1652. .skip_specials:
  1653. ; at first, dump index root
  1654.         add     esi, [esi]
  1655. .dump_root:
  1656.         test    byte [esi+0Ch], 2
  1657.         jnz     .dump_root_done
  1658.         call    .add_entry
  1659.         movzx   eax, word [esi+8]
  1660.         add     esi, eax
  1661.         jmp     .dump_root
  1662. .dump_root_done:
  1663. ; now dump all subnodes
  1664.         push    ecx edi
  1665.         lea     edi, [ebp+NTFS.ntfs_bitmap_buf]
  1666.         mov     [ebp+NTFS.ntfs_cur_buf], edi
  1667.         mov     ecx, 0x400/4
  1668.         xor     eax, eax
  1669.         rep stosd
  1670.         mov     [ebp+NTFS.ntfs_cur_attr], 0xB0   ; $BITMAP
  1671.         and     [ebp+NTFS.ntfs_cur_offs], 0
  1672.         mov     [ebp+NTFS.ntfs_cur_size], 2
  1673.         call    ntfs_read_attr
  1674.         pop     edi ecx
  1675.         push    0       ; save offset in $BITMAP attribute
  1676.         and     [ebp+NTFS.ntfs_cur_offs], 0
  1677. .dumploop:
  1678.         mov     [ebp+NTFS.ntfs_cur_attr], 0xA0
  1679.         mov     eax, [ebp+NTFS.cur_subnode_size]
  1680.         mov     [ebp+NTFS.ntfs_cur_size], eax
  1681.         mov     eax, [ebp+NTFS.cur_index_buf]
  1682.         mov     esi, eax
  1683.         mov     [ebp+NTFS.ntfs_cur_buf], eax
  1684.         push    [ebp+NTFS.ntfs_cur_offs]
  1685.         mov     eax, [ebp+NTFS.ntfs_cur_offs]
  1686.         imul    eax, [ebp+NTFS.cur_subnode_size]
  1687.         mov     [ebp+NTFS.ntfs_cur_offs], eax
  1688.         call    ntfs_read_attr
  1689.         pop     [ebp+NTFS.ntfs_cur_offs]
  1690.         mov     eax, [ebp+NTFS.cur_subnode_size]
  1691.         shl     eax, 9
  1692.         cmp     [ebp+NTFS.ntfs_cur_read], eax
  1693.         jnz     .done
  1694.         push    eax
  1695.         mov     eax, [ebp+NTFS.ntfs_cur_offs]
  1696.         and     eax, 0x400*8-1
  1697.         bt      dword [ebp+NTFS.ntfs_bitmap_buf], eax
  1698.         pop     eax
  1699.         jnc     .dump_subnode_done
  1700.         cmp     dword [esi], 'INDX'
  1701.         jnz     .dump_subnode_done
  1702.         push    ebx
  1703.         mov     ebx, esi
  1704.         call    ntfs_restore_usa
  1705.         pop     ebx
  1706.         jc      .dump_subnode_done
  1707.         add     esi, 0x18
  1708.         add     esi, [esi]
  1709. .dump_subnode:
  1710.         test    byte [esi+0Ch], 2
  1711.         jnz     .dump_subnode_done
  1712.         call    .add_entry
  1713.         movzx   eax, word [esi+8]
  1714.         add     esi, eax
  1715.         jmp     .dump_subnode
  1716. .dump_subnode_done:
  1717.         inc     [ebp+NTFS.ntfs_cur_offs]
  1718.         test    [ebp+NTFS.ntfs_cur_offs], 0x400*8-1
  1719.         jnz     .dumploop
  1720.         mov     [ebp+NTFS.ntfs_cur_attr], 0xB0
  1721.         push    ecx edi
  1722.         lea     edi, [ebp+NTFS.ntfs_bitmap_buf]
  1723.         mov     [ebp+NTFS.ntfs_cur_buf], edi
  1724.         mov     ecx, 0x400/4
  1725.         xor     eax, eax
  1726.         rep stosd
  1727.         pop     edi ecx
  1728.         pop     eax
  1729.         push    [ebp+NTFS.ntfs_cur_offs]
  1730.         inc     eax
  1731.         mov     [ebp+NTFS.ntfs_cur_offs], eax
  1732.         mov     [ebp+NTFS.ntfs_cur_size], 2
  1733.         push    eax
  1734.         call    ntfs_read_attr
  1735.         pop     eax
  1736.         pop     [ebp+NTFS.ntfs_cur_offs]
  1737.         push    eax
  1738.         jmp     .dumploop
  1739. .done:
  1740.         pop     eax
  1741.         pop     edx
  1742.         mov     ebx, [edx+4]
  1743.         pop     edx
  1744.         xor     eax, eax
  1745.         dec     ecx
  1746.         js      @f
  1747.         mov     al, ERROR_END_OF_FILE
  1748. @@:
  1749.         mov     [esp+1Ch], eax
  1750.         mov     [esp+10h], ebx
  1751.         call    ntfs_unlock
  1752.         popad
  1753.         ret
  1754.  
  1755. .add_special_entry:
  1756.         mov     eax, [edx]
  1757.         inc     dword [eax+8]   ; new file found
  1758.         dec     ebx
  1759.         jns     .ret
  1760.         dec     ecx
  1761.         js      .ret
  1762.         inc     dword [eax+4]   ; new file block copied
  1763.         mov     eax, [edx+4]
  1764.         mov     [edi+4], eax
  1765. ;        mov     eax, dword [ntfs_bitmap_buf+0x20]
  1766. ;        or      al, 0x10
  1767.         mov     eax, 0x10
  1768.         stosd
  1769.         scasd
  1770.         push    edx
  1771.         mov     eax, dword [ebp+NTFS.ntfs_bitmap_buf]
  1772.         mov     edx, dword [ebp+NTFS.ntfs_bitmap_buf+4]
  1773.         call    ntfs_datetime_to_bdfe
  1774.         mov     eax, dword [ebp+NTFS.ntfs_bitmap_buf+0x18]
  1775.         mov     edx, dword [ebp+NTFS.ntfs_bitmap_buf+0x1C]
  1776.         call    ntfs_datetime_to_bdfe
  1777.         mov     eax, dword [ebp+NTFS.ntfs_bitmap_buf+8]
  1778.         mov     edx, dword [ebp+NTFS.ntfs_bitmap_buf+0xC]
  1779.         call    ntfs_datetime_to_bdfe
  1780.         pop     edx
  1781.         xor     eax, eax
  1782.         stosd
  1783.         stosd
  1784.         mov     al, '.'
  1785.         push    edi ecx
  1786.         lea     ecx, [esi+1]
  1787.         test    byte [edi-0x24], 1
  1788.         jz      @f
  1789.         rep stosw
  1790.         pop     ecx
  1791.         xor     eax, eax
  1792.         stosw
  1793.         pop     edi
  1794.         add     edi, 520
  1795.         ret
  1796. @@:
  1797.         rep stosb
  1798.         pop     ecx
  1799.         xor     eax, eax
  1800.         stosb
  1801.         pop     edi
  1802.         add     edi, 264
  1803. .ret:
  1804.         ret
  1805.  
  1806. .add_entry:
  1807. ; do not return DOS 8.3 names
  1808.         cmp     byte [esi+0x51], 2
  1809.         jz      .ret
  1810. ; do not return system files
  1811. ; ... note that there will be no bad effects if system files also were reported ...
  1812.         cmp     dword [esi], 0x10
  1813.         jb      .ret
  1814.         mov     eax, [edx]
  1815.         inc     dword [eax+8]   ; new file found
  1816.         dec     ebx
  1817.         jns     .ret
  1818.         dec     ecx
  1819.         js      .ret
  1820.         inc     dword [eax+4]   ; new file block copied
  1821.         mov     eax, [edx+4]    ; flags
  1822.         call    ntfs_direntry_to_bdfe
  1823.         push    ecx esi edi
  1824.         movzx   ecx, byte [esi+0x50]
  1825.         add     esi, 0x52
  1826.         test    byte [edi-0x24], 1
  1827.         jz      .ansi
  1828.         shr     ecx, 1
  1829.         rep movsd
  1830.         adc     ecx, ecx
  1831.         rep movsw
  1832.         and     word [edi], 0
  1833.         pop     edi
  1834.         add     edi, 520
  1835.         pop     esi ecx
  1836.         ret
  1837. .ansi:
  1838.         jecxz   .skip
  1839. @@:
  1840.         lodsw
  1841.         call    uni2ansi_char
  1842.         stosb
  1843.         loop    @b
  1844. .skip:
  1845.         xor     al, al
  1846.         stosb
  1847.         pop     edi
  1848.         add     edi, 264
  1849.         pop     esi ecx
  1850.         ret
  1851.  
  1852. ntfs_direntry_to_bdfe:
  1853.         mov     [edi+4], eax    ; ANSI/UNICODE name
  1854.         mov     eax, [esi+48h]
  1855.         test    eax, 0x10000000
  1856.         jz      @f
  1857.         and     eax, not 0x10000000
  1858.         or      al, 0x10
  1859. @@:
  1860.         stosd
  1861.         scasd
  1862.         push    edx
  1863.         mov     eax, [esi+0x18]
  1864.         mov     edx, [esi+0x1C]
  1865.         call    ntfs_datetime_to_bdfe
  1866.         mov     eax, [esi+0x30]
  1867.         mov     edx, [esi+0x34]
  1868.         call    ntfs_datetime_to_bdfe
  1869.         mov     eax, [esi+0x20]
  1870.         mov     edx, [esi+0x24]
  1871.         call    ntfs_datetime_to_bdfe
  1872.         pop     edx
  1873.         mov     eax, [esi+0x40]
  1874.         stosd
  1875.         mov     eax, [esi+0x44]
  1876.         stosd
  1877.         ret
  1878.  
  1879. iglobal
  1880. _24             dd      24
  1881. _60             dd      60
  1882. _10000000       dd      10000000
  1883. days400year     dd      365*400+100-4+1
  1884. days100year     dd      365*100+25-1
  1885. days4year       dd      365*4+1
  1886. days1year       dd      365
  1887. months  dd  31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
  1888. months2 dd  31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
  1889. _400            dd      400
  1890. _100            dd      100
  1891. endg
  1892.  
  1893. ntfs_datetime_to_bdfe:
  1894. ; edx:eax = number of 100-nanosecond intervals since January 1, 1601, in UTC
  1895.         push    eax
  1896.         mov     eax, edx
  1897.         xor     edx, edx
  1898.         div     [_10000000]
  1899.         xchg    eax, [esp]
  1900.         div     [_10000000]
  1901.         pop     edx
  1902.     .sec:
  1903. ; edx:eax = number of seconds since January 1, 1601
  1904.         push    eax
  1905.         mov     eax, edx
  1906.         xor     edx, edx
  1907.         div     [_60]
  1908.         xchg    eax, [esp]
  1909.         div     [_60]
  1910.         mov     [edi], dl
  1911.         pop     edx
  1912. ; edx:eax = number of minutes
  1913.         div     [_60]
  1914.         mov     [edi+1], dl
  1915. ; eax = number of hours (note that 2^64/(10^7*60*60) < 2^32)
  1916.         xor     edx, edx
  1917.         div     [_24]
  1918.         mov     [edi+2], dl
  1919.         mov     [edi+3], byte 0
  1920. ; eax = number of days since January 1, 1601
  1921.         xor     edx, edx
  1922.         div     [days400year]
  1923.         imul    eax, 400
  1924.         add     eax, 1601
  1925.         mov     [edi+6], ax
  1926.         mov     eax, edx
  1927.         xor     edx, edx
  1928.         div     [days100year]
  1929.         cmp     al, 4
  1930.         jnz     @f
  1931.         dec     eax
  1932.         add     edx, [days100year]
  1933. @@:
  1934.         imul    eax, 100
  1935.         add     [edi+6], ax
  1936.         mov     eax, edx
  1937.         xor     edx, edx
  1938.         div     [days4year]
  1939.         shl     eax, 2
  1940.         add     [edi+6], ax
  1941.         mov     eax, edx
  1942.         xor     edx, edx
  1943.         div     [days1year]
  1944.         cmp     al, 4
  1945.         jnz     @f
  1946.         dec     eax
  1947.         add     edx, [days1year]
  1948. @@:
  1949.         add     [edi+6], ax
  1950.         push    esi edx
  1951.         mov     esi, months
  1952.         movzx   eax, word [edi+6]
  1953.         test    al, 3
  1954.         jnz     .noleap
  1955.         xor     edx, edx
  1956.         push    eax
  1957.         div     [_400]
  1958.         pop     eax
  1959.         test    edx, edx
  1960.         jz      .leap
  1961.         xor     edx, edx
  1962.         div     [_100]
  1963.         test    edx, edx
  1964.         jz      .noleap
  1965. .leap:
  1966.         mov     esi, months2
  1967. .noleap:
  1968.         pop     edx
  1969.         xor     eax, eax
  1970.         inc     eax
  1971. @@:
  1972.         sub     edx, [esi]
  1973.         jb      @f
  1974.         add     esi, 4
  1975.         inc     eax
  1976.         jmp     @b
  1977. @@:
  1978.         add     edx, [esi]
  1979.         pop     esi
  1980.         inc     edx
  1981.         mov     [edi+4], dl
  1982.         mov     [edi+5], al
  1983.         add     edi, 8
  1984.         ret
  1985.  
  1986. ;----------------------------------------------------------------
  1987. ntfs_CreateFolder:
  1988.         mov     [ebp+NTFS.ntfsFolder], 1
  1989.         jmp     @f
  1990.  
  1991. ntfs_CreateFile:
  1992.         mov     [ebp+NTFS.ntfsFolder], 0
  1993. @@:
  1994.         cmp     byte [esi], 0
  1995.         jnz     @f
  1996.         xor     ebx, ebx
  1997.         movi    eax, ERROR_ACCESS_DENIED
  1998.         ret
  1999. @@: ; 1. Search file
  2000.         call    ntfs_lock
  2001.         stdcall ntfs_find_lfn, [esp+4]
  2002.         jnc     .found
  2003.         cmp     [ebp+NTFS.ntfsFragmentCount], 1
  2004.         jnz     ntfsUnsupported     ; record fragmented
  2005.         test    eax, eax
  2006.         jz      ntfsFail
  2007.         jmp     .notFound
  2008.  
  2009. .found:     ; rewrite
  2010.         cmp     [ebp+NTFS.ntfs_cur_iRecord], 16
  2011.         jc      ntfsDenied
  2012.         cmp     [ebp+NTFS.ntfsFolder], 1
  2013.         jz      ntfsDenied
  2014.         mov     [ebp+NTFS.ntfs_cur_attr], 0x80
  2015.         mov     [ebp+NTFS.ntfs_cur_offs], 0
  2016.         mov     [ebp+NTFS.ntfs_cur_size], 0
  2017.         call    ntfs_read_attr
  2018.         jc      ntfsDenied
  2019.         mov     eax, [ebp+NTFS.frs_buffer]
  2020.         cmp     word [eax+baseRecordReuse], 0
  2021.         jnz     ntfsUnsupported     ; auxiliary record
  2022.         cmp     byte [eax+hardLinkCounter], 1
  2023.         jnz     ntfsUnsupported     ; file copying required
  2024.         mov     ecx, [ebp+NTFS.ntfs_attr_offs]
  2025.         cmp     byte [ecx+nonResidentFlag], 1
  2026.         jnz     ntfsUnsupported     ; resident $DATA
  2027.         mov     eax, [ebx+4]
  2028.         mov     edx, [ebx+8]
  2029.         add     eax, [ebx+12]
  2030.         adc     edx, 0
  2031.         cmp     edx, [ecx+attributeRealSize+4]
  2032.         jnz     ntfsUnsupported
  2033.         cmp     [ecx+attributeRealSize], eax
  2034.         jnz     ntfsUnsupported
  2035.         jmp     ntfs_WriteFile.write
  2036.  
  2037. .notFound:  ; create; check path folders
  2038.         cmp     dword [esp+4], 0
  2039.         jnz     ntfsNotFound
  2040.         cmp     byte [esi], 0
  2041.         jz      ntfsNotFound
  2042. ; 2. Prepare directory record
  2043.         mov     ecx, esi
  2044. @@:         ; count characters
  2045.         inc     ecx
  2046.         cmp     byte [ecx], '/'
  2047.         jz      ntfsNotFound
  2048.         cmp     byte [ecx], 0
  2049.         jnz     @b
  2050.         sub     ecx, esi
  2051.         push    ecx
  2052.         lea     ecx, [ecx*2+52h]    ; precalculate index length
  2053.         add     ecx, 7              ; align 8
  2054.         and     ecx, not 7
  2055.         mov     edi, [ebp+NTFS.cur_index_buf]
  2056.         push    esi
  2057.         push    ecx
  2058.         cmp     dword [edi], 'INDX'
  2059.         jz      .indexRecord
  2060.         mov     esi, [ebp+NTFS.frs_buffer]  ; indexRoot
  2061.         mov     edx, [esi+recordRealSize]
  2062.         add     edx, ecx
  2063.         cmp     [esi+recordAllocatedSize], edx
  2064.         jnc     @f
  2065.         add     esp, 12
  2066.         jmp     ntfsUnsupported     ; indexAllocation required
  2067. @@:         ; index fits in the indexRoot
  2068.         mov     [esi+recordRealSize], edx
  2069.         mov     ecx, edx
  2070.         shr     ecx, 2
  2071.         rep movsd
  2072.         mov     edi, [ebp+NTFS.ntfs_attr_offs]
  2073.         sub     edi, [ebp+NTFS.frs_buffer]
  2074.         add     edi, [ebp+NTFS.cur_index_buf]
  2075.         mov     esi, [esp]
  2076.         add     [edi+sizeWithHeader], esi
  2077.         add     [edi+sizeWithoutHeader], esi
  2078.         mov     cl, [edi+attributeOffset]
  2079.         add     edi, ecx
  2080.         add     [edi+16+nodeRealSize], esi
  2081.         add     [edi+16+nodeAllocatedSize], esi
  2082.         sub     eax, [ebp+NTFS.cur_index_buf]
  2083.         add     eax, edi
  2084.         mov     edi, [ebp+NTFS.cur_index_buf]
  2085.         add     edi, edx
  2086.         sub     edi, 4
  2087.         jmp     .common
  2088.  
  2089. .indexRecord:
  2090.         mov     edx, [edi+28]
  2091.         add     edx, ecx
  2092.         cmp     [edi+32], edx
  2093.         jnc     @f
  2094.         add     esp, 12
  2095.         jmp     ntfsUnsupported     ; new node required
  2096. @@:         ; index fits in the node
  2097.         mov     [edi+28], edx
  2098.         lea     edi, [edi+edx+24-4]
  2099. .common:
  2100.         mov     esi, edi
  2101.         sub     esi, [esp]
  2102.         mov     ecx, esi
  2103.         sub     ecx, eax    ; eax = pointer in the node
  2104.         shr     ecx, 2
  2105.         inc     ecx
  2106.         std
  2107.         rep movsd           ; move forward, make space
  2108.         mov     ecx, [esp]
  2109.         shr     ecx, 2
  2110.         xor     eax, eax
  2111.         rep stosd
  2112.         cld
  2113.         add     edi, 4
  2114.         pop     eax
  2115.         pop     esi
  2116.         mov     [edi+indexAllocatedSize], ax     ; fill index with data
  2117.         mov     eax, [esp]
  2118.         lea     eax, [eax*2+42h]
  2119.         mov     [edi+indexRawSize], ax
  2120.         mov     eax, [ebp+NTFS.ntfs_attr_iRecord]
  2121.         mov     [edi+directoryRecordReference], eax
  2122.         mov     eax, [ebp+NTFS.frs_buffer]
  2123.         mov     eax, [eax+reuseCounter]
  2124.         mov     [edi+directoryReferenceReuse], ax
  2125.         mov     eax, [ebx+12]
  2126.         mov     [ebp+NTFS.fileRealSize], eax
  2127.         mov     [edi+fileRealSize], eax
  2128.         mov     ecx, [ebp+NTFS.sectors_per_cluster]
  2129.         shl     ecx, 9
  2130.         add     eax, ecx
  2131.         dec     eax
  2132.         xor     edx, edx
  2133.         div     ecx
  2134.         mov     [ebp+NTFS.fileDataSize], eax
  2135.         mul     ecx
  2136.         mov     [edi+fileAllocatedSize], eax
  2137.         pop     ecx
  2138.         mov     [ebp+NTFS.indexOffset], edi
  2139.         mov     [edi+fileNameLength], cl
  2140.         add     edi, 52h
  2141. @@:         ; record filename
  2142.         lodsb
  2143.         call    ansi2uni_char
  2144.         stosw
  2145.         dec     ecx
  2146.         jnz     @b
  2147.         mov     eax, [ebp+NTFS.ntfsLastRead]
  2148.         mov     [ebp+NTFS.nodeLastRead], eax
  2149.         cmp     [ebp+NTFS.ntfsFolder], 0
  2150.         jz      @f
  2151.         mov     edi, [ebp+NTFS.indexOffset]
  2152.         mov     byte [edi+fileFlags+3], 16
  2153.         jmp     .mftBitmap
  2154.  
  2155. @@: ; 3. File data
  2156.         cmp     [ebp+NTFS.fileRealSize], 0
  2157.         jz      .mftBitmap
  2158. ; One piece free space bitmap search engine
  2159.         mov     edi, [ebp+NTFS.BitmapBuffer]
  2160.         add     edi, [ebp+NTFS.BitmapStart]
  2161.         mov     eax, [ebp+NTFS.fileDataSize]
  2162.         shr     eax, 5
  2163.         jz      .small
  2164.         push    eax         ; bitmap dwords
  2165.         add     edi, 4
  2166. .start:
  2167.         mov     ecx, [ebp+NTFS.BitmapSize]
  2168.         add     ecx, [ebp+NTFS.BitmapBuffer]
  2169.         sub     ecx, edi
  2170.         shr     ecx, 2
  2171. @@:
  2172.         xor     eax, eax
  2173.         repnz scasd         ; search for empty dword
  2174.         jz      @f
  2175.         call    bitmapBuffering
  2176.         jmp     @b
  2177. @@:
  2178.         cmp     ecx, [esp]
  2179.         jnc     @f
  2180.         call    bitmapBuffering
  2181.         jmp     @b
  2182. @@:
  2183.         sub     edi, 4
  2184.         mov     ecx, [esp]
  2185.         mov     esi, edi
  2186.         xor     eax, eax
  2187.         repz scasd          ; check following dwords
  2188.         jnz     .start
  2189.         sub     esi, 4
  2190.         mov     eax, [esi]
  2191.         xor     edx, edx
  2192.         bsr     edx, eax
  2193.         inc     edx
  2194.         push    edx         ; starting bit
  2195.         push    esi         ; starting dword
  2196.         add     esi, 4
  2197.         neg     edx
  2198.         add     edx, 32
  2199.         mov     eax, [ebp+NTFS.fileDataSize]
  2200.         sub     eax, edx
  2201.         mov     edx, eax
  2202.         shr     eax, 5
  2203.         shl     eax, 2
  2204.         add     esi, eax
  2205.         mov     eax, [esi]
  2206.         bsf     ecx, eax    ; last dword
  2207.         jz      .done
  2208.         and     edx, 31
  2209.         cmp     ecx, edx
  2210.         jnc     .done
  2211.         add     esp, 8
  2212.         jmp     .start
  2213.  
  2214. .small:     ; less than 32 clusters
  2215.         mov     ecx, [ebp+NTFS.BitmapSize]
  2216.         sub     ecx, [ebp+NTFS.BitmapStart]
  2217.         shr     ecx, 2
  2218. .smStart:
  2219.         mov     eax, -1
  2220.         repz scasd          ; search for zero bits
  2221.         push    ecx
  2222.         test    ecx, ecx
  2223.         jnz     @f
  2224.         call    bitmapBuffering
  2225.         pop     eax
  2226.         jmp     .smStart
  2227. @@:
  2228.         sub     edi, 4
  2229.         mov     eax, [edi]
  2230.         not     eax
  2231. @@:
  2232.         bsf     ecx, eax    ; first 0
  2233.         jz      .again
  2234.         not     eax
  2235.         shr     eax, cl
  2236.         shl     eax, cl
  2237.         bsf     edx, eax    ; next 1
  2238.         jz      @f
  2239.         sub     edx, ecx
  2240.         cmp     edx, [ebp+NTFS.fileDataSize]
  2241.         jnc     .got        ; fits inside
  2242.         bsf     ecx, eax
  2243.         not     eax
  2244.         shr     eax, cl
  2245.         shl     eax, cl
  2246.         jmp     @b
  2247. @@:         ; next dword
  2248.         mov     eax, [edi+4]
  2249.         bsf     edx, eax
  2250.         jz      .got        ; empty
  2251.         add     edx, 32
  2252.         sub     edx, ecx
  2253.         cmp     edx, [ebp+NTFS.fileDataSize]
  2254.         jnc     .got        ; share between dwords
  2255. .again:
  2256.         add     edi, 4
  2257.         pop     ecx
  2258.         jmp     .smStart
  2259.  
  2260. .got:
  2261.         push    ecx         ; starting bit
  2262.         push    edi         ; starting dword
  2263. .done:      ; mark space
  2264.         mov     ecx, [esp+4]
  2265.         cmp     ecx, 32
  2266.         jc      @f
  2267.         xor     ecx, ecx
  2268.         add     dword [esp], 4
  2269.         mov     [esp+4], ecx
  2270. @@:
  2271.         mov     edi, [esp]
  2272.         xor     eax, eax
  2273.         dec     eax
  2274.         shr     eax, cl
  2275.         shl     eax, cl
  2276.         neg     ecx
  2277.         add     ecx, 32
  2278.         sub     ecx, [ebp+NTFS.fileDataSize]
  2279.         jc      @f
  2280.         shl     eax, cl     ; fits inside dword
  2281.         shr     eax, cl
  2282.         or      [edi], eax
  2283.         jmp     .writeData
  2284.  
  2285. @@:
  2286.         or      [edi], eax
  2287.         neg     ecx
  2288.         push    ecx
  2289.         shr     ecx, 5
  2290.         add     edi, 4
  2291.         xor     eax, eax
  2292.         dec     eax
  2293.         rep stosd
  2294.         pop     ecx
  2295.         and     ecx, 31
  2296.         shr     eax, cl
  2297.         shl     eax, cl
  2298.         not     eax
  2299.         or      [edi], eax
  2300. .writeData:
  2301.         pop     edx
  2302.         sub     edx, [ebp+NTFS.BitmapBuffer]
  2303.         shl     edx, 3
  2304.         pop     eax
  2305.         add     eax, edx
  2306.         pop     edx
  2307.         mov     [ebp+NTFS.fileDataStart], eax
  2308.         mul     [ebp+NTFS.sectors_per_cluster]
  2309.         mov     ecx, [ebp+NTFS.fileRealSize]
  2310.         add     ecx, 511
  2311.         shr     ecx, 9
  2312.         mov     ebx, [ebx+16]
  2313.         call    fs_write64_app
  2314.         test    eax, eax
  2315.         jnz     ntfsDevice
  2316.     ; 4. MFT record
  2317. .mftBitmap: ; search for free record
  2318.         mov     edi, [ebp+NTFS.mftBitmapBuffer]
  2319.         mov     ecx, [ebp+NTFS.mftBitmapSize]
  2320.         mov     al, -1
  2321.         add     edi, 3
  2322.         sub     ecx, 3
  2323.         repz scasb
  2324.         dec     edi
  2325.         movzx   eax, byte [edi]
  2326.         not     al
  2327.         bsf     ecx, eax
  2328.         jz      ntfsUnsupported     ; no free records
  2329.         bts     [edi], ecx
  2330. ; get record location
  2331.         sub     edi, [ebp+NTFS.mftBitmapBuffer]
  2332.         shl     edi, 3
  2333.         add     edi, ecx
  2334.         mov     [ebp+NTFS.newMftRecord], edi
  2335.         mov     eax, [ebp+NTFS.frs_size]
  2336.         shr     eax, 9
  2337.         mul     edi
  2338.         mov     [ebp+NTFS.ntfs_cur_iRecord], 0
  2339.         mov     [ebp+NTFS.ntfs_cur_attr], 0x80
  2340.         mov     [ebp+NTFS.ntfs_cur_offs], eax
  2341.         mov     [ebp+NTFS.ntfs_cur_size], 1
  2342.         mov     eax, [ebp+NTFS.frs_buffer]
  2343.         mov     [ebp+NTFS.ntfs_cur_buf], eax
  2344.         call    ntfs_read_attr
  2345.         cmp     [ebp+NTFS.ntfs_cur_read], 0
  2346.         jnz     .mftRecord
  2347. ; extend MFT $DATA
  2348.         mov     eax, [ebp+NTFS.mft_cluster]
  2349.         mul     [ebp+NTFS.sectors_per_cluster]
  2350.         cmp     eax, [ebp+NTFS.ntfsLastRead]
  2351.         jnz     ntfsUnsupported     ; auxiliary record
  2352.         mov     edi, [ebp+NTFS.ntfs_attr_offs]
  2353.         mov     ebx, [ebp+NTFS.sectors_per_cluster]
  2354.         shl     ebx, 9+3
  2355.         add     dword [edi+lastVCN], 8
  2356.         add     [edi+attributeAllocatedSize], ebx
  2357.         adc     byte [edi+attributeAllocatedSize+4], 0
  2358.         add     [edi+attributeRealSize], ebx
  2359.         adc     byte [edi+attributeRealSize+4], 0
  2360.         add     [edi+initialDataSize], ebx
  2361.         adc     byte [edi+initialDataSize+4], 0
  2362.         movzx   eax, byte [edi+dataRunsOffset]
  2363.         add     edi, eax
  2364.         mov     al, [edi]
  2365.         inc     edi
  2366.         shl     eax, 4
  2367.         shr     al, 4
  2368.         mov     cl, 4
  2369.         sub     cl, al
  2370.         shl     cl, 3
  2371.         add     ah, al
  2372.         shr     eax, 8
  2373.         cmp     byte [edi+eax], 0
  2374.         jnz     ntfsUnsupported     ; $MFT fragmented
  2375.         mov     al, 8
  2376.         mov     edx, [edi]
  2377.         rol     eax, cl
  2378.         rol     edx, cl
  2379.         add     eax, edx
  2380.         jc      ntfsUnsupported
  2381.         ror     eax, cl
  2382.         shr     edx, cl
  2383.         mov     [edi], eax
  2384.         add     edx, [ebp+NTFS.mft_cluster]
  2385.         mov     esi, edx
  2386.         mov     ecx, edx
  2387.         and     ecx, 7
  2388.         shr     edx, 3
  2389.         add     edx, [ebp+NTFS.BitmapBuffer]
  2390.         mov     ax, [edx]
  2391.         shr     ax, cl
  2392.         test    al, al
  2393.         jnz     ntfsUnsupported
  2394.         dec     al
  2395.         xchg    [edx], al
  2396.         mov     [edx+1], al
  2397.         stdcall kernel_alloc, ebx
  2398.         test    eax, eax
  2399.         jz      ntfsNoMemory
  2400.         mov     ecx, ebx
  2401.         shr     ecx, 2
  2402.         mov     edi, eax
  2403.         push    ebx
  2404.         mov     ebx, eax
  2405.         xor     eax, eax
  2406.         rep stosd
  2407.         mov     eax, esi
  2408.         mul     [ebp+NTFS.sectors_per_cluster]
  2409.         pop     ecx
  2410.         shr     ecx, 9
  2411.         call    fs_write64_sys  ; clear new records
  2412.         stdcall kernel_free, ebx
  2413.         mov     eax, esi
  2414.         shr     eax, 3+9
  2415.         mov     ebx, eax
  2416.         shl     ebx, 9
  2417.         add     ebx, [ebp+NTFS.BitmapBuffer]
  2418.         add     eax, [ebp+NTFS.BitmapLocation]
  2419.         mov     ecx, 1
  2420.         xor     edx, edx
  2421.         call    fs_write64_app  ; partition bitmap
  2422.         test    eax, eax
  2423.         jnz     ntfsDevice
  2424.         mov     eax, [ebp+NTFS.frs_buffer]
  2425.         mov     [ebp+NTFS.ntfs_cur_buf], eax
  2426.         call    writeRecord     ; $MFT
  2427.         test    eax, eax
  2428.         jnz     ntfsDevice
  2429.         mov     eax, [ebp+NTFS.mftmirr_cluster]
  2430.         mul     [ebp+NTFS.sectors_per_cluster]
  2431.         mov     ebx, [ebp+NTFS.frs_buffer]
  2432.         movzx   ecx, word [ebx+updateSequenceSize]
  2433.         dec     ecx
  2434.         call    fs_write64_sys  ; $MFTMirr
  2435.         test    eax, eax
  2436.         jnz     ntfsDevice
  2437.         mov     eax, [ebp+NTFS.ntfs_cur_offs]
  2438.         add     [ebp+NTFS.ntfsLastRead], eax
  2439. .mftRecord:
  2440.         mov     esi, [ebp+NTFS.indexOffset]
  2441.         mov     edi, [ebp+NTFS.frs_buffer]
  2442.         xor     eax, eax