Subversion Repositories Kolibri OS

Rev

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

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