Subversion Repositories Kolibri OS

Rev

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