Subversion Repositories Kolibri OS

Rev

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